简而言之:您可以使用__strong
对 self in 的引用dealloc
而不是__weak
出于您的目的,但当且仅当该强引用不会超过dealloc
. 否则,我建议使用__unsafe_unretained
,如果它dealloc
比
Longer:我遇到过类似的情况,dealloc 期间的对象(视图控制器)应该取消订阅通知。这是一个自定义通知系统,取消订阅需要创建一个引用被取消订阅的实体的对象。我最终遇到了同样的情况:在 dealloc 中无法创建该对象,因为它需要一个导致崩溃的弱引用(这里有一些愚蠢的演示代码,而不是你在生产中会有的东西):
@interface Dummy : NSObject
@property(nonatomic, weak) id weakProperty;
@property(nonatomic, strong) id strongProperty;
@property(nonatomic, unsafe_unretained) id unsafeProperty;
- (instancetype)initWithWeakStuff:(id)stuff;
- (instancetype)initWithStrongStuff:(id)stuff;
- (instancetype)initWithUnsafeStuff:(id)stuff;
@end
@implementation Dummy
- (instancetype)initWithWeakStuff:(id)stuff {
self = [super init];
if (self) {
_weakProperty = stuff;
}
return self;
}
- (instancetype)initWithStrongStuff:(id)stuff {
self = [super init];
if (self) {
_strongProperty = stuff;
}
return self;
}
- (instancetype)initWithUnsafeStuff:(id)stuff {
self = [super init];
if (self) {
_unsafeProperty = stuff;
}
return self;
}
- (void)dealloc {
}
@end
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)dealloc {
Dummy *dummy = [[Dummy alloc] initWithStrongStuff:self];
[[NSNotificationCenter defaultCenter]
postNotificationName:@"some notification"
object:dummy]; // do something with it
}
@end
另一方面,如果引用很强大,那么一切似乎都运行良好(在 dealloc 期间)。如果新创建的对象比 self 寿命更长,就会出现问题:
- (void)dealloc {
Dummy *dummy = [[Dummy alloc] initWithStrongStuff:self];
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter]
postNotificationName:@"some notification"
object:dummy]; // do something with it
}); //Crash at the end of the block during dummy's dealloc
}
这意味着每当dummy
对象需要解除分配时,它都会尝试减少其strongProperty
. 到那时,它ViewController
已经被释放并释放了。但是,恕我直言,“最安全”的继续方式是unsafe_unretained
在这种情况下使用。从技术上讲,它与使用分配相同:无论内存管理如何,都会分配指针,并且当超出范围时不需要释放该引用。但是 usingunsafe_unretained
告诉你的代码的读者(或未来的你)你意识到了风险,并且一定有理由去做你所做的事情。