2014-12-12 3 views
0

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

viewController.rowLabels = @[@"Hello", @"World"]; 
viewController.testBlock = ^(NSInteger itemIndex) { 
// here i want to access another property of the viewController called foo 
}; 

Таким образом, как показано выше, я хочу получить доступ к другому свойству контроллера представления в самом блоке. Нужно ли мне делать * __ слабое -> сильное назначение для достижения этого или я могу просто получить к нему доступ, например NSLog (viewController.foo)?

+0

, пожалуйста, прочитайте главный ответ здесь: http://stackoverflow.com/questions/4352561/retain-cycle-on-self-with-blocks – cdstamper

+0

Вам нужно будет предоставить нам больше информации о том, что вы намерены делать. – vikingosegundo

ответ

4

Простой, но, возможно, проблематично ответ, просто чтобы получить доступ к нему, как вы делаете другие свойства:

viewController.rowLabels = @[@"Hello", @"World"]; 
viewController.testBlock = ^(NSInteger itemIndex) { 
    ... viewController.foo ... 
}; 

С ваш фрагмент мы не можем знать, что такое viewController - например это может быть локальная переменная из метода, в котором находится этот фрагмент, или глобальной переменной и т. д. Если вы просто читаете значение в viewController, как вы здесь, это не имеет значения [1].

Вышеупомянутые работы, но может возникнуть проблема: у вас, вероятно, есть сильный справочный цикл. Экземпляр viewController ссылается на блок через его свойство testBlock, а блок ссылается на экземпляр viewController. Если обе эти ссылки сильны (вероятно), тогда у вас есть циклическая зависимость и экземпляр viewController, и блок никогда не может быть освобожден системой. Вы можете разорвать этот порочный круг, используя слабый ссылку:

viewController.rowLabels = @[@"Hello", @"World"]; 
__weak ViewController *weakViewController = viewController; // make a weak reference to the instance 
viewController.testBlock = ^(NSInteger itemIndex) 
{ 
    // temporarily make a strong reference - will last just as long as the block 
    // is executing once the block finishes executing the strong reference is 
    // removed and no strong reference cycle is left. 
    ViewController *myController = weakViewController; 
    // only execute if the `ViewController still exists 
    if (myController != nil) 
    { 
     ... myController.foo ... 
    } 
}; 

НТН

[1] отмечают, что значение, которое вы читаете, ссылка на ViewController, например, и вы можете изменить свойство этого экземпляра, то, что вы не можете сделать (и не пытаетесь сделать), - это изменить экземпляр ссылок viewController, если viewController является локальной переменной.

+1

Обратите внимание, что автоматически фиксированные переменные (не -__-переменные блока, как и ваш первый пример) фиксируются как const и поэтому неизменяемы: https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/Blocks/Articles /bxVariables.html#//apple_ref/doc/uid/TP40007502-CH6-SW1 – cdstamper

+0

@cdstamper - Точно. Но не объекты, на которые они ссылаются. Обновление с использованием блока, в котором экземпляр объекта ссылается на локальную переменную, вероятно, является более неясным сценарием, и я больше не хотел мутить воды в этом вопросе! ;-) – CRD

0

Объявите __block переменный, содержащий объект вида контроллера, например, так:

__block __weak ViewController *blockVC = viewController; 
viewController.testBlock = ^(NSInteger itemIndex) { 
    NSLog(@"%@", blockVC.foo); 
}; 

Я использовал как __block и __weak так __block неявно сильно, но добавление __weak в качестве эталона может помочь сломать сильные эталонный цикл, все еще используя сильную ссылку __block, чтобы предотвратить освобождение.


С прошивкой 5.0, кажется, как будто вы можете просто создать __weak ссылку в отличие от использования __block переменную для доступа к переменной и его свойства в пределах блока:

__weak ViewController * weakVC = viewController; 
viewController.testBlock = ^(NSInteger itemIndex) { 

    ViewController * strongVC = weakVC; 
    if (strongVC) { 
     NSLog(@"%@", strongVC.foo); 
    } 
}; 

Но обратите внимание что в отличие от использования __weak в сочетании с типом хранения __block, __weak указывает ссылку, которая может не поддерживать объект живым, то есть может освободиться, поэтому даже внутри блока weakVC может быть нулевым, прежде чем он вам действительно понадобится. (Вот почему if (strongVC) условный требуется, когда только с помощью __weak переменной в одиночку.)

+5

Я вытер комментарии, которые были здесь, когда они уходили с рельсов, и в результате стало почти невозможно следовать. Если здесь будет добавлен новый набор комментариев, пожалуйста, держите его кратким, строго по теме и вежливым. –

+3

При всей вежливости: этот ответ неверен. @futurereader. – vikingosegundo

+0

дорогой @furturereader. Надеюсь, вы понимаете, что объект в блоке, являющийся ноль, означает ошибку, но только область вызова исчезает. Это нормально. не заставляйте область действия сохраняться, так как это цикл сохранения, который вы хотите избежать любой ценой. Если ваш код должен содержать такие хаки, это доказывает, что ваша архитектура повреждена. – vikingosegundo

Смежные вопросы