questo è un argomento chiamato Higher Order Messaging in Cocoa, e sviluppato da molte persone sul web. Inizia da here e prova a cercare su Google di più. Essi aggiungono un metodo categoria NSArray
in modo che si può fare
NSArray*transformed=[[anArray map] stringByDeletingPathExtension];
L'idea è la seguente:
[anArray map]
crea un oggetto temporaneo (diciamo hom
)
hom
riceve il messaggio stringByDeletingPathExtension
hom
invia nuovamente il messaggio a tutti gli elementi di anArray
hom
raccoglie i risultati e restituisce l'array risultante.
Se si desidera solo una rapida trasformazione, che definirei un metodo categoria:
@interface NSArray (myTransformingAddition)
-(NSArray*)my_arrayByApplyingBlock:(id(^)(id))block;
@end
@implementation NSArray (myTransformingAddition)
-(NSArray*)my_arrayByApplyingBlock:(id(^)(id))block{
NSMutableArray*result=[NSMutableArray array];
for(id x in self){
[result addObject:block(x)];
}
return result;
}
@end
allora si può fare
NSArray* transformed=[anArray my_arrayByApplyingBlock:^id(id x){return [x stringByDeletingPathExtension];}];
Nota il costrutto ^ return-type (arguments) { ...}
che crea un blocco. Il tipo di ritorno può essere omesso e clang
è abbastanza intelligente per indovinarlo, ma lo gcc
è piuttosto rigido e deve essere specificato qualche volta. (In questo caso, è indovinato dalla dichiarazione return
che ha [x stringBy...]
che restituisce un NSString*
. Così GCC indovina il tipo di ritorno del blocco di essere NSString*
invece di id
, che GCC pensa incompatibile, quindi arriva l'errore.)
Su OS X Leopard o iOS 3, è possibile utilizzare PLBlocks per supportare i blocchi. La mia personale opinione soggettiva è che le persone che si preoccupano del nuovo software in genere eseguono l'aggiornamento al nuovo sistema operativo, quindi supportare l'ultimo sistema operativo dovrebbe essere perfetto; supportare un vecchio sistema operativo non aumenterà il tuo cliente di un fattore di due ...
CHE HA DATO, c'è già un bel framework open-source che fa tutto ciò che ho detto sopra. Vedere la discussione here e in particolare lo FunctionalKit collegato lì.
Più oltre: è, infatti, facile da realizzare il vostro pseudocodice [array transform:stringByDeletingPathExtension]
.
@interface NSArray (myTransformingAddition)
-(NSArray*)my_transformUsingSelector:(SEL)sel;
@end
@implementation NSArray (myTransformingAddition)
-(NSArray*)my_transformUsingSelector:(SEL)sel;{
NSMutableArray*result=[NSMutableArray array];
for(id x in self){
[result addObject:[x performSelector:sel withObject:nil]];
}
return result;
}
@end
Quindi è possibile utilizzare come segue:
NSArray*transformed=[array my_transformUsingSelector:@selector(stringByDeletingPathExtension)];
Tuttavia non mi piace così tanto; è necessario disporre di un metodo già definito sull'oggetto nell'array per utilizzare questo metodo. Ad esempio, se NSString
non ha l'operazione cosa vuoi fare come metodo, cosa faresti in questo caso? È necessario aggiungere un primo momento ad NSString
tramite una categoria:
@interface NSString (myHack)
-(NSString*)my_NiceTransformation;
@end
@implementation NSString (myHack)
-(NSString*)my_NiceTransformation{
... computes the return value from self ...
return something;
}
@end
quindi è possibile utilizzare
NSArray*transformed=[array my_transformUsingSelector:@selector(my_NiceTransformation)];
ma tende ad essere molto prolisso, perché è necessario definire il metodo in altri posti prima. Io preferisco fornendo quello che voglio operare direttamente presso il sito di chiamata, come in
NSArray*transformed=[array my_arrayByApplyingBlock:^id(id x){
... computes the return value from x ...
return something;
}];
Infine, i metodi categoria mai aggiuntivi che non iniziano con un prefisso come my_
o qualsiasi altra cosa. Ad esempio, in futuro Apple potrebbe fornire un buon metodo chiamato transform
che fa esattamente quello che vuoi. Ma se hai già un metodo chiamato transform
nella categoria, questo porterà a un comportamento indefinito. In effetti, può succedere che ci sia già un metodo privato di Apple nella classe.
considerando tutti 'transform' davvero è loop sugli elementi, non sto davvero vedendo l'ineleganza di farlo da soli ... –
vuoi per farlo sul posto o creare un nuovo array? Hai anche bisogno di rimuovere percorsi per i file? I dati di esempio (che mostrano gli elementi iniziali dell'array e ciò che si desidera siano i risultati) sarebbero utili. La cosa migliore quando si scrive una domanda è di fornire una grande quantità di informazioni, pur restando concise. – outis
@Nicholas: si tratta di livelli di astrazione e manutenibilità più elevati. Quando puoi esprimere la tua intenzione su una riga e non devi scrivere (o copiare/incollare) lo stesso ciclo più volte, il codice è più facile da capire e mantenere. Se la singola linea è sufficientemente avanzata (a.k.a troppo intelligente per il programmatore medio), allora preferirei fare il ciclo anche io. – pesche