Вопрос

Я использую блоки уже некоторое время, но чувствую, что есть вещи, которые мне не хватает в управлении памятью как в ARC, так и в средах без ARC.Я чувствую, что более глубокое понимание поможет мне устранить многие утечки памяти.

AFNetworking — это мое основное использование блоков в конкретном приложении.Большую часть времени внутри обработчика завершения операции я делаю что-то вроде «[self.myArray addObject]».

Как в средах с поддержкой ARC, так и без нее, «self» будет сохраняться в соответствии с эта статья от Apple.

Это означает, что всякий раз, когда вызывается блок завершения сетевой операции AFNetworking, self сохраняется внутри этого блока и освобождается, когда этот блок выходит за пределы области действия.Я считаю, что это относится как к ARC, так и к не-ARC.Я запустил инструмент Leaks и статический анализатор, чтобы найти любые утечки памяти.Никто ничего не показал.

Однако лишь недавно я наткнулся на предупреждение, которое не мог понять.В этом конкретном примере я использую ARC.

У меня есть две переменные экземпляра, которые указывают на завершение и сбой сетевой операции.

@property (nonatomic, readwrite, copy) SFCompletionBlock completionBlock;
@property (nonatomic, readwrite, copy) SFFailureBlock failureBlock;
@synthesize failureBlock = _failureBlock;
@synthesize operation = _operation;

Где-то в коде я делаю это:

[self.operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id
                                                    responseObject) {
NSError *error = [NSError errorWithDomain:@"com.test" code:100 userInfo:@{@"description": @"zero results"}];
            _failureBlock(error);
        } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
            NSLog(@"nothing");
        }];

Xcode жалуется на строку, вызывающую errorBlock, с сообщением «Сильный захват «self» в этом блоке, скорее всего, приведет к циклу сохранения.Я считаю, что Xcode прав:блок отказа сохраняет себя, а сам — свою копию блока, поэтому ни один из двух не будет освобожден.

Однако у меня есть следующие вопросы/наблюдения.

1) Если я изменю _failureBlock(error) на «self.failureBlock(error)» (без кавычек), компилятор перестанет жаловаться.Почему это?Это утечка памяти, которую пропускает компилятор?

2) В общем, как лучше всего работать с блоками как в средах с поддержкой ARC, так и без нее при использовании блоки, являющиеся переменными экземпляра?Кажется, что в случае блоков завершения и сбоя в AFNetworking эти два блока нет переменные экземпляра, поэтому они, вероятно, не попадают в категорию циклов сохранения, которые я описал выше.Но что можно сделать при использовании блоков прогресса в AFNetworking, чтобы избежать циклов сохранения, подобных приведенному выше?

Мне бы хотелось услышать мысли других людей об ARC и не-ARC с блоками и проблемах/решениях с управлением памятью.Я считаю, что такие ситуации склонны к ошибкам, и считаю, что необходимо некоторое обсуждение этого вопроса, чтобы прояснить ситуацию.

Не знаю, имеет ли это значение, но я использую Xcode 4.4 с последней версией LLVM.

Это было полезно?

Решение

1) Если я изменяю _failureblock (ошибка) на "self.failureblock (ошибка)" (без кавычек) компилятор останавливает жалобу. Это почему? Это Утечка памяти компилятор пропускает?

Цикл сохранения существует в обоих случаях. Если вы нацеливаете iOS 5+, вы можете пройти со слабым ссылкой на себя:

__weak MyClass *weakSelf;
[self.operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
    NSError *error = [NSError errorWithDomain:@"com.test" code:100 userInfo:@{@"description": @"zero results"}];
    if (weakSelf.failureBlock) weakSelf.failureBlock(error);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    NSLog(@"nothing");
}];
.

Сейчас я не будет сохранен, и если он будет отделен до того, как вызывается обратный вызов, обратный вызов - это NO-OP. Тем не менее, возможно, что он может пройти откидность, в то время как обратный вызов вызывается на фоновой резьбе, поэтому этот шаблон может создать случайные аварии.

2) в целом, какова лучшая практика для работы с блоками в обоих Среды с поддержкой дуги и без дуги при использовании блоков Переменные экземпляра? Кажется, что в случае завершения и неудачи Блоки в Afnetworking, эти два блока не являются переменными экземпляра, так Они, вероятно, не попадают в категорию сохранения циклов, которые я описано выше. Но при использовании блоков прогресса в AfnetWorking, Что можно сделать, чтобы избежать сохранения циклов, как то выше?

Большую часть времени, я думаю, Это лучше не Блоки хранения в экземплярах переменные . Если вы вместо этого возвращаете блок из способа в своем классе, у вас все еще будет сохранить цикл сохранения, но он существует только с момента, когда этот метод будет выпущен в момент, когда блок выпускается. Таким образом, он предотвратит выделение вашего применения во время выполнения блока, но цикл сохранения заканчивается, когда блок выпускается:

-(SFCompletionBlock)completionBlock {
    return ^(AFHTTPRequestOperation *operation , id responseObject ) {
        [self doSomethingWithOperation:operation];
    };
}

[self.operation setCompletionBlockWithSuccess:[self completionBlock]
                                      failure:[self failureBlock]
];
.

Другие советы

Это означает, что всякий раз, когда называется блок завершения операции сети Afnetworking, Self сохраняется внутри этого блока и выпускается, когда этот блок выходит из сферы действия.

Нет, self сохраняется в блоке при его создании.И он освобождается, когда блок освобождается.

Я считаю, что Xcode прав:Блок отказа сохраняет себя, и Self удерживает свою собственную копию блока, поэтому ни один из двух не будет сделкой.

Рассматриваемый блок, который сохраняет self блок завершения передается setCompletionBlockWithSuccess. self не содержит ссылки на этот блок.Скорее, self.operation (вероятно, что-то вроде NSOperation) сохраняет блоки во время выполнения.Таким образом, существует временный цикл.Однако когда операция завершится выполнением, цикл будет разорван.

1) Если я изменю _failureBlock (ошибка) на «self.failureBlock (ошибка)» (без кавычек) Компилятор прекращает жаловаться.Почему это?Это утечка памяти, которую пропускает компилятор?

Разницы быть не должно. self фиксируется в обоих случаях.Компилятор не гарантирует, что он уловит все случаи циклов сохранения.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top