0

Я недавно узнал этот трюк, когда мне нужно ссылаться на я внутри блока.Захват Self в двойном блоке с ARC

__weak MyObject *safeSelf = self; 
[self doWithCompletionBlock:^{ 

    HMFInventoryBatchItemsController *strongSelf = safeSelf; 
    if (strongSelf) { 
     [strongSelf doSomethingElse]; 
    } 
}]; 

Но мне было интересно, что, если у меня есть блок внутри блока? Нужно ли снова делать то же самое?

__weak MyObject *safeSelf = self; 
    [self doWithCompletionBlock:^{ 

     HMFInventoryBatchItemsController *strongSelf = safeSelf; 
     if (strongSelf) { 

      __weak MyObject *saferSelf = strongSelf; 
      [strongSelf doAnotherThingWithCompletionBlock:^{ 

       HMFInventoryBatchItemsController *strongerSelf = saferSelf; 
       if (strongerSelf) { 
        [strongerSelf doSomethingElse]; 
       } 
      }]; 
     } 
    }]; 

Или это нормален

__weak MyObject *safeSelf = self; 
    [self doWithCompletionBlock:^{ 

     HMFInventoryBatchItemsController *strongSelf = safeSelf; 
     if (strongSelf) { 

      [strongSelf doAnotherThingWithCompletionBlock:^{ 

        [strongSelf doSomethingElse]; 

      }]; 
     } 
    }]; 
+1

Почему переназначение себя с помощью HMFInventoryBatchItemsController * strongSelf = safeSelf; Так как сам является собственностью блока? –

+0

Вам не нужно делать ссылку в блоке, если вы не хотите получить доступ к ее ivar. – Elden

+0

Я нашел эту статью в качестве ссылки http://amattn.com/2011/12/07/arc_best_practices.html – Hackmodford

ответ

2

Хороший ответ, это зависит. Это вообще небезопасно делать:

__weak MyObject *safeSelf = self; 

[self doWithCompletionBlock:^{ 
     [safeSelf doAnotherThingWithCompletionBlock:^{ 
       [safeSelf doSomethingElse]; 
     }]; 
}]; 

Причиной этого является то, что при вызове -doAnotherThingWithCompletionBlock, если этот метод считает он содержит ссылку на self, который обычно предполагает селектор, и разыменовывает себя для доступа к иварам, то вы потерпите крах, потому что на самом деле вы не держите ссылку.

Итак, нужно ли вам брать новую слабую ссылку или нет, зависит от семантики жизни, которую вы хотите/хотите.

EDIT:

Кстати, лязг даже есть предупреждение о том, что вопрос, который вы можете включить в Xcode с установкой CLANG_WARN_OBJC_RECEIVER_WEAK (CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK также полезно в то время как мы на него)

+0

Вы, вероятно, имеете в виду «метод» вместо «селектор». И вы, вероятно, также имеете в виду «ссылки на ивары» вместо «разыменования иваров», означает «self-> someIvar;»;) – CouchDeveloper

+0

действительно, я просто переформулировал свой ответ – JTAS

+0

Хорошо, теперь выглядит хорошо. ;) – CouchDeveloper

0
__block MyObject *safeSelf = self; 

    [self doWithCompletionBlock:^{ 
      [safeSelf doAnotherThingWithCompletionBlock:^{ 
        [safeSelf doSomethingElse]; 
      }]; 
    }]; 

Надеется, что это будет делать то, что он обычно делает должен. Сообщите компилятору, чтобы он не сохранил __weak MyObject * независимо от того, в какой области блока он находится. Дело в том, что я не тестировал. Тем временем я буду удивлен, если он действительно сохранит MyObject *

+0

Есть ли способ проверить это? – Hackmodford

+0

Вы можете использовать keepcount и смотреть, если у safeself есть +1 счет внутри блока (конечно, сделайте простой код, который может гарантировать, что «я» не сохраняется в другом месте.). Второй способ - это когда вы отпускаете объект после использования блочного вызова (если ваши блоки являются ivars, а не локальными для области функций). Если dealloc никогда не вызывается, ваши блоки сохраняют объект блокировки блока. Цель «__weak» - на самом деле предотвратить это. –

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