Як зберігати блоки у властивостях у Objective-C?


77

Я хотів би зберегти блок object-c у властивості для подальшого використання. Я не був впевнений, як це зробити, тому я трохи погуглив, і там дуже мало інформації про тему. Але врешті-решт мені вдалося знайти рішення, і я подумав, що, можливо, варто поділитися з іншими новачками, як я.

Спочатку я думав, що мені потрібно буде писати властивості від руки, щоб використовувати Block_copy & Block_release.

На щастя, я з'ясував, що блоки є NSObjects і - copy/ - releaseеквівалентно Block_copy/ Block_release. Тож я можу використовувати @property (copy)для автоматичного створення сетерів та геттерів.


1
Можливий дублікат Чи можу я використовувати блоки Objective-C як властивості? Це питання є нещодавнішим, ніж питання там.
Річард Дж. Росс III

1
Повний приклад коду UP-TO-DATE, пояснений просто для початківців: stackoverflow.com/a/20760583/294884
Fattie,

1
Для нових читачів це надзвичайно давнє запитання тепер щасливо надзвичайно пасивне. Ви просто кажете @property (copy) void (^ doStuff) (void); з нічим більше або менше, ніж копія. в наш час це пояснюється кришталево чітко (зокрема, чому) у багатьох місцях яблучного доко. не може бути простіше; ось і вся відповідь. Дійсно, цілий випуск має лише історичну цінність, оскільки зараз ви просто використовуєте Swift.
Fattie,

Відповіді:


135

Редагувати: оновлено для ARC

typedef void(^MyCustomBlock)(void);

@interface MyClass : NSObject

@property (nonatomic, copy) MyCustomBlock customBlock;

@end

@implementation MyClass

@end

MyClass * c = [[MyClass alloc] init];
c.customBlock = ^{
  NSLog(@"hello.....");
}

c.customBlock();

5
Хтось знає, чому для блоків слід використовувати (неатомний, копіювати), а ні (неатомний, зберігати)? Зазвичай використовується retain, і я ніде не можу знайти, що пояснює, чому використовувати копію для блоків.
Стів Поттер

29
Так Дейв, справді. Я також можу шукати і бачив їх. Пояснення були неясними, як ви використовуєте копію ", щоб вони фактично пережили кадр стека". Я вважав, що збереження об’єкта також це зробить. Жодна з них не пояснила, як розподіляються блоки. Однак коментар посилався на статтю - cocoawithlove.com/2009/10/how-blocks-are-implemented-and.html, яка це добре пояснила. Див. Розділ "Блоки - це трохи дивні предмети". Тож дякую!
Стів Поттер

Дейв - Я насправді не впевнений, що особливо слід використовувати "неатомний". (FWIW - не обов'язково правильно !!! - останній найбільший док Apple, говорить, що вам слід використовувати "копію" - кінець історії.) Важко зрозуміти, що продуктивність може мати значення, і оскільки ваша публікація тут є майже єдиним у світі посиланням на Справа, можливо, це небезпечно мати там. Будь-які думки щодо цього незрозумілого питання? Дякую!
Fattie

2
@JoeBlow вам потрібна атомність, лише якщо ви стурбовані тим, щоб одночасно отримувати та встановлювати значення властивості з декількох черг. Інакше це не має значення.
Дейв ДеЛонг,

3
Я / ми використовуємо nonatomicскрізь. Це повинно було бути IMO за замовчуванням. atomicробить більшу двійкову, нижчу продуктивність (блокує всі аксесуари), і, схоже, це обіцяє безпеку потоків - коли зазвичай це потрібно вирішувати на вищому рівні, ніж майстри.
Стівен Крамер

101

Як варіант, без typedef

@property (copy, nonatomic) void (^selectionHandler) (NSDictionary*) ;


20
Щоб пояснити, оскільки синтаксис настільки непрозорий, це властивість блоку з назвою "selectionHandler", яке приймає аргумент NSDictionary * і повертає void.
Крістофер Пікслей,

Я не думаю, що це так важко читати, але я згоден, що це виглядає приємніше із typedef. Я схильний писати купу typedefs для параметрів, які зазвичай хочу передавати: PFObjectBlock, PFStringBlock, PFArrayBlock, PFErrorBlock тощо
Бесі

id, SEL, IMP дозволять подальші спрощення?
dklt

9

Ви можете знайти дуже гарне пояснення цього у сесії 712 WWDC 2012, починаючи зі сторінки 83. Правильним способом збереження блоку під ARC є такий:

@property(strong) my_block_type work;

Будьте обережні з циклами утримання. Хороший спосіб вирішити - встановити для блоку нуль, коли він вам більше не потрібен:

self.work = nil;

2
лише з ARC. За MRC це неправильно. Алеcopy працює правильно як за MRC, так і за ARC
newacct

Я не думаю, що ця копія буде добре працювати у всіх випадках у MRC, але, можливо, у більшості з них
Хорхе Перес

Ви маєте рацію з MRC, але це не в ARC. Вибачте, я хотів сказати ARC у своєму попередньому коментарі.
Хорхе Перес

Дійсно цікаво, будь-яка ідея про те, як ARC вдається перемістити блок із стеку?
MonsieurDart

"__block yourClass * blockSelf = self". Використовуйте blockSelf лише у властивості "work".
MasterBeta
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.