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