Я немного запутался в использовании блока в Objective-C. В настоящее время я использую ARC, и в моем приложении довольно много блоков, и в настоящее время я всегда ссылаюсь на self
него вместо его слабой ссылки. Может ли это быть причиной того, что эти блоки сохранили self
и не допустили их освобождения? Вопрос в том, должен ли я всегда использовать weak
ссылку self
в блоке?
-(void)handleNewerData:(NSArray *)arr
{
ProcessOperation *operation =
[[ProcessOperation alloc] initWithDataToProcess:arr
completion:^(NSMutableArray *rows) {
dispatch_async(dispatch_get_main_queue(), ^{
[self updateFeed:arr rows:rows];
});
}];
[dataProcessQueue addOperation:operation];
}
ProcessOperation.h
@interface ProcessOperation : NSOperation
{
NSMutableArray *dataArr;
NSMutableArray *rowHeightsArr;
void (^callback)(NSMutableArray *rows);
}
ProcessOperation.m
-(id)initWithDataToProcess:(NSArray *)data completion:(void (^)(NSMutableArray *rows))cb{
if(self =[super init]){
dataArr = [NSMutableArray arrayWithArray:data];
rowHeightsArr = [NSMutableArray new];
callback = cb;
}
return self;
}
- (void)main {
@autoreleasepool {
...
callback(rowHeightsArr);
}
}
Ответы:
Это помогает не сосредоточиться на
strong
илиweak
части обсуждения. Вместо этого сосредоточьтесь на части цикла .Сохраняет цикл представляет собой цикл , который происходит , когда объект А сохраняет объект B, и объект Б сохраняет объект A. В этой ситуации, если любой объект выпущен:
Таким образом, эти два объекта будут просто зависать в памяти на протяжении всей жизни программы, даже если они должны, если все работает правильно, быть освобождены.
Итак, нас беспокоит то, что мы сохраняем циклы , и сами по себе блоки не создают эти циклы. Это не проблема, например:
Блок сохраняет
self
, ноself
не сохраняет блок. Если один или другой освобождается, цикл не создается, и все освобождается, как и должно быть.Где вы попали в беду это что-то вроде:
Теперь ваш объект (
self
) имеет явнуюstrong
ссылку на блок. И у блока есть неявная сильная ссылка наself
. Это цикл, и теперь ни один объект не будет освобожден должным образом.Поскольку в подобной ситуации,
self
по определению, уже имеетсяstrong
ссылка на блок, обычно ее проще всего решить, сделав явно слабую ссылкуself
для использования блока:Но это не должно быть шаблоном по умолчанию, который вы используете при работе с блоками, которые вызывают
self
! Это следует использовать только для разрыва того, что в противном случае было бы циклом сохранения между собой и блоком. Если бы вы применили этот шаблон повсюду, вы бы рискнули передать блок чему-то, что было выполнено послеself
освобождения.источник
-setCompleteionBlockWithSuccess:failure:
метода. Но еслиpaginator
он принадлежитViewController
, и эти блоки не были вызваны после того, как онViewController
был бы освобожден, использование__weak
ссылки было бы безопасным ходом (потому чтоself
владеет вещью, которая владеет блоками, и поэтому, вероятно, все еще будет рядом, когда блоки вызывают ее хотя они не сохраняют это). Но это много "если". Это действительно зависит от того, что это должно делать.MyObject
иSomeOtherObject
оба владеют блоком. Но поскольку ссылка на блок обратноMyObject
естьweak
, блок не принадлежитMyObject
. Таким образом , в то время как блок гарантированно существовать до тех пор , как либоMyObject
илиSomeOtherObject
существует, нет никакой гарантии , чтоMyObject
будет существовать до тех пор , пока блок делает.MyObject
может быть полностью освобожден, и, пока онSomeOtherObject
еще существует, блок все еще будет там.Вам не нужно всегда использовать слабую ссылку. Если ваш блок не сохраняется, но выполняется, а затем отбрасывается, вы можете сильно захватить себя, так как он не создаст цикл сохранения. В некоторых случаях вы даже хотите, чтобы блок удерживал себя до завершения блока, чтобы он не освобождался преждевременно. Однако, если вы захватите блок сильно, а внутри себя захватите, это создаст цикл сохранения.
источник
Я полностью согласен с @jemmons:
Чтобы преодолеть эту проблему, можно определить сильную ссылку
weakSelf
внутри блока:источник
->
), где вы хотите гарантировать, что вы действительно получили действительную ссылку, и постоянно удерживать ее в течение всего набора операций, например,if ( strongSelf ) { /* several operations */ }
Как указывает Лео, код, который вы добавили в свой вопрос, не предлагал бы сильный ссылочный цикл (иначе, сохранить цикл). Одна из проблем, связанных с операцией, которая может привести к сильному циклу ссылок, может быть, если операция не освобождается. Хотя ваш фрагмент кода предполагает, что вы не определили свою операцию как параллельную, но если она у вас есть, она не будет выпущена, если вы никогда не публиковали
isFinished
, или если у вас были циклические зависимости или что-то в этом роде. И если операция не будет отменена, контроллер представления также не будет освобожден. Я бы предложил добавить точку останова или методNSLog
вашей операцииdealloc
и подтвердить, что он вызывается.Ты сказал:
Проблемы с циклом сохранения (сильный ссылочный цикл), возникающие с блоками, аналогичны проблемам с циклом сохранения, с которыми вы знакомы. Блок будет поддерживать сильные ссылки на любые объекты, которые появляются внутри блока, и он не будет освобождать эти сильные ссылки, пока сам блок не будет освобожден. Таким образом, если блок ссылается
self
или даже просто ссылается на переменную экземпляраself
, которая будет поддерживать сильную ссылку на себя, это не разрешается до тех пор, пока блок не будет освобожден (или в этом случае, пока неNSOperation
будет освобожден подкласс.Для получения дополнительной информации см. Раздел « Избегайте сильных эталонных циклов при захвате себя» в разделе « Программирование с помощью Objective-C: Работа с блоками» .
Если ваш контроллер представления все еще не освобождается, вы просто должны определить, где находится неразрешенная сильная ссылка (при условии, что вы подтвердили, что
NSOperation
освобождается). Типичным примером является использование повторенияNSTimer
. Или некоторый пользовательскийdelegate
или другой объект, который ошибочно поддерживаетstrong
ссылку. Вы можете часто использовать Инструменты, чтобы отследить, где объекты получают свои сильные ссылки, например:Или в Xcode 5:
источник
В некоторых объяснениях игнорируется условие о цикле сохранения [Если группа объектов связана кругом сильных отношений, они поддерживают друг друга, даже если нет сильных ссылок вне группы.] Для получения дополнительной информации прочитайте документ
источник
Вот как вы можете использовать себя внутри блока:
// вызов блока
источник