Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dispatch_async的block里面需要__weak self 吗? #41

Closed
diong opened this issue Dec 10, 2015 · 22 comments
Closed

dispatch_async的block里面需要__weak self 吗? #41

diong opened this issue Dec 10, 2015 · 22 comments

Comments

@diong
Copy link

diong commented Dec 10, 2015

YYKit的代码: (YYDiskCache.m)

  • (void)_trimInBackground {
    __weak typeof(self) _self = self;
    dispatch_async(_queue, ^{
    __strong typeof(_self) self = _self;
    if (!self) return;
    dispatch_semaphore_wait(self->_lock, DISPATCH_TIME_FOREVER);
    [self _trimToCost:self.costLimit];
    [self _trimToCount:self.countLimit];
    [self _trimToAge:self.ageLimit];
    [self _trimToFreeDiskSpace:self.freeDiskSpaceLimit];
    dispatch_semaphore_signal(self->_lock);
    });
    }

看下dispatch_async官方文档说明:

  • @param block
  • The block to submit to the target dispatch queue. This function performs
  • Block_copy() and Block_release() on behalf of callers.
  • The result of passing NULL in this parameter is undefined.

block参数系统会自动调用copy,保证self不被释放,在block执行结束后会release。所以没必要传__weak self。 如果传__weak self,就无法保证block在执行时,self是否被释放,反而会出现错误。所以不能传__weak self。

@ibireme
Copy link
Owner

ibireme commented Dec 10, 2015

你可能需要再多了解一下 block、weak、strong 相关的内存管理。

- (void)_trimInBackground {
    __weak typeof(self) _self = self;
    dispatch_async(_queue, ^{
        __strong typeof(_self) self = _self; // ①
        if (!self) return; // ②
        dispatch_semaphore_wait(self->_lock, DISPATCH_TIME_FOREVER);
        [self _trimToCost:self.costLimit];
        [self _trimToCount:self.countLimit];
        [self _trimToAge:self.ageLimit];
        [self _trimToFreeDiskSpace:self.freeDiskSpaceLimit];
        dispatch_semaphore_signal(self->_lock);
    });
}

在①处,block 会捕获到 _self,这个值是 weak 的,随后在 block 执行①时,这个 __weak _self 会被赋值为 __strong self。在②处,如果 weak self 已经被释放,那么这里就会直接返回。这么做能避免循环引用,并且能确保在使用 self 时其不会被释放。

如果你用过 ReactiveCocoa,或者写过一些常见的一些网络库的 block 回调,应该会对这种写法很熟悉。

@ibireme ibireme closed this as completed Dec 10, 2015
@diong
Copy link
Author

diong commented Dec 10, 2015

  1. block通过__weak self来传参,是可以避免循环引用,没错。
  2. 在block里面,有再转成__strong self,并且判断空情况,这个也没错(之前没注意到空处理)。
    我想说的是,dispatch_async这个方法里面,有没有必要传__weak self进来?
    一些网络库的block回调有这样写法,是因为block和调用的对象双反互相强引用,会出现循环引用,才用__weak self来避免。 dispatch_async与self之间又不会引起循环引用,所以觉得没必要传__weak self.

@ibireme
Copy link
Owner

ibireme commented Dec 11, 2015

self->_queue->block->self 这不是循环引用吗

@Mryong
Copy link

Mryong commented Jun 8, 2016

如果self->_queue->block->self 是循环引用,那么self->_queue->block->strongSelf 难道就不是循环引用了么?所以这句话__strong typeof(_self) self = _self; 有什么意义呢?

@Mryong
Copy link

Mryong commented Jun 8, 2016

(void)_trimRecursively {
__weak typeof(self) _self = self;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(_autoTrimInterval * NSEC_PER_SEC)), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
__strong typeof(_self) self = _self;
if (!self) return;
[self _trimInBackground]; [
self _trimRecursively]; });
}
首先我觉得
__weak typeof(self) _self = self;
__strong typeof(_self) self = _self;
这两句没必要写,先weak再strong 和原来的self有什么区别呢? 原来的self指针就是strong类型啊。

其次我觉得 if (!self) return 这个条件永远不会成立,因为这时候已经定了strongSelf强指针指向self对象,所以self的对象的引用计数必然已经+1了,直到block释放的时候才会-1,而此时显然blokc还没释放,所以self指向的对象的应用计数必然大于等于1,所以不会释放,所以!self条件必然不会成立。

@duxinxiao
Copy link

官方文档上说会Block_copy() 和Block_release() ,所以会帮你打破引用循环,不用weak/strong应该也没问题

@DingSoung
Copy link

DingSoung commented Jun 6, 2017

@Mryong ②那里有处理,所以没问题的

相当于

__weak typeof(self) weakSelf = self;
    xxxxx ^ {
    weakSelf.xxxxx
}

@Norcy
Copy link

Norcy commented Oct 31, 2017

GCD的应该不需要用 weakSelf。

self->_queue->block->self 这不是循环引用吗

_queue不会持有 block。

@JohnDn
Copy link

JohnDn commented Apr 2, 2018

我认为使用weakSelf时,当这个viewController释放了,weakSelf会变成nil。
但是如果使用self,self会在Block释放时,才释放,应该不会造成循环引用。

@tomscheney
Copy link

tomscheney commented Apr 2, 2018 via email

@JohnDn
Copy link

JohnDn commented Apr 2, 2018

@tomschenjian 刚才可能没说清楚,我那段话里Block指的是dispatch_async block,这里只针对GCD中使用self进行讨论。当然一般情况里,self持有block,block中也强引用self,这样确实是强引用循环,block的释放需要依赖self的释放,同时self的释放也依赖block的释放。

但是在dispatch_async block回调中强引用了self,不会造成循环引用吧?dispatch_async block结束后会自动release,同时dispatch_async block对self的强引用也结束了,self也会释放。

还请大神多多指教。。。

@tomscheney
Copy link

tomscheney commented Apr 2, 2018 via email

@hssdx
Copy link

hssdx commented Apr 2, 2018

@Mryong 你没理解什么是循环引用,那里的 strongSelf 是在 {...} 代码块内部的临时变量!临时变量在代码块退出时会自动调用 release

@DingSoung
Copy link

不用争了, self->queue -> async block -> weak self
如果是Queue.main, queue.global 就不需要

@web3Aiden
Copy link

web3Aiden commented Apr 17, 2018

queue不会持有block,这样写也不会有循环引用
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 4 * NSEC_PER_SEC), vc.queue, ^{ NSLog(@"dispatch_after:%@", vc); });

dispatch_async(vc.queue, ^{ NSLog(@"dispatch_async:%@", vc); });

@hssdx
Copy link

hssdx commented Apr 17, 2018

不是queue没有持有block,而且queue在执行完block后释放了block(赋值nil)🙂,它确实有循环引用,但是执行完后queue主动打破了循环引用。

@chenyuecathy
Copy link

self->_queue->block->self 这不是循环引用吗
dispatch确实产生了循环引用,但queue在事后主动释放了block,破除了循环引用。

@Yincongxiao
Copy link

这里是否有必要使用__weak我认为是看自己的需求而定的,block持有外部变量的特性可以帮我们延长对象生命周期
yy这种写法当执行block时如果self释放了,那么接下来block内部的逻辑就不会再执行.
如果不用__weak修饰的话由于queue->block->self,那么此时self是不会释放的,block的逻辑会得到执行,执行完以后queue释放block,block释放self,所以也不会有循环引用
所以还是看自己想得到哪种效果了.

@ripperhe
Copy link

这里是否有必要使用__weak我认为是看自己的需求而定的,block持有外部变量的特性可以帮我们延长对象生命周期
yy这种写法当执行block时如果self释放了,那么接下来block内部的逻辑就不会再执行.
如果不用__weak修饰的话由于queue->block->self,那么此时self是不会释放的,block的逻辑会得到执行,执行完以后queue释放block,block释放self,所以也不会有循环引用
所以还是看自己想得到哪种效果了.

有道理

@Wizhiai
Copy link

Wizhiai commented Jun 1, 2020

这里是否有必要使用__weak我认为是看自己的需求而定的,block持有外部变量的特性可以帮我们延长对象生命周期
yy这种写法当执行block时如果self释放了,那么接下来block内部的逻辑就不会再执行.
如果不用__weak修饰的话由于queue->block->self,那么此时self是不会释放的,block的逻辑会得到执行,执行完以后queue释放block,block释放self,所以也不会有循环引用
所以还是看自己想得到哪种效果了.

有道理,但感觉作者没想这么多,可能单纯的只是写了下防循环引用而已,其实这里可以不用。看过很多人遇到block就weak的。

@holybin
Copy link

holybin commented Oct 18, 2021

GCD的应该不需要用 weakSelf。

self->_queue->block->self 这不是循环引用吗

_queue不会持有 block。

不一定的哈,需要分情况讨论
1、如果是dispatch_async/dispatch_after,是存在 self->_queue->block->self这个引用链的,但是queue会主动调用release block,所以不会造成循环引用
2、如果是dispatch_sync,queue不会持有block,所以不存在循环引用

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests