我读了很多关于使用__weak self
inside的文章dispatch_async
,现在我有点困惑。
如果我有 :
self.myQueue = dispatch_queue_create("com.biview.core_data", NULL);
dispatch_async(self.myQueue, ^(void){
if (!self.var1) {
self.var1 = ...;
}
dispatch_async(dispatch_get_main_queue(), ^(void) {
if ([self.var2 superview]) {
[self.var2 removeFromSuperview];
}
[self.Label setText:text];
});
});
我需要使用吗__weak self
?因为我读到某些情况下dispatch_async
不需要__weak self
。
假设self是指向的对象指针UIViewController
。
注意事项:
AUIViewController
是“ UIKit”对象。UIKit对象不得在非主线程上发送方法,即-这些方法只能在主线程上执行!
无论是同步队列还是异步队列,已经排队的块最终都将被执行-无论如何!好吧,除非程序在此之前终止。
捕获的可保留强指针将在复制该块时保留(例如,异步调度时),并在该块被破坏时(完成后)再次释放。
捕获的可保留弱指针将不会保留或释放。
在您的情况,在那里你捕捉自己在其中的调度块主队列,您不必担心不好的事情发生。
由于self将被捕获在异步分发的块中,因此self将被隐式保留,并在块完成后再次释放。
这意味着,自我的寿命将延长,直到障碍完成为止。请注意,您的第二个块是在主线程上分派的,可以确保在执行该块时self仍然有效。
上面的“延长寿命”可能是程序的理想功能。
如果您明确不想延长UIViewController
对象的寿命,而是希望该块(最终执行时)检查该UIViewController
对象是否仍然存在,则可以使用self的__weak指针。请注意,无论块UIViewController
仍处于活动状态还是在此期间已被重新分配,该块都会最终执行。
如果在块执行前已将其UIViewController
释放,则您可能希望该块不执行任何操作:
MyController* __weak weakSelf = self;
dispatch_async(queue, ^{
MyController* strongSelf = weakSelf;
if (strongSelf) {
...
}
else {
// self has been deallocated in the meantime.
}
});
另请参阅:过渡到ARC发行说明
UIKit
不得在非主线程上向对象发送方法!由于UIKit
对象只能在主线程上执行方法,因此可能会发生另一个细微的错误。
如果块捕获UIKit
异步分配的对象并在非主线程上执行,则可能违反此规定。然后,可能发生该块保留对该对象的最后一个强引用的情况UIKit
。现在,当最终执行该块时,该块将被销毁并UIKit
释放该对象。由于这是对该对象的最后一个强引用UIKit
,因此将对其进行释放。但是,这发生在已执行该块的线程上-这不是主线程!现在,坏的事情可能(并且通常会发生)发生,因为该dealloc
方法仍然是发送给UIKit
对象的方法。
您可以通过调度一个捕获指向该UIKit对象的强指针的块并将其发送给伪方法来避免此错误:
UIViewController* strongUIKitPointer = ...
dispatch_async(non_main_queue, ^{
... // do something
dispatch(dispatch_get_main_queue(), ^{
[strongUIKitPointer self]; // note: self is a method, too - doing nothing
});
});
但是,在您的方案中,最后一个强引用只能在主线程上执行的块中。因此,您可以避免这种细微的错误。;)
在您的设置中,您永远不会有保留周期。如果可保留对象A强烈引用另一个可保留对象B,而对象B强烈引用A,则发生保留周期。请注意,“块”也是可保留对象。
一个带有循环引用的人为示例:
typedef void(^my_completion_block_t)(NSArray* result);
@interface UsersViewController : UIViewController
@property (nonatomic, copy) my_completion_block_t completion;
@property (nonatomic) NSArray* users;
@end
在这里,我们有一个属性补全,其值类型为Block。也就是说,我们得到一个名称为_completion
类型为Block的ivar 。
客户端可以设置一个完成处理程序,当某个操作完成时应调用该处理程序。假设该操作从远程服务器获取用户列表。该计划是在操作完成后设置属性用户:
粗心的方法会偶然引入循环引用:
在“ UsersViewController.m”中的某个位置
self.completion = ^(NSArray* users){
self.users = users;
}
[self fetchUsers]; // start asynchronous task
在这里,self对ivar拥有很强的参考力_completion
,这是一个块。并且该块本身捕获self,这导致在分派块时复制该块时保留self。这是一个经典的参考周期。
为了避免这种循环引用,我们有几种选择:
使用__weak
合格的自我指针
UsersViewController* __weak weakSelf = self;
self.completion = ^(NSArray* users) {
UsersViewController* strongSelf = weakSelf;
if (strongSelf) {
strongSelf.users = users;
}
else {
// the view controller does not exist anymore
}
}
[usersViewController fetchUsers];
使用__block
合格的self指针,并nil
在完成时最终将其设置在块中:
UsersViewController* __block blockSelf = self;
self.completion = ^(NSArray* users) {
blockSelf.users = users;
blockSelf = nil;
}
[usersViewController fetchUsers];
另请参阅:过渡到ARC发行说明
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句