17

我想让数组中的所有对象都执行选择器。我发现了适当命名的makeObjectsPerformSelector:方法,但我有一个问题。如果我在数组上使用它,它会更改现有数组还是返回一个新数组?如果它修改了现有对象,那么在应用了选择器的情况下返回一个新数组的最简单方法是什么?

4

5 回答 5

29

makeObjectsPerformSelector: 将对数组中的每个对象运行该选择器。如果这些对象被选择器修改,它们将被修改。它不返回任何东西。现在,有一个问题,默认情况下 Cocoa 中的大多数副本都是浅副本,这意味着您获得了一个新数组,但它指向的底层对象是相同的对象。您将需要使用 initWithArray:copyItems 使其也复制根级别的项目。如果您想要一个包含更改对象的新数组以及旧数组,请执行以下操作:

NSArray *newArray = [[NSArray alloc] initWithArray:oldArray copyItems:YES];
[newArray makeObjectsPerformSelector:@selector(doSomethingToObject)];
于 2009-02-18T22:18:31.820 回答
15

如果我在数组上使用它,它会更改现有数组还是返回一个新数组?

不。

首先,阅读签名:

- (void)makeObjectsPerformSelector:(SEL)aSelector

void,后面没有星号,表示“不返回任何内容”。

其次,注意这是 NSArray 的一个方法,它是一个不可变的类。因此,makeObjectsPerformSelector:不改变接收数组,因为那是不可能的。

有 NSMutableArray,因为它是 NSArray 的子类,所以它继承了makeObjectsPerformSelector:. 但是,如果 NSMutableArray 改变了该方法的行为,它的文档将有自己的方法列表(请参阅init各种类文档中的许多定义)。没有这样的列表,因此您可以安全(且正确)推断其-[NSMutableArray makeObjectsPerformSelector:]工作方式与-[NSArray makeObjectsPerformSelector:].

对象可以修改自己以响应您的消息,但数组本身将包含与makeObjectsPerformSelector:之前相同的对象。

于 2009-02-18T23:21:31.730 回答
7

除了其他答案,如果您确实想使用调用方法的结果创建一个新数组,您可以这样做:

NSArray *derivedArray = [originalArray valueForKey:@"foo"];

在您的对象可以处理 '-valueForKey:@"foo"' 消息时才有效,并且显然仅适用于不带参数并返回非零值的方法。

于 2009-02-19T10:59:47.433 回答
2

我希望我能正确解释这一点......

如果您执行 [myArray makeObjectsPerformSelector:someSelector],您实际上只是在遍历 myArray 并将选择器消息发送到每个对象。该数组未更改,因为不允许 makeObjectsPerformSelector 更改其内容。

所以最后,你得到了具有相同对象的相同数组。

于 2009-02-18T22:25:09.540 回答
0

在下面的示例中,您可以看到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
于 2018-10-19T13:22:14.680 回答