Нужно ли всегда использовать слабые ссылки на себя внутри блоков?

Меня смущает использование блоков self inside, я просматриваю некоторые документы 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


person ShivaPrasad    schedule 02.11.2012    source источник
comment
возможный дубликат Можно пройти [self anyFunction] в блоках без объекта __weak (iOS 5 + ARC)   -  person Abizern    schedule 02.11.2012
comment
Также дубликат stackoverflow.com/questions/20030873/   -  person Rose Perrone    schedule 05.04.2015


Ответы (2)


Вы должны использовать только слабую ссылку на self, если self будет удерживать ссылку на блок.

В вашем примере вы не сохраняете ссылку на свой блок в self, вы используете только блоки, встроенные в UIView animateWithDuration:, и поэтому нет необходимости использовать __weak myViewController *weakSelf = self;

Почему это так? Потому что блок сохранит сильные ссылки на любые переменные, которые он использует, из класса, использующего блок. Это включает self. Теперь, если сам экземпляр класса хранит сильную ссылку на блок, а блок хранит сильную ссылку на экземпляр класса, у вас есть цикл сохранения, который вызовет утечку памяти.

person WDUK    schedule 02.11.2012
comment
поэтому в методе класса (animateWithDuration) нет необходимости в слабом я, так как я не сохраняю и не владею этим блоком, я прав...? - person ShivaPrasad; 02.11.2012
comment
В примере 1 self.handler = ^(id response, NSError *error) { self.newresponse = response; //используем здесь слабое я }; нам нужна неделя self, так как блок сохраняется сам, а self сохраняется блоком, поэтому он сохраняет циклы...? - person ShivaPrasad; 02.11.2012
comment
@jeeva В примере 1 требуется слабая ссылка на себя. В примерах 2 и 3 слабая ссылка на себя не требуется. - person WDUK; 02.11.2012
comment
Спасибо, ваше объяснение полностью имеет смысл. Однако я не могу объяснить использование weakSelf в этом примере кода от Apple: developer.apple.com/library/ios/#documentation/AddressBook/ - person Ortwin Gentz; 09.01.2013
comment
Нужна слабая ссылка, потому что блок использует свойство, принадлежащее себе (weakSelf.numberOfSmiths). Если вы обращаетесь к свойству объекта, это сохранит объект, чтобы убедиться, что свойство по-прежнему доступно при запуске блока. - person WDUK; 09.01.2013
comment
Я до сих пор не до конца понимаю. Если он использовал self.numberOfSmiths, он все равно не должен вызывать цикл сохранения. self не имеет ссылки на блок. - person mlaster; 20.07.2013
comment
Хороший момент, я упустил тот факт, что self не сохраняет блок; это просто обратный вызов для фреймворка. Извинения. Я считаю, что в данном случае это форма защитного кодирования. Нет ничего плохого в том, чтобы объявить его слабым, поскольку концептуально нет смысла сохранять здесь self (почему обратный вызов должен продлевать жизнь self?). Это также означает, что если кто-то захочет сохранить блок позже, ему не нужно менять его содержимое. В конечном счете, хотя объявление его слабым здесь не требуется для предотвращения утечек, некоторые программисты используют этот стиль для обеспечения надежности. - person WDUK; 22.07.2013
comment
Нужно ли использовать слабую ссылку для self, если мы вызываем методы только в нем? Скажи myblock {[self removeLoadingIcon];} ? - person GoodSp33d; 24.11.2013
comment
@WDUK, что, если блок анимации работает бесконечно? - person onmyway133; 12.02.2015
comment
@WDUK, что, если (поскольку блок анимации является отложенной операцией) self освобождается при запуске блока? - person Stas; 01.02.2016
comment
You should only use a weak reference to self, if self will hold on to a reference of the block. Что делать, если вы анимируете элемент UIKit в блоке, но ваше представление освобождается? Вы не хотите сохранять сильную ссылку, чтобы просто анимировать что-то, чего больше нет в представлении, поэтому в этом случае имеет смысл также использовать weak, даже если нет цикла сохранения. - person Pablo A.; 31.08.2016

Вот код, демонстрирующий ответ @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 как ивар, но когда block выходит за рамки, мы не сохраняем ссылку на него.

В методе test, когда два объекта выходят за пределы области видимости, обратите внимание, что objectThatDoesNotRetainBlock освобождается, поскольку он не является частью цикла сохранения.

С другой стороны, objectThatRetainsBlock не освобождается, потому что это часть цикла сохранения. Он сохраняет блок вне области вызова метода.

Если вам нужно другое объяснение, см. этот ответ.

person Rose Perrone    schedule 05.04.2015