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];
Другие вопросы по тегам