Почему помещение себя в блоки GCD вызовет утечку памяти?

Я прочитал замечательную статью, написанную benzado о том, что использование блока приведет к утечке памяти, если у нас есть переменная класса, сохраняющая сам блок, а блок сохраняет «я», что вызывает цикл сохранения.

Как мне избежать захвата себя в блоках при реализации API?

Но я не понимаю, почему использование GCD вызовет ту же проблему? такие функции, как dispatch_async(), выглядят для меня как локальная переменная, которая не должна захватываться самим классом?

А в официальном документе говорилось, что мы должны поставить автовыпуск в блоки, чтобы наши объекты освобождались вовремя.

В большей части моего проекта IOS я использую GCD следующим образом:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,(unsigned long)NULL), ^(void) {

    NSDictionary *resultDic = [MyService loadData];

    dispatch_async(dispatch_get_main_queue(), ^{
        [self.delegate useData:resultDic];
    });
});

Теперь мне нужно изменить их все на

__block MyClass *blockSelf = self;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,(unsigned long)NULL), ^(void) {

    @autoreleasepool{
        NSDictionary *resultDic = [MyService loadData];

        dispatch_async(dispatch_get_main_queue(), ^{

            @autoreleasepool{
                [blockSelf.delegate useData:resultDic];
            }
        });

    }
});

??

Это выглядит грязным. Кто-нибудь знает, как это сделать правильно?

Кстати, если я вызвал некоторые функции в блоке и использовал в этих функциях «self» или «self.delegate», значит ли это, что мне нужно изменить все это на что-то другое? (и я не знаю, что делать, чтобы это исправить)

К вашему сведению, мой проект IOS создан в среде IOS8.1 и не-ARC.


person 林鼎棋    schedule 06.02.2015    source источник
comment
Немного не по теме: вы должны сделать себе одолжение и переключиться на ARC.   -  person Aaron Brager    schedule 06.02.2015
comment
Я не уверен, что вы поняли пост, на который ссылаетесь. В нем не упоминается @autoreleasepool, потому что это не нарушает циклы сохранения.   -  person Tommy    schedule 06.02.2015
comment
это устаревший код, и я ничего не могу сделать, кроме как оставить его не-ARC orz. Да, проблема @autoreleasepool упоминается в официальной статье Apple Developer Document вместо ссылки, которую я разместил здесь.   -  person 林鼎棋    schedule 06.02.2015


Ответы (1)


@autoreleasepool не нужен.

В блок, который вы передаете dispatch_async, блок будет скопирован (Block_copy) в кучу, но он будет освобожден (Block_release) сразу после его вызова. Так что никакого цикла сохранения там нет.

Для всего блока, который вы используете в своем проекте, если self имеет сильную ссылку на блок или сильную цепочку ссылок на блок, вы должны использовать __block MyClass *blockSelf = self;, чтобы избежать цикла сохранения.

Примечание. __block MyClass *blockSelf = self; работает не в ARC, при переходе на ARC используйте вместо него __weak.

person KudoCC    schedule 06.02.2015