Подтвердить что ты не робот

ARC, ivars в блоках и эталонных циклах через захваченное я

Im работает в чистой среде iOS5/ARC, поэтому я могу использовать ссылки __weak по мере необходимости. Я делаю ссылку на ivars в блоке во многих ситуациях, в первую очередь, на блоки анимации, которые перемещают представления вокруг, которые являются свойствами, например, моего класса контроллера представления.

Мой вопрос:

В самом тривиальном использовании ivars в блоке я создаю ссылочный цикл? Нужно ли использовать метод __weak self/strong self каждый раз, когда я пишу блок, который манипулирует переменными экземпляра содержащего объекта?

Я пересматривал сессию WWDC 2011 года № 322 (Objective-C Advancements in Depth), чтобы понять нюансы относительно 3-минутного сегмента, начинающегося со времени индекса 25:03 о "Reference Cycle Via Captured Self". Для меня это подразумевает, что любое использование иваров в блоке должно быть защищено с помощью слабой self/strong self setup, как описано в этом сегменте.

Пример метода ниже на контроллере просмотра типичен для анимаций, которые я делаю.

В блоке openIris неправильно ли ссылаться на ivars "_topView" и "_bottomView", как у меня?

Должен ли я всегда настраивать ссылку __weak для себя перед блоком, а затем сильную ссылку внутри блока на слабую ссылку, только что настроенную ранее, а затем получить доступ к ivars через эту сильную ссылку в моем блоке?

Из сеанса WWDC я понимаю, что ссылки на ivars в блоке действительно создают ссылку на подразумеваемое я, которое эти ivars висят.

Для меня это означает, что на самом деле нет простого или тривиального случая, когда правильно получить доступ к иварам в блоке без слабой/сильной танцы, чтобы не было циклов. Или я читаю много в углу, который не распространяется на простые случаи, например мой пример?

- (void)openIrisAnimated:(BOOL)animated
{
    if (_isIrisOpened) {
        NSLog(@"Asked to open an already open iris.");
        return; // Bail
    }

    // Put the common work into a block.
    // Note: "_topView" and "_bottomView" are the backing ivars of 
    // properties "topView" and "bottomView"
    void (^openIris)() = ^{
        _topView.frame     = CGRectMake(....);        
        _bottomView.frame  = CGRectMake(....);
    };

    // Now do the actual opening of the iris, whether animated or not:
    if (animated) {
        [UIView animateWithDuration:0.70f 
                         animations:^{
                             openIris();
                         }];
    }
    else {
        openIris();
    }

    _irisOpened = YES; // Because we have now just opened it
}

Вот как Id переписывает кусок openIris с помощью руководства с сеанса № 322, но мне просто интересно, нужны ли все мои аналогичные блоки для этого слабого/сильного эталонного танца, чтобы обеспечить правильность и стабильность:

__weak MyClass *weakSelf = self;


void (^openIris)() = ^{
     MyClass *strongSelf = weakSelf;

     if (strongSelf) {        
        strongSelf.topView.frame     = CGRectMake(....);
        strongSelf.bottomView.frame  = CGRectMake(....);
     }
};

Действительно ли это необходимо?

4b9b3361

Ответ 1

Здесь существует только цикл, если он затем продолжает удерживать ссылку на блок (или что-то принадлежащее себе). Если нет, вам хорошо идти, поскольку срок службы блока не продиктован тем, что он сохранил.

Итак, в вашем конкретном примере вы, кажется, поняли. Анимационные блоки не обязательно должны участвовать в слабом/сильном танце.

Ответ 2

Случай, о котором нужно беспокоиться, это что-то вроде addObserverForName:object:queue:usingBlock:. Документы говорят: "Блок копируется центром уведомлений". В ARC это слово "копия" является красным флагом; теперь вам нужно предпринять шаги, чтобы вы (вызывающий) не просочились.

EDIT: Кроме того, иногда сам ARC будет предупреждать вас. Блок завершения -[UIPageViewController setViewControllers:direction:animated:completion:] является примером. Я бы никогда не подозревал, что использование self здесь может привести к циклу удержания, но ARC предупредил, что это произойдет, поэтому я сделал слабый сильный танец на всякий случай.