Эта тема называется «Сообщения высшего порядка в какао» и разработана многими людьми в Интернете.Начните с здесь и попробуйте поискать больше.Они добавляют метод категории к NSArray
, так что вы можете сделать
NSArray*transformed=[[anArray map] stringByDeletingPathExtension];
Идея заключается в следующем:
[anArray map]
создает временный объект (скажем, hom
) hom
получает сообщение stringByDeletingPathExtension
hom
повторно отправляет сообщение всем элементам anArray
hom
собирает результатыи возвращает полученный массив.
Если вы просто хотите быстрое преобразование, я бы определил метод категории:
@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
Тогда вы можете сделать
NSArray* transformed=[anArray my_arrayByApplyingBlock:^id(id x){return [x stringByDeletingPathExtension];}];
Обратите внимание на конструкцию ^ return-type (arguments) { ...}
, которая создает блок.Возвращаемый тип может быть опущен, и clang
достаточно умен, чтобы угадать его, но gcc
довольно строги в этом и его нужно когда-нибудь указать.(В этом случае это делается из оператора return
, который имеет [x stringBy...]
, который возвращает NSString*
. Таким образом, GCC предполагает, что тип возвращаемого блока равен NSString*
вместо id
, который GCC считает несовместимымТаким образом, появляется ошибка.)
В OS X Leopard или iOS 3 вы можете использовать PLBlocks для поддержки блоков.Мое личное субъективное мнение заключается в том, что люди, которым небезразлично новое программное обеспечение, обычно переходят на новейшую ОС, поэтому поддержка последней ОС должна быть просто отличной;поддержка более старой ОС не увеличит вашего клиента в два раза ...
ЭТО СКАЗАЛ , уже есть хорошая платформа с открытым исходным кодом, которая делает все, что я сказал выше.См. Обсуждение здесь , и особенно связанный с ним FunctionalKit .
Более того: ваш псевдокод на самом деле легко реализовать [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
Тогда вы можете использовать его следующим образом:
NSArray*transformed=[array my_transformUsingSelector:@selector(stringByDeletingPathExtension)];
Однако мне это не очень нравится;вам необходимо иметь метод, уже определенный для объекта в массиве, чтобы использовать этот метод.Например, если NSString
не имеет операции, которую вы хотите сделать как метод, что бы вы сделали в этом случае?Сначала вам нужно добавить его в NSString
через категорию:
@interface NSString (myHack)
-(NSString*)my_NiceTransformation;
@end
@implementation NSString (myHack)
-(NSString*)my_NiceTransformation{
... computes the return value from self ...
return something;
}
@end
Затем вы можете использовать
NSArray*transformed=[array my_transformUsingSelector:@selector(my_NiceTransformation)];
Но это, как правило, очень многословно, потому что вам нужно определитьМетод в других местах в первую очередь.Я предпочитаю предоставлять то, что я хочу, чтобы работать непосредственно на сайте вызова, как в
NSArray*transformed=[array my_arrayByApplyingBlock:^id(id x){
... computes the return value from x ...
return something;
}];
Наконец, никогда добавлять методы категории, которые не начинаются с префикса, такого как my_
или чего-либо еще,Например, в будущем Apple может предоставить хороший метод под названием transform
, который делает именно то, что вы хотите.Но если у вас уже есть метод с именем transform
в категории, это приведет к неопределенному поведению.На самом деле, может случиться так, что в классе Apple уже есть частный метод.