2012-06-11 13 views
6

Ich habe ein paar Beispiele um NSArray indexOfObjectPassingTest gesehen, aber ich konnte sie nicht arbeiten lassen (sie würden keinen gültigen Index zurückgeben). So, jetzt versuche ich einen Inline-Block zu verwenden. Ich habe es getan, indem ich einen Block typedefiniert habe, ihn dann als Eigenschaft definiert, synthetisiert und im Konstruktor initialisiert habe. Aber diese Art von macht den ganzen Punkt stumm, wie ich leicht eine Methode erstellen und stattdessen verwenden könnte (weniger Tippen, weniger Aufwand).Suche nach einem Objekt-Index in NSArray mit einem Inline-Block

Was ich versuche zu erreichen ist etwas entlang dieser:

Observations *obs = [self.myAppointment.OBSERVATIONS objectAtIndex: ^NSInteger (NSString *keyword){ 
    for (Observations *obs in self.myAppointment.OBSERVATIONS) { 
     if ([obs.TIME isEqualToString:keyword] == YES) return (NSInteger)[self.myAppointment.OBSERVATIONS indexOfObject:obs]; 
    } 
    return (NSInteger)-1; 
}]; 

jedoch Xcode einfach wird es nicht haben. Ich habe verschiedene Varianten ausprobiert, aber es scheint Deklarieren inline ein Problem zu sein, was seltsam ist, weil, wie ich gesagt habe, typedefing es, zu erklären und zu synthetisieren es wie folgt funktioniert:

Observations *obs = [self.myAppointment.OBSERVATIONS objectAtIndex:findObs(keyword)]; 

Wo findObs ist wieder ein definierter Block, der das Gleiche tut. Ist das ein Syntaxproblem, oder fehlt mir noch etwas Wichtigeres?

Antwort

24

-objectAtIndex: nimmt einen NSUInteger als Parameter, aber Sie übergeben es einen Block (bezeichnet durch die ^). Ihr zweites Beispiel ruft findObs (was Ihr Block sein kann) mit dem keyword-Argument auf und übergibt das Ergebnis dieses Aufrufs an -objectAtIndex:.

Sie wollen wahrscheinlich kombinieren -objectAtIndex: mit -indexOfObjectPassingTest::

NSString *keyword = /* whatever */; 
NSArray *array = self.myAppointment.OBSERVATIONS; 
NSUInteger idx = [array indexOfObjectPassingTest:^(id obj, NSUInteger idx, BOOL *stop){ 
    Observations *obs = (Observations*)obj; 
    return [obs.TIME isEqualToString:keyword]; 
}]; 
if (idx != NSNotFound) 
    Observations *obs = [array objectAtIndex:idx]; 
+0

Dank toll gearbeitet. Ich nehme also an, dass das Übergeben eines Inline-Blocks als NSInteger-Parameter (der im Wesentlichen erwartet, dass der Rückgabewert des Blocks als Parameter übergeben wird) nicht machbar ist, es sei denn, sein Typ ist definiert und synthetisiert? –

+0

Sie können Ihren Block auch in-line aufrufen: '[... ObjektAtIndex: (^ NSInteger (NSString * k) {...}) (Schlüsselwort)];', aber die Dinge beginnen ein bisschen chaotisch. –

+1

Dieses Beispiel gibt das letzte Objekt zurück, das den Test im Array bestanden hat. Um die Iteration zu stoppen, sobald das erste Objekt gefunden wird, müssen Sie '* stop' auf' YES' setzen. – Moose

3

Es ist nicht notwendig, typedef oder irgendetwas zu synthetisieren zu Ihrem zweiten Beispiel Arbeit zu machen - nur um den Block von einer Methode zurückgeben, die wie folgt aussehen:

-(NSUInteger(^)(NSArray *, NSString *))findObs { 
    return ^(NSArray *array, NSString *keyword) { 
     for (NSUInteger i = 0; i < [array count]; i++) { 
      Observations *obs = [array objectAtIndex:i]; 
      if ([obs.TIME isEqualToString:keyword]) { 
       return i; 
      } 
     } 
     return NSNotFound; 
    }; 
} 

Observations *obs = [self.myAppointment.OBSERVATIONS objectAtIndex:[self findObs](keyword)]; 

Hier sind einige good reasons for defining blocks as method return values, rather than inline.

+1

Sie müssen den Block kopieren, den Sie zurückgeben, es sei denn, Sie verwenden ARC, die es für Sie tut – user102008

+1

Ja, @ user102008, das ist richtig. Ich gehe im Allgemeinen von ARC in diesen Tagen aus, es sei denn, es ist aus der Codebeispiel von jemandem klar, dass sie ARC nicht verwenden. –

4

Dies ist ein Beispiel, das den Index einer Zeichenfolge in einem Array von Zeichenfolgen zurückgibt. Es kann an jede Art von Objekt angepasst werden.

NSString* myString = @"stringToFind"; 
NSUInteger objectIndex = [myStringArray indexOfObjectPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) { 
     return (*stop = ([obj isEqualToString:myString])); 
    }]; 

die ursprüngliche Frage zu beantworten, genau:

NSString *keyword = @"myKeyword"; 
NSUInteger index = [self.myAppointment.OBSERVATIONS indexOfObjectPassingTest:^(id obj, NSUInteger idx, BOOL *stop) { 
    return (*stop = [(Observations*)obs.TIME isEqualToString:keyword]); 
}]; 
Observations *obs = (index!=NSNotFound) ? self.myAppointment.OBSERVATIONS[index] : NULL; 

Aber es ist ziemlich seltsam, etwas namens TIME mit einem Schlüsselwort zu vergleichen ...;)