如何在非ARC模式下手动释放此静态变量

时间:2013-11-03 10:47:16

标签: ios objective-c memory-management

有一个似乎使用ARC的小型Toast实用程序源代码(https://github.com/Joyfl/JLToast)。但我想在手动保留 - 释放(MRR)模式下使用它。

特别是,我不确定center = [[JLToastCenter alloc] init];的{​​{1}}中的+(id)defaultCenter(对于ARC模式)是否应该重写为JLToastCenter.m(对于MRR模式) ),center = [[[JLToastCenter alloc] init] autorelease];被声明为center

在这个post中,@ mipadi给出的答案是“如果变量只初始化一次,并且应该在应用程序的生命周期内保持不变,那么不,它不应该被释放(它的无论如何,当应用程序退出时,内存将基本上被释放。“我想在static id center = nil;中的静态变量center但是不确定它的情况就是这种情况。

下面列出的我自己的MRR模式版本增加了release / autorelease / dealloc的东西。我还将所有点符号更改为消息传递方式。

源代码

源代码列表:

JLToastCenter.m

JLToastCenter.h

JLToastCenter.m

JLToast.h

JLToast.m

JLToastView.h

JLToastView.m文件:

JLToastCenter.h

#import <Foundation/Foundation.h> @class JLToast; @interface JLToastCenter : NSObject { NSOperationQueue *_queue; } + (id)defaultCenter; - (void)addToast:(JLToast *)toast; @end 文件:

JLToastCenter.m

#import "JLToastCenter.h" #import "JLToast.h" @implementation JLToastCenter + (id)defaultCenter { static id center = nil; static dispatch_once_t onceToken; // It makes singleton object thread-safe dispatch_once(&onceToken, ^{ center = [[[JLToastCenter alloc] init] autorelease]; // Added autorelease by me, originally as center = [[JLToastCenter alloc] init]; [[NSNotificationCenter defaultCenter] addObserver:center selector:@selector(deviceOrientationDidChange:) name:UIDeviceOrientationDidChangeNotification object:nil]; }); return center; } // Added by me - (void)dealloc { [_queue release]; [super dealloc]; } - (id)init { self = [super init]; if( self ) { _queue = [[NSOperationQueue alloc] init]; [_queue setMaxConcurrentOperationCount:1]; } return self; } - (void)addToast:(JLToast *)toast { [_queue addOperation:toast]; } - (void)deviceOrientationDidChange:(id)sender { if( [[_queue operations] count] ) { [[[[_queue operations] objectAtIndex:0] view] layoutSubviews]; } } @end 文件:

JLToast.h

#import <UIKit/UIKit.h> #define JLToastShortDelay 2.0f #define JLToastLongDelay 3.5f @class JLToastView; @interface JLToast : NSOperation { BOOL _isExecuting; BOOL _isFinished; } @property (nonatomic, strong) JLToastView *view; @property (nonatomic, copy) NSString *text; // added by me @property (nonatomic) NSTimeInterval delay; @property (nonatomic) NSTimeInterval duration; + (id)makeText:(NSString *)text; + (id)makeText:(NSString *)text duration:(NSTimeInterval)duration; + (id)makeText:(NSString *)text delay:(NSTimeInterval)delay duration:(NSTimeInterval)duration; - (void)show; - (void)cancel; @end 文件:

JLToast.m

#import "JLToast.h" #import "JLToastView.h" #import "JLToastCenter.h" #import <dispatch/dispatch.h> @implementation JLToast @synthesize view = _view; // added by me @synthesize text = _text; // added by me + (id)makeText:(NSString *)text { return [JLToast makeText:text delay:0 duration:JLToastShortDelay]; } + (id)makeText:(NSString *)text duration:(NSTimeInterval)duration { return [JLToast makeText:text delay:0 duration:duration]; } + (id)makeText:(NSString *)text delay:(NSTimeInterval)delay duration:(NSTimeInterval)duration { JLToast *toast = [[[JLToast alloc] init] autorelease]; // added autorelease by me [toast setText:text]; [toast setDelay:delay]; [toast setDuration:duration]; return toast; } // added by me - (void)dealloc { [_view release]; [_text release]; [super dealloc]; } - (id)init { self = [super init]; if( self ) { _view = [[JLToastView alloc] init]; } return self; } - (void)show { [[JLToastCenter defaultCenter] addToast:self]; } - (void)cancel { } #pragma mark - #pragma mark Getter/Setter - (NSString *)text { return [[_view textLabel] text]; } - (void)setText:(NSString *)text { [[_view textLabel] setText:text]; // [_view layoutSubviews]; } #pragma mark - #pragma mark NSOperation Overriding - (BOOL)isConcurrent { return YES; } - (void)start { if( ![NSThread isMainThread] ) { [self performSelectorOnMainThread:@selector(start) withObject:nil waitUntilDone:NO]; return; } [super start]; } - (void)main{ [self willChangeValueForKey:@"isExecuting"]; _isExecuting = YES; [self didChangeValueForKey:@"isExecuting"]; dispatch_async(dispatch_get_main_queue(), ^{ // Non-main thread cannot modify user interface [_view layoutSubviews]; // Calls layoutSubviews before being-shown. added by the original creator devxoul at around 20131013 [_view setAlpha:0]; [[[UIApplication sharedApplication] keyWindow] addSubview:_view]; [UIView animateWithDuration:0.5 delay:_delay options:UIViewAnimationOptionBeginFromCurrentState animations:^{ [_view setAlpha:1]; } completion:^(BOOL finished) { [UIView animateWithDuration:_duration animations:^{ [_view setAlpha:1.0001]; } completion:^(BOOL finished) { [self finish]; [UIView animateWithDuration:0.5 animations:^{ [_view setAlpha:0]; }]; }]; }]; }); } - (void)finish { [self willChangeValueForKey:@"isExecuting"]; [self willChangeValueForKey:@"isFinished"]; _isExecuting = NO; _isFinished = YES; [self didChangeValueForKey:@"isExecuting"]; [self didChangeValueForKey:@"isFinished"]; } - (BOOL)isExecuting { return _isExecuting; } - (BOOL)isFinished { return _isFinished; } @end 文件:

JLToastView.h

#import <UIKit/UIKit.h> @interface JLToastView : UIView @property (nonatomic, strong) UIView *backgroundView; @property (nonatomic, strong) UILabel *textLabel; @property (nonatomic) UIEdgeInsets textInsets; @end 文件:

JLToastView.m

2 个答案:

答案 0 :(得分:3)

您链接的问题的答案完全适用于您的案例。因为 dispatch_once()

center = [[JLToastCenter alloc] init]; // correct

在应用程序的生命周期中执行一次, 第一次调用defaultCenter时。 对defaultCenter的后续调用只返回center变量的内容, 所以你希望那个对象保持活力。

使用

center = [[[JLToastCenter alloc] init] autorelease]; // wrong

一旦程序控制返回到main,对象就会被释放(并可能被释放) 事件循环和当前自动释放池结束。

因此这里没有autorelease! (但是为什么要将项目从ARC转换为MRC?)

答案 1 :(得分:3)

摆脱自动释放!

[JLToastCenter defaultCenter]应始终返回相同的对象。第一次调用它时,它会创建对象。 (这称为“延迟初始化”,因为您只在需要时创建对象)然后它将一个指向共享对象的指针存储在静态变量中以保持它。

如果要添加autorelease,则会在下次当前自动释放池耗尽时创建并释放该对象。然后静态变量将包含指向已释放对象的指针。下次您将调用[JLToastCenter defaultCenter],然后向已发布的对象发送消息,可能会发生各种事情(您的应用可能会崩溃)。