【问题标题】:Retain cycles when using addObserverForName:object:queue:usingBlock:使用 addObserverForName:object:queue:usingBlock 时保留循环:
【发布时间】:2014-12-02 13:20:52
【问题描述】:

我是使用块编程的新手。我的 Listener 类中有以下代码(不使用 arc):

- (void)someBlock:((void)^(NSDictionary *)myDictionary)myBlock
{
    __block Listener *weakSelf = self;
    weakSelf = [[NSNotificationCenter defaultCenter] 
                   addObserverForName:@"MyNotification"
                               object:nil
                                queue:nil
                           usingBlock:^(NSNotification *note) 
        { 
            //--- Here have the retain cycles
            myBlock(note.userInfo);
            [[NSNotificationCenter defaultCenter] removeObserver:weakSelf
                                                            name:@"MyNotification"];
        }];
}

在我的 DoMyStuff 课程中:

... some code
Listener *myListener = [[[Listener alloc] init] autorelease];
[myListener someBlock:((void)^(NSDictionary *)myDictionary)myBlock{
    [self.someProperty doSomething:myDictionary];
}];

谁能告诉我解决保留周期的正确方向? 这两个问题我都查过了

  1. "Correct management of addObserverForName:object:queue:usingBlock:"
  2. "Why doesn't Remove Observer from NSNotificationCenter:addObserverForName:usingBlock get called"

但他们没有在另一个块内使用块,所以那里的解决方案对我不起作用。

【问题讨论】:

  • 我的回答应该会有所帮助。
  • 您应该注意-addObserverForName:object:queue:usingBlock: 不会返回对self 的引用,而是返回一个指向充当观察者的不透明对象的指针。
  • 是什么让您认为存在保留周期?
  • @newacct ,myListener someBlock: 内部有 self 并且此块由通知中心的方法使用,并且可能存在足够长的时间以导致“泄漏”(也许观察者永远不会被注销?)。并且块正在保持自我。我认为问题在于DoMyStuff 类。
  • 大家好,感谢所有 cmets。但是你们真的在真正的项目上运行过这个吗?我已经尝试了今天我能想象到的所有可能性,但都没有奏效。我试图在内存中跟踪观察者本身,然后我发现了一件非常有趣的事情。我使用一个属性将 self 替换为观察者,然后将断点设置为观察者。我实际上发现,观察者内存位置在 [... addobserverForName ...] 之后发生了变化。非常感谢您抽出宝贵时间,但我认为问题本身可能比我们想象的要难。

标签: ios objective-c cocoa objective-c-blocks


【解决方案1】:

这里的问题是您在块内使用[self.someProperty doSomething:myDictionary]; 从而保留了自我。请注意,使用 ivar 会导致保留循环,因为它与 self->ivar 相同。

通常看起来像这样(__weak/__unsafe_unretained 用于 ARC,__block 用于 MRR)

__weak ClassName *weakSelf = self;
[SomeClass someMethodWithBlock:^{
    // use weakSelf here; if you want to make sure that self is alive throughout whole block, do something like ClassName *strongSelf = weakSelf;
}];

有一个不错的库 https://github.com/jspahrsummers/libextobjc,其中包含 @weakify/@strongify 宏(可能仅限 ARC)。

如果可能的话,您还应该使用 ARC(如果我没记错的话,它可以从 iOS 4 使用,并且从 iOS 5 开始有 __weak,这几天应该没问题)。

【讨论】:

  • 非常感谢。我已经尝试过了,但它对我的情况不起作用。我已经为 op 放了一些 cmets。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-05-20
  • 2013-01-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多