In short: you can use a __strong
reference to self in dealloc
instead of __weak
for your purposes but if and only if that strong reference won't outlive the end of dealloc
. Otherwise, I would advise using __unsafe_unretained
, which is still unsafe if it outlives the dealloc
but is clearer to read.
Longer: I had a similar situation where the object (view controller) during dealloc should unsubscribe from notifications. That's a custom notifications system and unsubscribing requires creating an object with a reference to the entity that's being unsubscribed.
I ended up with the same situation: in dealloc there's no way to create that object because it required a weak reference which caused a crash (here's some stupid demo code, not something you would have in production):
@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
If, on the other hand, the reference was strong, all seems to work well (during dealloc). The problem would arise if that newly created object would outlive 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
}
This would mean that whenever the dummy
object would need to dealloc it would try to decrease the ref count of its strongProperty
. And at that point the ViewController
has been deallocated and released already.
However, IMHO the "safest" way to proceed is to use unsafe_unretained
in this case. Technically it's the same as using assign: pointer will be assigned regardless of memory management and that reference will not need to be released when it goes out of scope. But using unsafe_unretained
tells the readers of your code (or future you) that you were aware of the risk and there must have been a reason to do what you did.
self
) is being deallocated, why do you need to decrement thedlcounter
at all? It will soon not even exist - do you need to use it later in thedealloc
method? – WrothcancelAllPendingDownloads
prior to deallocing. – Lent__weak
reference toself
in this example?dl
is an instance in the scope of the method, not retained byself
, so it should be fine to useself
within the block, right? Is it just to prevent runningself.dlcounter--
ifself
has been already deallocated? In that case, doesn't the block retain self, so it keeps it alive (in case of usingself
within the block). Thanks – Pierrette