2012-06-11 12 views
6

He visto algunos ejemplos en torno al uso NSArray indexOfObjectPassingTest, pero no pude hacer que funcionen (que no volverían un índice válido). Así que ahora estoy intentando usar un bloque en línea. Lo hice tipificando un bloque, luego configurándolo como una propiedad, sintetizándolo e inicializándolo en el constructor. Sin embargo, ese tipo de información hace que todo el punto quede mudo, ya que podría crear fácilmente un método y usarlo en su lugar (menos tipeo, menos esfuerzo).La búsqueda de un índice de objeto en NSArray usando un bloque de línea

Lo que estoy tratando de lograr es algo a lo largo de este:

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

Sin embargo Xcode simplemente no lo tendrá. He probado diferentes variaciones, pero declararlo en línea parece ser un problema, que es raro, porque como he dicho, typedefing, declarando, y sintetizando funciona así:

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

Dónde está findObs de nuevo un bloque definido que hace lo mismo. ¿Es esto un problema de sintaxis, o me falta algo más importante?

Respuesta

24

-objectAtIndex: toma un NSUInteger como parámetro, pero lo está pasando un bloque (denotado por el ^). Su segundo ejemplo, se llama findObs (que puede ser su bloque) con el argumento keyword, pasando el resultado de esa llamada a -objectAtIndex:.

es probable que desee combinar -objectAtIndex: con -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

Gracias que funcionaron muy bien. Por lo tanto, considero que pasar un bloque en línea como un parámetro NSInteger (esencialmente esperando que el valor de retorno del bloque se pase como parámetro) no es factible, a menos que su tipo esté definido y sintetizado. –

+0

También puede llamar a su bloque en línea: '[... objectAtIndex: (^ NSInteger (NSString * k) {...}) (palabra clave)]; ', pero las cosas empezar a buscar un poco desordenado. –

+1

Este ejemplo devolverá el último objeto que pasa la prueba en la matriz. Para detener la iteración tan pronto como se encuentre el primer objeto, debe establecer '* stop' en' SÍ' – Moose

3

No es necesario typedef o sintetizar cualquier cosa para hacer que su segundo trabajo ejemplo - acaba de regresar de la esquina de un método, que se vería así:

-(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)]; 

Éstos son algunos good reasons for defining blocks as method return values, rather than inline.

+1

necesita copiar el bloque que está devolviendo, a menos que esté usando ARC que lo hace por usted – user102008

+1

Sí, @ user102008, eso es correcto. En general, asumo ARC en estos días, a menos que esté claro en la muestra de código de alguien que no están usando ARC. –

4

Este es un ejemplo que devuelve el índice de una cadena en una matriz de cadenas. Se puede adaptar a cualquier tipo de objeto.

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

Para responder a la pregunta original, precisamente:

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; 

Pero es bastante extraño para comparar algo que se llama tiempo con una palabra clave ...;)

Cuestiones relacionadas