我想让数组中的所有对象都执行选择器。我发现了适当命名的makeObjectsPerformSelector:
方法,但我有一个问题。如果我在数组上使用它,它会更改现有数组还是返回一个新数组?如果它修改了现有对象,那么在应用了选择器的情况下返回一个新数组的最简单方法是什么?
5 回答
makeObjectsPerformSelector: 将对数组中的每个对象运行该选择器。如果这些对象被选择器修改,它们将被修改。它不返回任何东西。现在,有一个问题,默认情况下 Cocoa 中的大多数副本都是浅副本,这意味着您获得了一个新数组,但它指向的底层对象是相同的对象。您将需要使用 initWithArray:copyItems 使其也复制根级别的项目。如果您想要一个包含更改对象的新数组以及旧数组,请执行以下操作:
NSArray *newArray = [[NSArray alloc] initWithArray:oldArray copyItems:YES];
[newArray makeObjectsPerformSelector:@selector(doSomethingToObject)];
如果我在数组上使用它,它会更改现有数组还是返回一个新数组?
不。
首先,阅读签名:
- (void)makeObjectsPerformSelector:(SEL)aSelector
void
,后面没有星号,表示“不返回任何内容”。
其次,注意这是 NSArray 的一个方法,它是一个不可变的类。因此,makeObjectsPerformSelector:
不改变接收数组,因为那是不可能的。
有 NSMutableArray,因为它是 NSArray 的子类,所以它继承了makeObjectsPerformSelector:
. 但是,如果 NSMutableArray 改变了该方法的行为,它的文档将有自己的方法列表(请参阅init
各种类文档中的许多定义)。没有这样的列表,因此您可以安全(且正确)推断其-[NSMutableArray makeObjectsPerformSelector:]
工作方式与-[NSArray makeObjectsPerformSelector:]
.
对象可以修改自己以响应您的消息,但数组本身将包含与makeObjectsPerformSelector:
之前相同的对象。
除了其他答案,如果您确实想使用调用方法的结果创建一个新数组,您可以这样做:
NSArray *derivedArray = [originalArray valueForKey:@"foo"];
这仅在您的对象可以处理 '-valueForKey:@"foo"' 消息时才有效,并且显然仅适用于不带参数并返回非零值的方法。
我希望我能正确解释这一点......
如果您执行 [myArray makeObjectsPerformSelector:someSelector],您实际上只是在遍历 myArray 并将选择器消息发送到每个对象。该数组未更改,因为不允许 makeObjectsPerformSelector 更改其内容。
所以最后,你得到了具有相同对象的相同数组。
在下面的示例中,您可以看到superView
创建了一个并添加了 10 个子视图,然后向它们中的每一个发送removeFromSuperView
(类中存在的方法view
),结果是 中的零子视图superView
。
如果您熟悉 JavaScript 并尝试map
在 JavaScript 中找到类似的东西,那么情况并非如此。map
对数组的每个元素运行一个函数并将其替换为结果,但这里makeObjectsPerformSelector
运行一个存在于数组的每个对象中的方法。
UIView* superView = [[UIView alloc] initWithFrame:CGRectZero];
for(int i = 0; i < 10; i++){
UIView* view = [[UIView alloc] initWithFrame:CGRectZero];
[superView addSubview:view];
}
NSLog(@"count = %lu", (unsigned long)[superView.subviews count]); // 10
[superView.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)]; // removeFromSuperview is exist in `view`, you can call [view removeFromSuperview];
NSLog(@"count = %lu", (unsigned long)[superView.subviews count]); // 0