[英]How can I reference __weak self in dealloc method
I have a method called in various places called "cancelAllPendingDownloads" This is a general method that cancels various jobs and updates internal counters. 我有一个名为“cancelAllPendingDownloads”的各种地方调用的方法这是取消各种作业和更新内部计数器的一般方法。
Problem happens when it is called within the dealloc method 在dealloc方法中调用时会出现问题
-(void)dealloc
{
[self cancelAllPendingDownloads]; // want to cancel some jobs
}
-(void)cancelAllPendingDownloads // updates some internals
{
__weak __typeof__(self) weakSelf = self; // This line gets a EXC_BAD_INSTRUCTION error in runtime
for(Download *dl in self.downloads)
{
dl.completionHandler = ^{ // want to replace the previous block
weakSelf.dlcounter--;
}
[dl cancel];
}
}
Not sure why it fails in the dealloc method as "self" still exists 不确定为什么它在dealloc方法中失败,因为“self”仍然存在
When I change the code to 当我将代码更改为
__typeof__(self) strongSelf = self; //everything works fine
__weak __typeof__(self) weakSelf = strongSelf; (or "self") BAD_INSTRUCTION error
The error happens on the second line 错误发生在第二行
Just to make the "you are not supposed" or "You can't" part of the other good answers more precise: 只是为了使“你不应该”或“你不能”更好地回答其他好的答案:
The runtime function for storing a weak reference is objc_storeWeak()
, and the Clang/ARC documentation states: 用于存储弱引用的运行时函数是objc_storeWeak()
,而Clang / ARC文档说明:
id objc_storeWeak(id *object, id value);
... If value is a null pointer or the object to which it points has begun deallocation, object is assigned null and unregistered as a __weak object. ...如果value是空指针或它指向的对象已开始解除分配,则将对象指定为null并取消注册为__weak对象。 Otherwise, object is registered as a __weak object or has its registration updated to point to value. 否则,将对象注册为__weak对象或将其注册更新为指向值。
Since the self
object has already begun deallocation, weakSelf
should be set to NULL
(and therefore is not of any use). 由于self
对象已经开始释放, weakSelf
应该设置为NULL
(因此没有任何用处)。
However, there seems to be a bug (as discussed here http://www.cocoabuilder.com/archive/cocoa/312530-cannot-form-weak-reference-to.html ) that objc_storeWeak()
crashes in this case, instead of returning NULL
. 但是,似乎有一个错误(如http://www.cocoabuilder.com/archive/cocoa/312530-cannot-form-weak-reference-to.html所讨论的),在这种情况下objc_storeWeak()
崩溃,而不是返回NULL
。
If an object is in dealloc
state, you are not supposed to create any new references to it. 如果对象处于dealloc
状态,则不应该为其创建任何新引用。 Consider the object as already destroyed. 考虑已经销毁的对象。 Don't use it in a callback/delegate any more. 不要再在回调/委托中使用它。
Note that dlcounter
won't ever be read. 请注意,永远不会读取dlcounter
。 Just cancel the connections without reading the results. 只需取消连接而不读取结果。
TL;DR TL; DR
- How can I reference __weak
self in dealloc
method? - 如何在dealloc
方法中引用__weak
self?
- Don't reference it. - 不要参考它。
You can't initialize a week (or a strong) reference to self in the dealloc method and use it elsewhere - it's too late, the object will be inevitably destroyed. 你不能在dealloc方法中初始化一周(或强)对self的引用并在别处使用它 - 它太晚了,对象将不可避免地被破坏。
However, you might try this: 但是,您可以尝试这样做:
-(void)dealloc
{
NSArray* localDownloads = self.downloads;
for(Download* dl in localDownloads) {
[dl cancel];
}
}
It should be clear that there are better places to invoke cancellation, for example, in a view controller, you may override viewWillDisappear:
. 应该很清楚,有更好的地方可以调用取消,例如,在视图控制器中,您可以覆盖viewWillDisappear:
.
I am assuming you are using ARC for your project. 我假设您正在为您的项目使用ARC。
Straight from Apple: Apple Talked about Weak and Strong 直接来自苹果公司: Apple谈论弱势和强势
__strong is the default. An object remains “alive” as long as
there is a strong pointer to it.
__weak specifies a reference that does not keep the referenced object alive.
A weak reference is set to nil when there are no strong references to the object.
This is an Article Explaining Dealloc: Dealloc Method Explained and More 这是一篇文章解释Dealloc: Dealloc方法的解释和更多
This method will be called after the final release of the object
but before it is deallocated or any of its instance variables are destroyed.
The superclass’s implementation of dealloc will be called automatically when
the method returns.
After this being pointed out... I highly recommend you revise your code design because there is no reason for you to call a weak typeof (self) to solve your problem of cancelling those downloads at dealloc or any type of deallocing that involves _ weak _typeof__self for that matter. 这被指出后......我强烈建议你修改你的代码的设计,因为没有理由让你调用一个弱的typeof(个体经营)解决在取消或dealloc的这些下载涉及任何类型的deallocing的您的问题_ 弱 _typeof__self就此而言。
What I can recommend though is that that class that you are trying to cancel those downloads frin, make it keep track of those downloads with a Download UniqueID and just stop them or delete them at dealloc. 我可以推荐的是,那个你试图取消这些下载的课程,让它通过下载UniqueID跟踪这些下载,然后停止它们或者在dealloc中删除它们。 Its simpler and easier to manage rather than that wierd call to __weak self and all that code you are doing. 它更简单,更容易管理,而不是对__weak self以及你正在做的所有代码的那种奇怪的调用。
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
. 简而言之:你可以在dealloc
使用__strong
引用self而不是__weak
用于你的目的,但是当且仅当强引用不会比dealloc
结束时更长。 Otherwise, I would advise using __unsafe_unretained
, which is still unsafe if it outlives the dealloc
but is clearer to read. 否则,我会建议使用__unsafe_unretained
,如果它比dealloc
但仍然更安全,它仍然是不安全的。
Longer: I had a similar situation where the object (view controller) during dealloc should unsubscribe from notifications. 更长:我有类似的情况,dealloc期间的对象(视图控制器)应该取消订阅通知。 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): 我最终遇到了同样的情况:在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
If, on the other hand, the reference was strong, all seems to work well (during dealloc). 另一方面,如果引用很强,那么一切似乎都很好(在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
. 这意味着每当dummy
对象需要dealloc时,它会尝试减少其strongProperty
的引用计数。 And at that point the ViewController
has been deallocated and released already. 此时, ViewController
已经被解除分配并已经发布。 However, IMHO the "safest" way to proceed is to use unsafe_unretained
in this case. 但是,恕我直言,“最安全”的方法是在这种情况下使用unsafe_unretained
。 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. 从技术上讲,它与使用assign相同:无论内存管理如何,都将分配指针,并且当超出范围时不需要释放引用。 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. 但是使用unsafe_unretained
告诉读者你的代码(或者你的未来)你知道风险,并且必须有理由去做你做的事情。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.