Ответ 1
Вместо этого вы захотите сделать это:
- (void) setupStoredBlock
{
int salt = 42;
m_storedBlock = Block_copy(^(int incoming){ return 2 + incoming + salt; });
}
Я пытаюсь понять блоки. Я получаю, как использовать их обычно, когда передается непосредственно методу. Мне сейчас интересно взять блок, сохранить его (скажем) в переменной экземпляра и вызвать его позже.
Руководство по программированию блоков заставляет его звучать так, как я могу это сделать, используя Block_copy/сохранить, чтобы скопировать блок, но когда я пытаюсь запустить его, я разбиваю свою программу.
- (void) setupStoredBlock
{
int salt = 42;
m_storedBlock = ^(int incoming){ return 2 + incoming + salt; };
[m_storedBlock retain];
}
Я пытаюсь называть его позже:
- (void) runStoredBlock
{
int outputValue = m_storedBlock(5);
NSLog(@"When we ran our stored blockwe got back: %d", outputValue);
[m_storedBlock release];
}
У кого-нибудь есть идеи? (Или, что-то я не получаю с блоками?)
Большое спасибо!
Вместо этого вы захотите сделать это:
- (void) setupStoredBlock
{
int salt = 42;
m_storedBlock = Block_copy(^(int incoming){ return 2 + incoming + salt; });
}
Скопируйте блок, когда вы хотите, чтобы он оставался. Autorelease или отпустите его, когда вы закончите с ним. Сохраните его, если вам понадобится длинный путь для написания /* NOP */
.
@interface Foo : FooSuper {}
@property(copy) int (^storedBlock)(int);
@end
@implementation Foo
@synthesize storedBlock = mStoredBlock;
- (void)setupStoredBlock {
self.storedBlock = ^{/*...*/};
// or: mStoredBlock = [^{/*...*/} copy];
// but this simple implementation violates the atomicity contract
}
- (void)runStoredBlock {
int result = self.storedBlock(5);
NSLog(@"%s: result = %d", __func__, result);
}
@end
• Как и все локальные переменные, в стеке существует нестатический блок и будет выгружаться из стека, как и любая другая локальная переменная, которая не была объявлена статической.
• Block_copy() копирует блок из стека в кучу, где все экземпляры malloc существуют. И, как и все новые методы /copy, Block_copy() возвращает объект с выделенной кучей с номером сохранения 1. Блок является объектом objectC, но не соответствует как обычный объект. Следовательно, не должно быть разницы между Block_Release() и методом объектной разблокировки.
• В этом примере используется метод копирования экземпляра блока. Поскольку для присвоения результата Block_copy() для идентификатора требуется тип, который я делаю. Не хочу ошибаться. Метод копирования позволяет блок-переменной присваиваться непосредственно идентификатору.
- (void) setupStoredBlock
{
int zStackLocalVariable = 42;
iHeapAllocatedVariable = [^int(int aMore){ return zStackLocalVariable + aMore; } copy];
}
• Чтобы объявить объект static, требуется, чтобы он был физически выделен самим кодом. Блоком, который объявляется статичным, является компилятор, которому запрещен доступ к переменным за пределами его собственной области. Из-за требований объявления статического блока я предполагаю, что блок в стеке каким-то образом отличается от блока, который находится в куче.
• Блок - объективный объект c, класс которого, чье имя класса и другая связанная информация я еще не пытался извлечь, но, как и объекты Protocol, Object и другие скрытые классы objectC, он не соответствует NSObject. Однако, как и все объекты objectC, он должен соответствовать сохранению/освобождению. ARC расширяет эквиваленты сохранения/освобождения в объектах Core Foundation и, возможно, если не сейчас, то в конечном итоге, в malloc/free allocations.
• Я жду настоящей мотивации для тщательного изучения mikeash.com, так как яблоко любит держать нас всех на некоторых гипер-теоретических плоскости небольшого физического значения, хотя все, что имеет значение, является физическим.
В недавнем WWDC (2010) была очень приятная презентация по этому вопросу. В нем описано, как были реализованы блоки и почему вам нужно использовать Block_copy. Вы можете скачать фильм из презентации: http://developer.apple.com/itunes/?destination=adc.apple.com.4092414566 Фильм называется "Расширенный Objective-C и сбор мусора"