Skip to content

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

Closed
@diong

Description

@diong

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。

Activity

ibireme

ibireme commented on Dec 10, 2015

@ibireme
Owner

你可能需要再多了解一下 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 回调,应该会对这种写法很熟悉。

diong

diong commented on Dec 10, 2015

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

ibireme commented on Dec 11, 2015

@ibireme
Owner

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

Mryong

Mryong commented on Jun 8, 2016

@Mryong

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

Mryong

Mryong commented on Jun 8, 2016

@Mryong

(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

duxinxiao commented on Aug 2, 2016

@duxinxiao

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

song-react

song-react commented on Jun 6, 2017

@song-react

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

相当于

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

Norcy commented on Oct 31, 2017

@Norcy

GCD的应该不需要用 weakSelf。

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

_queue不会持有 block。

JohnDn

JohnDn commented on Apr 2, 2018

@JohnDn

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

tomscheney

tomscheney commented on Apr 2, 2018

@tomscheney
JohnDn

JohnDn commented on Apr 2, 2018

@JohnDn

@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

tomscheney commented on Apr 2, 2018

@tomscheney
hssdx

hssdx commented on Apr 2, 2018

@hssdx

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

song-react

song-react commented on Apr 3, 2018

@song-react

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

8 remaining items

Loading
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @ibireme@tomscheney@diong@holybin@Mryong

        Issue actions

          dispatch_async的block里面需要__weak self 吗? · Issue #41 · ibireme/YYKit