Нужно ли использовать слабые ссылки на себя всегда внутри блоков..?
Я запутался в использовании внутренних блоков, я просматриваю некоторые документы Apple, но не могу найти правильный ответ.
Некоторые люди всегда говорят, что используют слабый внутренний блок внутри, но некоторые говорят, что используют слабое я в блоках, которые скопированы, а не всегда для использования всегда.
Пример 1:
self.handler = ^(id response, NSError *error)
{
self.newresponse = response; //use weak self here
};
Пример 2:
Используя слабый я,
__weak myViewController *weakSelf = self;
[UIView animateWithDuration:interval delay:0.0 options:curve animations:^
{
[weakSelf.view.superview setTransform:CGAffineTransformMakeTranslation(0, -106)];
//in above is it use of weak is neassary
}
completion:^(BOOL finished)
{
}];
Без слабой самости;
__weak myViewController *weakSelf = self;
[UIView animateWithDuration:interval delay:0.0 options:curve animations:^
{
[myViewController.view.superview setTransform:CGAffineTransformMakeTranslation(0, -106)];
}
completion:^(BOOL finished)
{
}];
В приведенных выше примерах, которые являются правильными...?
** Я использую ARC
Ответы
Ответ 1
Вы должны использовать только слабую ссылку на self
, если self
будет удерживать ссылку на блок.
В вашем примере вы не сохраняете ссылку на свой блок в self
, вы используете только встроенные блоки с UIView animateWithDuration:
, и поэтому нет необходимости использовать __weak myViewController *weakSelf = self;
Почему это так? Поскольку блок сохранит сильные ссылки на любые переменные, которые он использует из класса с использованием блока. Это включает self
. Теперь, если сам экземпляр класса сохраняет сильную ссылку на блок, и блок сохраняет сильную ссылку на экземпляр класса, у вас есть цикл сохранения, который будет вызывать утечки памяти.
Ответ 2
Вот код, который демонстрирует ответ @WDUK:
typedef void (^SimpleBlock)();
@interface ObjectThatRetainsBlock : NSObject
@property(nonatomic, strong) SimpleBlock block;
@end
@implementation ObjectThatRetainsBlock
- (instancetype)init {
self = [super init];
if (self) {
self.block = ^{ NSLog(@"Running block in %@", self); };
self.block();
}
return self;
}
- (void)dealloc {
NSLog(@"ObjectThatRetainsBlock is deallocated.");
}
@end
@interface ObjectThatDoesNotRetainBlock : NSObject
@end
@implementation ObjectThatDoesNotRetainBlock
- (instancetype)init {
self = [super init];
if (self) {
SimpleBlock block = ^{ NSLog(@"Running block in %@", self); };
block();
}
return self;
}
- (void)dealloc {
NSLog(@"ObjectThatDoesNotRetainBlock is deallocated.");
}
@end
- (void)test {
ObjectThatRetainsBlock *objectThatRetainsBlock =
[[ObjectThatRetainsBlock alloc] init];
ObjectThatDoesNotRetainBlock *objectThatDoesNotRetainBlock =
[[ObjectThatDoesNotRetainBlock alloc] init];
}
Метод test
печатает:
Running block in <ObjectThatRetainsBlock: 0x7f95f3335e50>
Running block in <ObjectThatDoesNotRetainBlock: 0x7f95f3335c50>
ObjectThatDoesNotRetainBlock is deallocated.
Обратите внимание, что в init
методе ObjectThatDoesNotRetainBlock
мы создаем block
как ivar, но когда block
выходит за рамки, мы не будем ссылаться на него.
В методе test
, когда два объекта выходят из области видимости, обратите внимание, что ObjectThatDoesNotRetainBlock
освобождается, поскольку он не является частью цикла сохранения.
С другой стороны, objectThatRetainsBlock
не освобождается, поскольку он является частью цикла сохранения. Он сохраняет этот блок за пределами вызова метода.
Если вы хотите получить другое объяснение, см. этот ответ.