Исправить предупреждение "захват [объекта] сильно в этом блоке, вероятно, приведет к циклу сохранения" в коде с поддержкой ARC
в коде с поддержкой 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 ответов:
отвечая самому себе:
мое понимание документации говорит, что с помощью ключевого слова
block
и установка переменной в ноль после использования ее внутри блока должна быть в порядке, но она все еще показывает предупреждение.__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
. Тот же поведение, но указатель остается висящим, а не автоматически устанавливается в ноль, когда объект уничтожается.
проблема возникает, потому что вы назначаете блок для запроса, который имеет сильную ссылку на запрос в нем. Блок автоматически сохранит запрос, поэтому исходный запрос не будет освобожден из-за цикла. Есть смысл?
это просто странно, потому что вы помечаете объект запроса с __block, чтобы он мог ссылаться на себя. Вы можете исправить это, создав слабую ссылку вместе с его.
ASIHTTPRequest *request = [[ASIHTTPRequest alloc] initWithURL:...]; __weak ASIHTTPRequest *wrequest = request; [request setCompletionBlock:^{ NSDictionary *jsonDictionary = [[CJSONDeserializer deserializer] deserialize:wrequest.rawResponseData error:nil]; // ... }];
это причины из-за сохранения себя в блоке. Блок будет доступен из self, и self упоминается в блоке. это создаст цикл сохранения.
попробуйте решить эту проблему, создав слабую ссылку
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];
несколько раз компилятор xcode имеет проблемы с идентификатором циклов сохранения, поэтому, если вы уверены, что вы не сохраняете completionBlock, вы можете поместить флаг компилятора следующим образом:
#pragma clang diagnostic push #pragma clang diagnostic ignored "-Warc-retain-cycles" #pragma clang diagnostic ignored "-Wgnu" -(void)someMethod { }
когда я пробую решение, предоставленное Гийомом, все в порядке в режиме отладки, но он разбивается в режиме выпуска.
обратите внимание, что не используйте __слабый, но __небезопасный_unretained, потому что моя цель-iOS 4.3.
мой код аварийно завершает работу, когда setCompletionBlock: вызывается на объект "запрос": запрос был освобожден ...
таким образом, это решение работает как в режиме отладки, так и в режиме выпуска :
// 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]; }];
ASIHTTPRequest *request = [[ASIHTTPRequest alloc] initWithURL:... __block ASIHTTPRequest *blockRequest = request; [request setCompletionBlock:^{ NSDictionary *jsonDictionary = [[CJSONDeserializer deserializer] deserialize:blockRequest.responseData error:nil]; blockRequest = nil; // .... }];
взгляните на документацию на веб-сайте разработчика Apple : https://developer.apple.com/library/prerelease/ios/#documentation/General/Conceptual/ARCProgrammingGuide/Introduction.html#//apple_ref/doc/uid/TP40011029
в нижней части страницы есть раздел о циклах сохранения.