你为什么有时会把NSArray强制转换为NSMutableArray,有时你不能?

时间:2014-01-08 20:47:17

标签: ios iphone objective-c nsmutablearray nsarray

具体做法是:

self.words = (NSMutableArray*)[self.text componentsSeparatedByString:@" "];
只要有分隔符,

就可以正常工作。我看到该方法返回包含在NSArray中的原始字符串,如果没有的话。这个单元素NSArray固执地拒绝被强制转换为NSMutableArray。

但是,当我这样做时:

self.words = [NSMutableArray arrayWithArray:self.words];

它运作得很好。

这里有什么我想念的吗?从NSArray转换为NSMutableArray是不好的做法吗?

9 个答案:

答案 0 :(得分:4)

你很困惑。

此代码:

self.words = (NSMutableArray*)[self.text componentsSeparatedByString:@" "];

...是错误的,并且正在为你以后的崩溃做好准备。 Casting只是告诉编译器“相信我,我知道我在做什么。”它不会更改基础对象的类型。方法componentsSeparatedByString返回NSArray,而不是可变数组。如果您随后尝试改变生成的数组,则会因无法识别的选择器消息而崩溃。使用强制转换,编译器相信您的对象在运行时确实是一个可变数组,但它不会。

这会崩溃:

self.words = (NSMutableArray*)[self.text componentsSeparatedByString:@" "];
[self.words addObject: @"new"];

但是,这段代码:

self.words = [[self.text componentsSeparatedByString:@" "] mutableCopy];
[self.words addObject: @"new"];

......做对了。它不会转换指针,它是对一个方法的方法调用,该方法将NSArray作为输入并返回具有相同内容的可变数组。因此第二行将起作用,因为第一行采用了从componentsSeparatedByString返回的不可变数组,并使用它来创建一个可变数组。

答案 1 :(得分:2)

NSArray投射到NSMutableArray是不好的做法。如果你很幸运,它可能有用,因为数组是使用NSMutableArray构建的,但你不能依赖它。

如果您想NSMutableArray NSArray,请使用mutableCopy

self.words = [[self.text componentsSeparatedByString:@" "] mutableCopy];

答案 2 :(得分:2)

  

从NSArray转换为NSMutableArray是不好的做法?

是。接近荒谬,真的。

类型转换根本不会以任何方式更改对象,它只是告诉编译器它应该将对象看作是新类型的实例。但在运行时,对象保持完全相同。您可以将NSArray投射到NSMutableArray,但不会将对象转换为NSMutableArray。它仍然是同一类型的同一个对象。

答案 3 :(得分:2)

你的误解似乎与铸造的本质有关。转换不会更改对象,它只是告诉编译器假装它是该类型的对象。如果对象确实不是NSMutableArray,那么预计不会使其成为一个。

答案 4 :(得分:2)

NSString* string1 = @"this thing";
NSString* string2 = @"this";

NSMutableArray* array1;
NSMutableArray* array2;
array1 = (NSMutableArray*)[string1 componentsSeparatedByString:@" "];
array2 = (NSMutableArray*)[string2 componentsSeparatedByString:@" "];

[array1 addObject:string1]; //(A) 
[array2 addObject:string1]; //(B)

这将在(B)最后一行打破:
        -[__NSArrayI addObject:]: unrecognized selector sent to instance 0x1702257a0

但是会在(A) 1

中断

公开声明为immutable的对象可能已私下创建为可变对象。在这种情况下,如果从不可变公共类型转换为私有可变类型,一切都会正常工作。如果对象被创建为可变对象,那么这样的演员阵容将无法满足您的需求。

componentsSerparatedByString的情况下,这表明方法实现仅在需要时才创建可变数组 - 即,如果它必须向数组添加多个对象。如果它只找到一个对象,则会得到一个NSArray,如果找到多个,则会得到一个NSMutableArray。这是一个实际细节,故意以用户身份隐藏起来。

界面告诉您在所有情况下都期望NSArray,并且在所有情况下都可以使用NSArray。

你不应该依赖这些细节来获得你想要的东西。坚持使用公共API,这就是它的用途。

1 相反,正如Bryan Chen指出的那样,它现在可能不会破裂,但将来可能会这样做

答案 5 :(得分:1)

当你这样做时:

self.words = (NSMutableArray*)[self.text componentsSeparatedByString:@" "];

数组仍然是不可变的,如果你从NSMutableArray类发送一条消息,它就会崩溃。技巧(NSMutableArray*)只会让编译器满意。

在第二种情况下:

self.words = [NSMutableArray arrayWithArray:self.words];

你没有CAST,你创建一个新的数组对象。

当然,您不需要以这种方式强制转换数组。 NSMutableArray对象已经NSArray,就像派生类的任何对象同时是基类的对象一样

答案 6 :(得分:1)

在所有情况下使用第二种变体,因为它是正确的解决方案,对于支持您的代码的用户来说更清楚:

NSArray *array = [self.text componentsSeparatedByString:@" "];
self.words = [NSMutableArray arrayWithArray:array];

永远不要这样做:

self.words = [NSMutableArray arrayWithArray:self.words];

这将完全混淆所有devs =)

答案 7 :(得分:0)

在第一种情况下,componentsSeparatedByString:方法专门返回NSArray,它不能仅仅转换为可变类型。如果你想要它是可变的,你必须这样做:

self.words = [[self.text componentsSeparatedByString:@" "] mutableCopy];

第二个是在arrayWithArray:类上调用NSMutableArray方法,这意味着它正在创建NSMutableArray的实例。这就是它的原因。您可以将NSMutableArray转换为NSArray,但不能反过来,因为NSMutableArrayNSArray的子类。

答案 8 :(得分:0)

Casting对对象没有任何作用。例如:

NSString *mouse = (id)@[@"mouse"];

它会编译,但变量鼠标不是NSString。这是NSArray。你可以通过写

来检查它
po mouse

在控制台中。

创建对象的可变副本的唯一方法是在其上调用'mutableCopy'方法:

NSArray *array = @[@"a"];
NSMutableArray *mutableCopy = [array mutableCopy];