简体   繁体   English

如何在dealloc方法中引用__weak self

[英]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.

相关问题 在ARC中,dealloc方法调用包含对self的弱引用的method / block,从而导致weakSelf = nil - In ARC, dealloc method calls method/block that contains weak reference to self result in weakSelf = nil 为什么在另一个线程上发生dealloc的同时尝试创建对self的弱引用时崩溃? - Why am I crashing when trying to create a weak reference to self while dealloc is happening on another thread? 我可以在-dealloc中调用[self retain]吗?或者,我如何确保主线程上发生dealloc? - Can I call [self retain] within -dealloc? Or, how do I ensure dealloc happens on the main thread? NSTimer自我弱; 为什么没有叫dealloc? - NSTimer with weak self; why is dealloc not called? 如何在Swift中的类函数中对self进行弱引用? - How to make weak reference to self in class function in Swift? 将强引用转换为弱引用转换为自我 - Converting a strong reference to weak reference to self 在我的 ViewController 中,如何将函数作为参数传递并保持 [弱自我]? - In my ViewController, how can I pass a function as a parameter and keep [weak self]? 如何在类方法中返回self? - How can I return self in a class method? iOS-GCD对自我的弱引用 - iOS - GCD weak and strong reference to self 是否有一种现代化的方法来获得块的弱自引用? - Is there a modernized way of getting a weak self reference for blocks?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM