Block-Closures и тернарный оператор для перечисления NSArray с динамическим кодом
Я понятия не имею, возможно ли то, что я пытаюсь сделать, или нет. У меня нет опыта работы с блоками, я просто прочитал несколько уроков и мне очень понравилась идея. Мой класс AppointmentView.h (и m) расширяет ViewController. Он содержит несколько свойств, которые являются членами другого Назначения класса, которое, в свою очередь, имеет несколько NSArrays. В целях создания сгруппированного табличного представления я проверяю значения массивов, а затем соответствующим образом копирую значения, которые будут отображаться (ничего особенного или сложного). Обычно я следую инструкциям if-else и соответствующим образом контролирую их, однако, посмотрев на блоки, я подумал, выполнимо ли следующее:
[self setOutcomes: [[NSArray alloc] initWithObjects:
^{ return [myAppointment.CANCELED isEqualToString:@"NO"] == YES ?
[[NSString alloc] initWithString:@"Not Cancelled"] :
[[NSString alloc] initWithString:@"Cancelled"]; },
^{ return [myAppointment.CANCELED isEqualToString:@"NO"] == YES ?
[[NSString alloc] initWithString:@"No Cancellation reason"] :
[[NSString alloc] initWithString:myAppointment.CANCREASON]; },
^{ return [myAppointment EVENTS].length > 0 ?
[[NSString alloc] initWithString:myAppointment.EVENTS] :
[[NSString alloc] initWithString:@"No Events"]; },
^{ return [myAppointment SUMMARY].length > 0 ?
[[NSString alloc] initWithString:myAppointment.SUMMARY] :
[[NSString alloc] initWithString:@"No Summary"]; },
nil]];
Этот код компилируется нормально, но он вылетает при запуске. Насколько я понимаю, это неправильно, потому что я говорю перечислению выполнять фрагмент кода каждый раз. Так что это не то, что я хочу. Тогда я попробовал следующее:
[self setOutcomes: [[NSArray alloc] initWithObjects:
[[NSString alloc] initWithString: (NSString *) ^(void){
return [myAppointment.CANCELED isEqualToString:@"NO"] == YES ?
@"Not Cancelled" : @"Cancelled"; }],
[[NSString alloc] initWithString: (NSString *) ^(void){
return [myAppointment.CANCELED isEqualToString:@"NO"] == YES ?
@"No Cancellation reason" : myAppointment.CANCREASON; }],
[[NSString alloc] initWithString: (NSString *) ^(void){
return [myAppointment.EVENTS isEqualToString:@""] == YES ?
myAppointment.EVENTS : @"No Events"; }],
[[NSString alloc] initWithString: (NSString *) ^(void){
return [myAppointment.SUMMARY isEqualToString:@""] == YES ?
myAppointment.SUMMARY : @"No Summary"; }],
nil]];
Который, хотя он прекрасно компилируется, вылетает со следующей ошибкой:
- [ДлинаNSMallocBlock ]: нераспознанный селектор отправлен на экземпляр 0x6bd68f0
Я также попытался определить тип универсального метода, который мог бы использовать, но тоже не помог. Итак, мне было интересно, это возможно? Я знаю, что для этого фрагмента кода я мог бы просто использовать if-else (как обычно) и покончить с этим, но при других обстоятельствах такой вариант генерации динамического кода был бы чрезвычайно полезен.
У меня сложилось впечатление, что либо NSString не знает, как с этим справиться, и поэтому я должен расширить его с помощью опций, скажем,
initWithBlock:
Или я что-то здесь упускаю. Или это может быть просто невозможно.... (?)
PS: я только что видел NSArray enumerateUsingBlock: метод, но я не уверен, что это послужит моей цели в этом случае, так как каждая запись в массиве полностью отличается от другой, и конкретный блок не будет соответствовать критериям.
2 ответа
Если вам нужно сделать простой выбор в инициализаторе, вам не нужны блоки.
[NSArray initWithObjects:
([myAppointment.CANCELED isEqualToString:@"NO"] ? @"Not Cancelled" : @"Cancelled"),
([myAppointment.CANCELED isEqualToString:@"NO"] ? @"No Cancellation reason" : myAppointment.CANCREASON),
nil];
Используйте парены, чтобы заключить оператор?:.
Обновлено, чтобы ответить на вопрос о том, как определить и вызвать блок в том же месте
Этот модульный тест работал для меня:
- (void)testBlockNow
{
BOOL X = ^{ return YES; }();
STAssertTrue(X, nil);
}
Это просто: ^{ … }
определить блок, затем ()
чтобы вызвать блок.
Да, вы можете хранить блоки в массиве, но вам нужно быть умным.
typedef (void)(^X)();
X block1 = ^{ … };
X block2 = ^{ … };
X block3 = ^{ … };
NSArray *array = [NSArray initWithObjects:
[[block1 copy] autorelease],
[[block2 copy] autorelease],
[[block3 copy] autorelease],
nil];