简体   繁体   English

iOS 4阻止并保留计数

[英]iOS 4 blocks and retain counts

I'm just getting started with blocks and Grand Central Dispatch. 我刚刚开始使用积木和Grand Central Dispatch。 I've been told (and read in the Apple Documentation ) that any object referenced from within a block gets retained. 我被告知(并在Apple文档中阅读)任何块中引用的对象都会被保留。

For instance: 例如:

^{  
    self.layer.transform = CATransform3DScale(CATransform3DMakeTranslation(0, 0, 0), 1, 1, 1);
    self.layer.opacity = 1;
}

"self" gets retained so it leaks. “自我”得到保留,因此泄漏。 To avoid that, I need to assign self to: 为了避免这种情况,我需要将self分配给:

__block Object *blockSelf = self;

and then use blockSelf instead of self inside my block. 然后在我的块中使用blockSelf而不是self

My question is: what happens when your block has a lot more code and references several objects? 我的问题是:当你的块有更多的代码并引用几个对象时会发生什么? Do I need to assign them all to __block objects? 我是否需要将它们全部分配给__block对象? For instance: 例如:

^{  
    [self doSomething];

    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"prevName == %@", artistName];
    [request setEntity:entity];
    [request setPredicate:predicate];

    Object *newObject = [[Object alloc] init];
    [someArray addObject];
    [newObject release];
}

No. The problem occurs when your block retains an object which retains it. 不会。当您的块保留一个保留它的对象时,会出现问题。 Your block will retain any object that it references, except for those annotated with __block . 您的块将保留它引用的任何对象,但使用__block注释的对象除外。 Hence: 因此:

// The following creates a retain cycle which will leak `self`:
self.block = ^{
  [self something];
};

self retains block , and block implicitly retains self . self保留blockblock隐含self This will also happen if you reference instance variables of self . 如果您引用self实例变量,也会发生这种情况。

// The following avoids this retain cycle:
__block typeof(self) bself = self;
self.block = ^{
  [bself something];
};

Variables annotated with __block are mutable (for pointers, that is, the address they point to can be changed); __block注释的变量是可变的(对于指针,也就是说,它们指向的地址可以改变); as a result, it makes no sense to retain that object, since you need to treat that object as a local variable (as in, it can be reassigned, affecting an object outside the scope of the block). 因此,保留该对象没有任何意义,因为您需要将该对象视为局部变量(例如,它可以被重新分配,影响块范围之外的对象)。 Thus, __block don't get retained by blocks. 因此, __block不会被块保留。

But, now you can run into unforeseen problems if you try to use this block in certain ways. 但是,如果您尝试以某种方式使用此块,现在可能遇到无法预料的问题。 For instance, if you decide to delay the invocation of this block somehow, and self has been deallocated by the time you execute that block, your program will crash, since you're sending a message to a deallocated object. 例如,如果您决定以某种方式延迟调用此块,并且在执行该块时已取消分配self ,则程序将崩溃,因为您正在向已释放的对象发送消息。 What you need then is a weak reference, which is not provided out-of-the-box in the non-garbage-collected environment! 那么你需要的是一个弱引用,它不是在非垃圾收集环境中开箱即用的!

One solution is to use MAZeroingWeakRef to wrap your block; 一种解决方案是使用MAZeroingWeakRef来封装你的块; this will zero out the pointer so that you'll just end up sending messages to nil should you attempt to message self after self has been deallocated: 这将归零的指针,让你在刚刚结束了将消息发送到nil ,你应该尝试的消息selfself已释放:

MAZeroingWeakRef *ref = [MAZeroingWeakRef refWithTarget:self];
self.block = ^{
  [ref.target something];
};

I've also implemented a weak reference wrapper in Objective-C++ , which provides the benefit of a more lightweight syntax: 我还在Objective-C ++中实现了一个弱引用包装器 ,它提供了更轻量级语法的好处:

js::weak_ref<SomeClass> ref = self;
self.block = ^{
  [ref something];
};

Because js::weak_ref is a class template, you'll get handy strong-typing (that is, you'll get warnings at compile-time if you try to send the reference a message which it doesn't appear to respond to). 因为js::weak_ref是一个类模板,所以你会得到方便的强类型(也就是说,如果你尝试向引用发送一个它似乎没有响应的消息,你将在编译时收到警告) 。 But Mike's MAZeroingWeakReference is a lot more mature than mine, so I'd suggest using his unless you want to get your hands dirty. 但迈克的MAZeroingWeakReference比我的成熟得多,所以我建议使用他,除非你想弄脏你的手。

To read more about issues with __block and the use-case for weak references, read Avoiding retain cycles with blocks, a right way and Jonathan Rentzsch's response . 要阅读有关__block问题和弱引用用例的更多信息,请阅读使用块避免保留周期,正确方法Jonathan Rentzsch的响应

I'd say it depends what you're doing with your block. 我会说这取决于你对你的阻碍做了什么。 If you're not storing it anywhere and use it in the definition place (like sorting an array using a block), then it gets released along with variables referenced inside it (since it's created in stack and is marked for autorelease). 如果您没有将它存储在任何地方并在定义位置使用它(比如使用块对数组进行排序),那么它将与其中引用的变量一起释放(因为它是在堆栈中创建的并且标记为自动释放)。 If you're storing it somewhere (an array, dictionary or probably pass the block to some other function) copy the block and balance it out with autorelease before passing it along. 如果你将它存储在某个地方(数组,字典或者可能将块传递给其他函数),请copy块并使用autorelease平衡它,然后再传递它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM