Исправлено предупреждение «Сильный захват [объекта] в этом блоке может привести к сохранению цикла» в коде с поддержкой ARC - PullRequest
139 голосов
/ 26 августа 2011

В коде с поддержкой ARC, как исправить предупреждение о потенциальном цикле сохранения при использовании блочного API?

Предупреждение:
Capturing 'request' strongly in this block is likely to lead to a retain cycle

созданный этим фрагментом кода:

ASIHTTPRequest *request = [[ASIHTTPRequest alloc] initWithURL:...

[request setCompletionBlock:^{
    NSDictionary *jsonDictionary = [[CJSONDeserializer deserializer] deserialize:request.rawResponseData error:nil];
    // ...
    }];

Предупреждение связано с использованием объекта request внутри блока.

Ответы [ 7 ]

163 голосов
/ 26 августа 2011

Отвечая себе:

Мое понимание документации говорит о том, что использование ключевого слова block и установка переменной равной nil после использования ее внутри блока должны быть в порядке, но все равно отображается предупреждение.

__block ASIHTTPRequest *request = [[ASIHTTPRequest alloc] initWithURL:...

[request setCompletionBlock:^{
    NSDictionary *jsonDictionary = [[CJSONDeserializer deserializer] deserialize:request.responseData error:nil];
    request = nil;
// ....

    }];

Обновление: заставило его работать с ключевым словом '_ слабый' вместо ' _block' и использованием временной переменной:

ASIHTTPRequest *_request = [[ASIHTTPRequest alloc] initWithURL:...
__weak ASIHTTPRequest *request = _request;

[request setCompletionBlock:^{
    NSDictionary *jsonDictionary = [[CJSONDeserializer deserializer] deserialize:request.responseData error:nil];
    // ...
    }];

Если вы хотите настроить таргетинг на iOS 4, используйте __unsafe_unretained вместо __weak. Такое же поведение, но указатель остается висящим вместо того, чтобы автоматически устанавливаться в ноль при уничтожении объекта.

49 голосов
/ 07 января 2013

Проблема возникает из-за того, что вы присваиваете блоку запрос, в котором есть сильная ссылка на запрос.Блок автоматически сохранит запрос, поэтому исходный запрос не будет освобожден из-за цикла.Имеет смысл?

Это просто странно, потому что вы помечаете объект запроса __block, чтобы он мог ссылаться на себя.Вы можете исправить это, создав слабую ссылку рядом с it.

ASIHTTPRequest *request = [[ASIHTTPRequest alloc] initWithURL:...];
__weak ASIHTTPRequest *wrequest = request;

[request setCompletionBlock:^{
    NSDictionary *jsonDictionary = [[CJSONDeserializer deserializer] deserialize:wrequest.rawResponseData error:nil];
    // ...
    }];
12 голосов
/ 11 июля 2014

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

Попробуйте решить эту проблему путем создания слабой ссылки self

__weak typeof(self) weakSelf = self;

operationManager = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operationManager.responseSerializer = [AFJSONResponseSerializer serializer];
[operationManager setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {

    [weakSelf requestFinishWithSucessResponseObject:responseObject withAFHTTPRequestOperation:operation andRequestType:eRequestType];

} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    [weakSelf requestFinishWithFailureResponseObject:error withAFHTTPRequestOperation:operation andRequestType:eRequestType];
}];
[operationManager start];
6 голосов
/ 26 ноября 2014

Иногда у компилятора xcode возникают проблемы с идентификатором циклов сохранения, поэтому, если вы уверены, что не сохранили завершение, вы можете установить флаг компилятора следующим образом:

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-retain-cycles"
#pragma clang diagnostic ignored "-Wgnu"

-(void)someMethod {
}
3 голосов
/ 16 января 2012

Когда я пробую решение, предоставленное Гийомом, в режиме отладки все нормально, но в режиме выпуска происходит сбой.

Обратите внимание, что не используйте __weak, но __unsafe_unretained, потому что моя цель - iOS 4.3.

Мой код падает, когда setCompletionBlock: вызывается для объекта «запрос»: запрос был освобожден ...

Итак, это решение работает в режимах Debug и Release:

// Avoiding retain cycle :
// - ASIHttpRequest object is a strong property (crashs if local variable)
// - use of an __unsafe_unretained pointer towards self inside block code

self.request = [ASIHttpRequest initWithURL:...
__unsafe_unretained DataModel * dataModel = self;

[self.request setCompletionBlock:^
{
    [dataModel processResponseWithData:dataModel.request.receivedData];        
}];
2 голосов
/ 24 июля 2013
ASIHTTPRequest *request = [[ASIHTTPRequest alloc] initWithURL:...
__block ASIHTTPRequest *blockRequest = request;
[request setCompletionBlock:^{
    NSDictionary *jsonDictionary = [[CJSONDeserializer deserializer] deserialize:blockRequest.responseData error:nil];
    blockRequest = nil;
// ....

}];

в чем разница между __слабым и __блочным эталоном?

0 голосов
/ 26 августа 2011

Ознакомьтесь с документацией на веб-сайте Apple для разработчиков: https://developer.apple.com/library/prerelease/ios/#documentation/General/Conceptual/ARCProgrammingGuide/Introduction.html#//apple_ref/doc/uid/TP40011029

Внизу страницы есть раздел о сохранении циклов.

...