本文介绍了是否有一个Objective-C的算法,如C ++ STL的`transform`?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的目标是拥有一个包含特定扩展名的所有文件名的数组,但没有扩展名。

有一个elegant解决方案获取特定扩展名的所有文件名使用predicate过滤器和instructions就如何分割成路径文件名和扩展,但把它们结合在一起我会写一个循环(不可怕,但是不优雅要么)。

有没有用Objective-C的一种方式(可能是类似predicate机制),应用一些功能到一个数组中的每个元素,并把结果在第二阵列,如变换的C ++ STL的算法呢?

我想要写的:

  //我们pretend'anArray'中弥漫通过查询文件系统,而不是硬codeD
NSArray的* anArray = [[NSArray的页头] initWithObjects:@one.ext,@two.ext,零]

//这就是我喜欢写(伪code)
NSArray的*转化= [anArray变换:stringByDeletingPathExtension]。

//虞姬的回答下面提出的(这可能是接近你可以得到
//我的愿望与目标C)
NSArray的*转化= [anArray my_arrayByApplyingBlock:^(ID X){
                           返回[X stringByDeletingPathExtension]
                       }];
 

解决方案

这是一个所谓的高阶消息可可,和许多人在网络上发展起来的话题。从从这里开始,并尝试使用Google更多。他们添加类别的方法的NSArray 这样就可以做到

 的NSArray *转化= [[anArray图] stringByDeletingPathExtension]。
 

的思想如下:

  • [anArray图] 创建一个临时对象(比如
  • 收到邮件 stringByDeletingPathExtension
  • 重新将消息发送到的所有元素 anArray
  • 收集结果,并返回结果数组。

如果你只是想快速变换,我会定义一个类中的方法:

  @interface的NSArray(myTransformingAddition)
 - (NSArray的*)my_arrayByApplyingBlock:(ID(^)(ID))块;
@结束

@implementation的NSArray(myTransformingAddition)
 - (NSArray的*)my_arrayByApplyingBlock:(ID(^)(ID)){块
     NSMutableArray里*结果= [NSMutableArray的阵列]
     对于(内径×自我){
          [结果ADDOBJECT:块(X)];
     }
     返回结果;
}
@结束
 

然后,你可以做

 的NSArray *转化= [anArray my_arrayByApplyingBlock:^编号(ID X){返回[X stringByDeletingPathExtension];}];
 

请注意构建 ^返回类型(参数){...} 这将创建一个块。返回类型可以被省略,是猜测它很聪明,但 GCC 是很严格吧并且需要被某个指定。 (在这种情况下,它是从返回语句其中有猜测 [X stringBy ...] 返回一个的NSString * 。所以GCC猜测块的返回类型为的NSString * 而不是 ID ,其中海合会认为是不兼容的,因此而来的错误。)

在OS X Leopard或iOS的3,你可以用 PLBlocks 支持块。我个人主观的看法是,谁在乎新的软件的人通常升级到最新的操作系统,因此支持最新的OS应该只是罚款;支持较旧的操作系统不会受到两个因素增加你的客户?

这就是说,不过已经有了很好的开源框架,做了所有我上面说的。见讨论这里,尤其是的挂在那里。


更多加法:它实际上是很容易实现的伪code [排列变换:stringByDeletingPathExtension]。

  @interface的NSArray(myTransformingAddition)
 - (NSArray的*)my_transformUsingSelector:(SEL)SEL;
@结束

@implementation的NSArray(myTransformingAddition)
 - (NSArray的*)my_transformUsingSelector:(SEL)SEL; {
     NSMutableArray里*结果= [NSMutableArray的阵列]
     对于(内径×自我){
          [结果ADDOBJECT:[X performSelector:SEL withObject:无]];
     }
     返回结果;
}
@结束
 

然后你可以使用它,如下所示:

 的NSArray *转化= [阵列my_transformUsingSelector:@selector(stringByDeletingPathExtension)];
 

不过,我不喜欢那么多;需要有对象上已定义的阵列中使用这种方法的方法。例如,如果的NSString 没有你想要做一个什么样的方法操作,你会在这种情况下怎么办?您需要首先它通过一个类别添加到的NSString

  @interface的NSString(myHack)
 - (的NSString *)my_NiceTransformation;
@结束

@implementation的NSString(myHack)
 - (的NSString *)my_NiceTransformation {
   ...计算从自我的返回值...
   返回的东西;
}
@结束
 

然后你可以用

 的NSArray *转化= [阵列my_transformUsingSelector:@selector(my_NiceTransformation)];
 

但它往往是非常详细的,因为你需要首先定义在其他地方的方法。我preFER提供什么,我想直接调用现场操作,如

 的NSArray *转化= [阵列my_arrayByApplyingBlock:^编号(ID X){
   ...计算从x的返回值...
   返回的东西;
}];
 

最后,永远添加类方法不开始与preFIX像我_ 或什么的。例如,在未来苹果可能会提供一个名为很好的方法转换这不正是你想要的。但是,如果你有一个名为方法转换的类别已,这将导致不确定的行为。事实上,它可以发生,有类中的私有方法由苹果了。

My goal is to have an array that contains all filenames of a specific extension, but without the extension.

There's an elegant solution to get all filenames of a specific extension using a predicate filter and instructions on how to split a path into filename and extension, but to combine them I would have to write a loop (not terrible, but not elegant either).

Is there a way with Objective-C (may be similar to the predicate mechanism) to apply some function to every element of an array and put the results in a second array, like the transform algorithm of the C++ STL does?

What I'd like to write:

// let's pretend 'anArray' was filled by querying the filesystem and not hardcoded
NSArray* anArray = [[NSArray alloc] initWithObjects:@"one.ext", @"two.ext", nil];

// that's what I liked to write (pseudo code)
NSArray* transformed = [anArray transform: stringByDeletingPathExtension];

// Yuji's answer below proposes this (which may be as close as you can get
// to my wish with Objective C)
NSArray* transformed = [anArray my_arrayByApplyingBlock:^(id x){
                           return [x stringByDeletingPathExtension];
                       }];
解决方案

That's a topic called Higher Order Messaging in Cocoa, and developed by many people on the web. Start from here and try googling more. They add a category method to NSArray so that you can do

NSArray*transformed=[[anArray map] stringByDeletingPathExtension];

The idea is as follows:

  • [anArray map] creates a temporary object (say hom)
  • hom receives the message stringByDeletingPathExtension
  • hom re-sends the message to all the elements of anArray
  • hom collects the results and returns the resulting array.

If you just want a quick transform, I would define a category method:

@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

Then you can do

NSArray* transformed=[anArray my_arrayByApplyingBlock:^id(id x){return [x stringByDeletingPathExtension];}];

Note the construct ^ return-type (arguments) { ...} which creates a block. The return-type can be omitted, and clang is quite smart on guessing it, but gcc is quite strict about it and needs to be specified sometime. (In this case, it's guessed from the return statement which has [x stringBy...] which returns an NSString*. So GCC guesses the return type of the block to be NSString* instead of id, which GCC thinks is incompatible, thus comes the error. )

On OS X Leopard or iOS 3, you can use PLBlocks to support blocks. My personal subjective opinion is that people who care about new software typically upgrade to the newest OS, so supporting the latest OS should be just fine; supporting an older OS won't increase your customer by a factor of two...

THAT SAID, there's already a nice open-source framework which does all I said above. See the discussion here, and especially the FunctionalKit linked there.


More addition: it's in fact easy to realize your pseudocode [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

Then you can use it as follows:

NSArray*transformed=[array my_transformUsingSelector:@selector(stringByDeletingPathExtension)];

However I don't like it so much; you need to have a method already defined on the object in the array to use this method. For example, if NSString doesn't have the operation what you want to do as a method, what would you do in this case? You need to first add it to NSString via a category:

@interface NSString (myHack)
-(NSString*)my_NiceTransformation;
@end

@implementation NSString (myHack)
-(NSString*)my_NiceTransformation{
   ... computes the return value from self ...
   return something;
}
@end

Then you can use

NSArray*transformed=[array my_transformUsingSelector:@selector(my_NiceTransformation)];

But it tends to be very verbose, because you need to define the method in other places first. I prefer providing what I want to operate directly at the call site, as in

NSArray*transformed=[array my_arrayByApplyingBlock:^id(id x){
   ... computes the return value from x ...
   return something;
}];

Finally, never add category methods which do not start with a prefix like my_ or whatever. For example, in the future Apple might provide a nice method called transform which does exactly what you want. But if you have a method called transform in the category already, that will lead to an undefined behavior. In fact, it can happen that there is a private method by Apple already in the class.

这篇关于是否有一个Objective-C的算法,如C ++ STL的`transform`?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-05 00:33