当前位置:K88软件开发文章中心编程语言Objective-CObjective-C01 → 文章内容

对象之间的通讯

减小字体 增大字体 作者:佚名  来源:网上搜集  发布时间:2019-1-10 11:12:24

completion:completionHandler];
不是很麻烦的事情。
但是, 当 block 被 self 在一个属性 retain(就像下面的例子)呢self.completionHandler = ^{ NSLog(@"%@", self);
{
MyViewController *myController = [[MyViewController alloc] init...];
[self presentViewController:myController animated:YES completion:self.completionHandler];
这就是有名的 retain cycle, 并且我们通常应该避免它。
这种情况下我们收到 CLANG 的警告:Capturing '
self'
strongly in this block is likely to lead to a retain cycle (在 block 里面发现了 `self` 的强引用,
可能会导致循环引用)所以可以用 weak 修饰2. 在 block 外定义一个 __weak 的 引用到 self,
并且在 block 里面使用这个弱引用这样会避免循环引用,
也是我们通常在 block 已经被 self 的 property 属性里面 retain 的时候会做的。
__weak typeof(self) weakSelf = self;
self.completionHandler = ^{ NSLog(@"%@", weakSelf);
{
;
MyViewController *myController = [[MyViewController alloc] init...];
[self presentViewController:myController animated:YES completion:self.completionHandler];
这个情况下 block 没有 retain 对象并且对象在属性里面 retain 了 block 。
所以这样我们能保证了安全的访问 self。
不过糟糕的是,
它可能被设置成 nil 的。
问题是:如果和让 self 在 block 里面安全地被销毁。
举个例子,
block 被一个对象复制到了另外一个(比如 myControler)作为属性赋值的结果。
之前的对象在可能在被复制的 block 有机会执行被销毁。
下面的更有意思。
3. 在 block 外定义一个 __weak 的 引用到 self,
并在在 block 内部通过这个弱引用定义一个 __strong 的引用你可能会想,
首先,
这是避免 retain cycle 警告的一个技巧。
然而不是,
这个到 self 的强引用在 block 的执行时间 被创建。
当 block 在定义的时候,
block 如果使用 self 的时候,
就会 retain 了 self 对象。
Apple 文档 中表示 "
为了 non-trivial cycles ,
你应该这样"
:MyViewController *myController = [[MyViewController alloc] init...];
// ...MyViewController * __weak weakMyController = myController;
myController.completionHandler = ^(NSInteger result) { MyViewController *strongMyController = weakMyController;
if (strongMyController) { // ... [strongMyController dismissViewControllerAnimated:YES completion:nil];
// ... {
else { // Probably nothing... {
{
;
首先,
我觉得这个例子看起来是错误的。
如果 block 本身被 completionHandler 属性里面 retain 了,
那么 self 如何被 delloc 和在 block 之外赋值为 nil 呢? completionHandler 属性可以被声明为 assign 或者 unsafe_unretained 的,
来允许对象在 block 被传递之后被销毁。
我不能理解这样做的理由,
如果其他对象需要这个对象(self),
block 被传递的时候应该 retain 对象,
所以 block 应该不被作为属性存储。
这种情况下不应该用 __weak/__strong 总之,
其他情况下,
希望 weakSelf 变成 nil 的话,
就像第二种情况解释那么写(在 block 之外定义一个弱应用并且在 block 里面使用)。
还有,
Apple的 "
trivial block"
是什么呢。
我们的理解是 trivial block 是一个不被传送的 block ,
它在一个良好定义和控制的作用域里面,
weak 修饰只是为了避免循环引用。
虽然有 Kazuki Sakamoto 和 Tomohiko Furumoto) 讨论的 一 些 的 在线 参考, Matt Galloway 的 (Effective Objective-C 2.0 和 Pro Multithreading and Memory Management for iOS and OS X ,
大多数开发者始终没有弄清楚概念。
在 block 内用强引用的优点是,
抢占执行的时候的鲁棒性。
看上面的三个例子,
在 block 执行的时候1. 直接在 block 里面使用关键词 self如果 block 被属性 retain,
self 和 block 之间会有一个循环引用并且它们不会再被释放。
如果 block 被传送并且被其他的对象 copy 了,
self 在每一个 copy 里面被 retain2. 在 block 外定义一个 __weak 的 引用到 self,
并且在 block 里面使用这个弱引用没有循环引用的时候,
block 是否被 retain 或者是一个属性都没关系。
如果 block 被传递或者 copy 了,
在执行的时候,
weakSelf 可能会变成 nil。
block 的执行可以抢占,
并且后来的对 weakSelf 的不同调用可以导致不同的值(比如,
在 一个特定的执行 weakSelf 可能赋值为 nil )__weak typeof(self) weakSelf = self;
dispatch_block_t block = ^{ [weakSelf doSomething];
// weakSelf != nil // preemption, weakSelf turned nil [weakSelf doSomethingElse];
// weakSelf == nil{
;
3. 在 block 外定义一个 __weak 的 引用到 self,
并在在 block 内部通过这个弱引用定义一个 __strong 的引用。
不论管 block 是否被 retain 或者是一个属性,
这样也不会有循环引用。
如果 block 被传递到其他对象并且被复制了,
执行的时候,
weakSelf 可能被nil,
因为强引用被复制并且不会变成nil的时候,
我们确保对象 在 block 调用的完整周期里面被 retain了,
如果抢占发生了,
随后的对 strongSelf 的执行会继续并且会产生一样的值。
如果 strongSelf 的执行到 nil,
那么在 block 不能正确执行前已经返回了。
__weak typeof(self) weakSelf = self;
myObj.myBlock = ^{ __strong typeof(self) strongSelf = weakSelf;
if (strongSelf) { [strongSelf doSomething];
// strongSelf != nil // preemption, strongSelf still not nil(抢占的时候,
strongSelf 还是非 nil 的) [strongSelf doSomethingElse];
// strongSelf != nil {
else { // Probably nothing... return;
{
{
;
在一个 ARC 的环境中,
如果尝试用 ->
符号来表示,
编译器会警告一个错误:Dereferencing a __weak pointer is not allowed due to possible null value caused by race condition, assign it to a strong variable first. (对一个 __weak 指针的解引用不允许的,
因为可能

上一页  [1] [2] [3] [4]  下一页


对象之间的通讯