2012-05-23 20 views
2

如果我想要做的事情是可能的,我不知道。我对块没有经验,只是阅读了一些教程,非常喜欢这个想法。 我的类AppointmentView.h(和m)扩展了ViewController。它包含一些属性,这些属性是另一个类别约会的成员,而这些属性又有一些NSArrays。 为了创建分组tableview,我检查数组的值,然后适当复制将显示的值(没有太花哨或复杂)。 通常我会去的if-else语句,并适当地控制,望着块后,但是,它让我想,如果以下是可行的:用动态代码枚举NSArray的Block-Closures和三元运算符

[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 length]: unrecognized selector sent to instance 0x6bd68f0

我也试过typedefining,我可以用一个通用的方法,但没有帮助的。 所以,我想知道,这可能吗?我知道,对于这段代码,我可以简单地使用if-else(就像我通常会这样做)并完成它,但是其他情况下,这种动态代码生成选项将非常有用。

我的感觉是,无论是NSString的不知道如何处理这一点,因此我应该有一个选项扩展它让说

initWithBlock:

还是我人在这里失去了一些东西。或者它可能只是不可能....(?)

PS:我刚刚看到NSArray的enumerateUsingBlock:方法,但我不确定这是否会在这种情况下,我的目的,因为数组中的每个条目是完全不同的,而一个特定的块不符合标准。

回答

3

如果您需要在初始化程序中进行简单的选择,则不需要块。

[NSArray initWithObjects: 
     ([myAppointment.CANCELED isEqualToString:@"NO"] ? @"Not Cancelled" : @"Cancelled"), 
     ([myAppointment.CANCELED isEqualToString:@"NO"] ? @"No Cancellation reason" : myAppointment.CANCREASON), 
     nil]; 

使用parens来包围?:运算符。


更新来回答如何在同一地点定义和调用块问题

这个单元测试工作对我来说:

- (void)testBlockNow 
{ 
    BOOL X = ^{ return YES; }(); 
    STAssertTrue(X, nil); 
} 

这很简单:^{ … }定义块,然后()来调用该块。

+0

谢谢,这工作得很好。在这种情况下,这就足够了。然而,在更复杂的情况下,如果三元运算符不够用,我怎么能使用当场定义的块而不是三元运算符? –

+0

为我更新了我的答案。 –

+1

@Alex:有一个GCC扩展,它可以让你将一个任意复杂的语句块作为一个表达式来包含:gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html我认为这样可以做到你想要的而不会搞乱当你不需要它时,用块。 – newacct

2

是的,你可以将块存储在一个数组中,但你需要对它有所了解。

typedef (void)(^X)(); 

X block1 = ^{ … }; 
X block2 = ^{ … }; 
X block3 = ^{ … }; 

NSArray *array = [NSArray initWithObjects: 
        [[block1 copy] autorelease], 
        [[block2 copy] autorelease], 
        [[block3 copy] autorelease], 
        nil]; 
+0

这是非常有用的,但不是真正的我以后,因为在这种情况下,你正在使用不同的块为每个案件。我宁愿不定义任何东西,但随着值的填充,实现该块。 –

+0

我不确定你要求什么。如果你想动态添加和删除数组中的块,这是可能的。使用带有-addObject:和-removeObject:的NSMutableArray。如果你想在运行时创建新块,这在编译语言中是不可能的。 –

+0

不完全是,我希望编译的代码(块)根据其他变量动态生成字符串的值。我可能会做错误的参数和指针,因为我得到的错误似乎表明没有选择器为某些实例设置。现在就试试你的例子。 –