Cocoa块作为强指针与拷贝
Cocoa Blocks作为强指针和作为拷贝之间的区别
在Objective-C中,Block是一种特殊的对象,它可以用来存储一段代码并在需要时执行。在使用Block时,我们可以将其作为强指针或拷贝来使用。下面我们来看一下为什么会出现这个问题以及如何解决。
问题的出现原因:
在使用Block时,我们通常会将其存储在一个容器中,比如NSDictionary。然而,由于Block是在栈上分配的,而不是在堆上分配的,当我们将Block存储在栈上时,当作用域结束时,栈帧会被销毁,而Block也会随之销毁。这样就会出现一个悬空指针的问题。
解决方法:
为了解决上述问题,我们可以使用copy关键字将Block从栈上拷贝到堆上。这样就可以确保Block在作用域结束后仍然有效。
具体来说,我们可以使用strong属性来存储Block,并在赋值时使用copy方法:
@property (nonatomic, strong) void (^block)(); self.block = [^{} copy];
这样做可以确保Block在作用域结束后仍然有效,并且不会出现悬空指针的问题。
需要注意的是,上述问题在ARC下已经得到了解决,而在非ARC下仍然存在。在非ARC下,使用copy关键字拷贝Block可以解决该问题。
在使用Cocoa Blocks时,如果将其作为强指针存储在容器中,需要注意作用域结束时的悬空指针问题。为了解决这个问题,可以使用copy关键字将Block从栈上拷贝到堆上。在ARC下,这个问题已经得到了解决,不再需要手动拷贝Block。在非ARC下,使用copy关键字可以解决该问题。
这就是关于Cocoa Blocks作为强指针和拷贝之间区别的原因以及解决方法的总结。希望对大家有所帮助!
(Cocoa blocks as strong pointers vs copy)这个问题的出现的原因是因为在MRC和ARC中,对于属性的所有权修饰符的选择会有所不同。在MRC中,属性的所有权修饰符包括assign、retain和copy,而在ARC中引入了strong修饰符。当在MRC中使用strong时,它与retain是同义词。因此,问题就在于retain和copy之间的区别,其中有很大的区别,因为copy的setter会保存给定值的副本。
对于block来说,需要进行拷贝才能在创建它的作用域之外使用(使用block字面量)。由于您的属性将把该值存储为持久存在于函数调用之间的实例变量,并且有可能有人会从创建它的作用域中分配一个空闲的block,所以约定是您必须将其进行拷贝。因此,copy是正确的所有权修饰符。
在ARC中,strong使底层的实例变量__strong,并且copy也使其__strong,并在setter中添加了复制语义。但是,ARC还保证,无论何时将值保存到block指针类型的__strong变量中,都会执行拷贝。您的属性的类型为MyBlock,我假设它是一个block指针类型的typedef。因此,如果所有权修饰符为strong,则在setter中仍然会执行拷贝。所以,在ARC中,对于这个属性使用strong和copy没有区别。
然而,如果这个声明可能同时在MRC和ARC中使用(例如库中的头文件),最好使用copy,这样它就可以在两种情况下正常工作。
Cocoa blocks作为强指针与复制之间的问题是出现在block对象的存储上的。block对象可以存储在栈上,这是一种编译器的优化,可以快速地分配和销毁block对象。然而,如果block对象需要超过创建它的函数的生命周期,那么它必须被移到堆上。在block实现最初发布的时候,编译器无法自动处理将block移到堆上的操作,所以程序员必须手动使用函数`block_copy()`来进行复制。
尽管现在不再需要手动复制block对象,但是苹果仍然将使用`copy`作为block属性的属性标识符视为最佳实践。然而,这是不必要的,因为存储block对象在栈上本身就是一种优化,代码不应该感知这种优化。
使用ARC和当前的Clang编译器,可以将block对象视为其他对象,不需要复制它们。只有在MRC中才需要手动管理block对象的复制。
关于这个问题的解决方法是,使用ARC和当前的Clang编译器,可以将block对象视为其他对象,不需要复制它们。这是因为存储block对象在栈上本身就是一种优化,代码不应该感知这种优化。