2 Stimmen

Block-Closures und ternärer Operator zur Aufzählung von NSArray mit dynamischem Code

Ich habe keine Ahnung, ob das, was ich zu tun versuche, möglich ist oder nicht. Ich habe keine Erfahrung mit Blöcken, nur ein paar Tutorials gelesen, und wirklich wie die Idee. Meine Klasse AppointmentView.h (und m) ist eine Erweiterung eines ViewControllers. Sie enthält ein paar Eigenschaften, die Mitglieder einer anderen Klasse Appointment sind, die wiederum ein paar NSArrays hat. Um einen gruppierten Tableview zu erstellen, überprüfe ich die Werte der Arrays und kopiere dann die entsprechenden Werte, die angezeigt werden sollen (nichts allzu Ausgefallenes oder Kompliziertes). Normalerweise würde ich mit if-else-Anweisungen zu gehen, und die Kontrolle entsprechend, aber nach dem Blick auf Blöcke, es hat mich denken, wenn die folgenden machbar ist:

[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]];

Dieser Code lässt sich gut kompilieren, stürzt aber bei der Ausführung ab. Meines Erachtens ist das falsch, weil ich die Aufzählung anweise, jedes Mal ein Stück Code auszuführen. Das ist also nicht das, was ich will. Dann habe ich das Folgende versucht:

   [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]];

Dieser lässt sich zwar gut kompilieren, stürzt aber mit dem folgenden Fehler ab:

-[ NSMallocBlock length]: nicht erkannter Selektor an Instanz 0x6bd68f0 gesendet

Ich habe auch versucht, eine generische Methode zu definieren, die ich verwenden könnte, aber auch das hat nicht geholfen. Ich frage mich also, ob das möglich ist. Ich weiß, dass ich für dieses Stück Code einfach ein if-else verwenden könnte (wie ich es normalerweise tun würde) und damit fertig wäre, aber unter anderen Umständen wäre eine solche dynamische Codegenerierungsoption äußerst nützlich.

Ich habe das Gefühl, dass entweder NSString nicht weiß, wie dies zu behandeln, und ich sollte daher erweitern es mit einer Optionen lässt sagen

initWithBlock:

Oder ich übersehe hier etwas anderes. Oder es ist vielleicht einfach nicht möglich.... (?)

PS: Ich habe soeben die Methode enumerateUsingBlock: von NSArray gesehen, aber ich bin mir nicht sicher, ob dies in diesem Fall meinem Zweck dienen würde, da sich jeder Eintrag im Array völlig von den anderen unterscheidet und ein bestimmter Block nicht den Kriterien entsprechen würde.

3voto

Jeffery Thomas Punkte 41299

Wenn Sie im Initialisierungsprogramm einfache Entscheidungen treffen müssen, brauchen Sie keine Blöcke.

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

Verwenden Sie Parens, um den Operator ?: einzuschließen.


Aktualisiert, um die Frage zu beantworten, wie man einen Block an der gleichen Stelle definiert und aufruft

Dieser Einheitstest hat bei mir funktioniert:

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

Das ist ganz einfach: ^{ … } um den Block zu definieren, dann () um den Block aufzurufen.

2voto

Jeffery Thomas Punkte 41299

Ja, Sie können Blöcke in einem Array speichern, aber Sie müssen es geschickt anstellen.

typedef (void)(^X)();

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

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

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X