Mar*_*vec 52 weak-references ios objective-c-blocks retain-cycle
我读了很多关于__weak self在里面使用的帖子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];
});
});
Run Code Online (Sandbox Code Playgroud)
我需要使用吗__weak self?因为我读过在某些情况下dispatch_async 不需要__weak self.
Cou*_*per 137
假设,self是指向a的对象指针UIViewController.
需要考虑的事项:
A UIViewController是"UIKit"对象.UIKit对象不应该在非主线程上发送方法,即 - 那些方法只能在主线程上执行!
已排队的块 - 无论是同步还是异步 - 最终将被执行 - 无论如何!好吧,除非程序在此之前终止.
当复制块时(例如,异步调度时)将保留捕获的可保留强指针,并在块被销毁时(在完成后)再次释放.
捕获的可保留弱指针不会被保留而不会被释放.
在您的方案中,您在主队列中调度的块中捕获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.
}
});
Run Code Online (Sandbox Code Playgroud)
另请参阅:转换到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
});
});
Run Code Online (Sandbox Code Playgroud)
但是,在您的方案中,最后一个强引用可能只在主线程上执行的块中.因此,您可以避免这种微妙的错误.;)
在您的设置中,您永远不会有保留周期.如果可保留对象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
Run Code Online (Sandbox Code Playgroud)
在这里,我们有一个属性完成,其值类型是块.也就是说,我们得到一个名称_completion类型为Block 的ivar .
客户端可以设置完成处理程序,当某个操作完成时应该调用该处理程序.假设,该操作从远程服务器获取用户列表.计划是在操作完成后设置属性用户:
不小心的方法会不小心引入循环引用:
在"UsersViewController.m"中的某处
self.completion = ^(NSArray* users){
self.users = users;
}
[self fetchUsers]; // start asynchronous task
Run Code Online (Sandbox Code Playgroud)
在这里,自我强烈地提到了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];
Run Code Online (Sandbox Code Playgroud)使用自定义的__block限定指针,并在完成时最终将其设置在块中:nil
UsersViewController* __block blockSelf = self;
self.completion = ^(NSArray* users) {
blockSelf.users = users;
blockSelf = nil;
}
[usersViewController fetchUsers];
Run Code Online (Sandbox Code Playgroud)另请参阅:转换到ARC发行说明
War*_*shi 28
在swift中这种所谓的强弱舞蹈的一个例子:
func doSomeThingAsynchronously() {
DispatchQueue.global().async {
// Do task in default queue
DispatchQueue.main.async { [weak self] in
// Do task in main queue
guard let self = self else { return }
self.updateView()
}
}
}
Run Code Online (Sandbox Code Playgroud)
func doSomeThingAsynchronously() {
DispatchQueue.global().async {
// Do task in default queue
DispatchQueue.main.async { [weak self] in
// Do task in main queue
guard let strongSelf = self else { return }
strongSelf.updateView()
}
}
}
Run Code Online (Sandbox Code Playgroud)
func doSomeThingAsynchronously() {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) { () -> () in
// Do task in default queue
dispatch_async(dispatch_get_main_queue(), { [weak self] () -> () in
guard let strongSelf = self else { return }
// Do task in main queue
strongSelf.updateView()
})
}
}
Run Code Online (Sandbox Code Playgroud)
流行的开源项目Alamofire使用这种方法.
使用扩展对象的生命周期[薄弱的自我]和守护让 strongSelf =自其他{}回报成语.
有关更多信息,请查看swift-style-guide