为什么你有时候会把一个NSArray转换成NSMutableArray,有时你不能呢?

特别:

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

只要有分离器就能正常工作。 但是我发现如果没有这个方法的话,这个方法会返回一个包装在NSArray中的原始string。 这个单独的元素NSArray固执地拒绝被转换为一个NSMutableArray。

但是,当我这样做:

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

它工作得很好。

有什么我在这里失踪? 从NSArray投射到NSMutableArray是不好的做法吗?

你很困惑。

此代码:

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

…是错误的,并且正在设置你以后的崩溃。 施放只是告诉编译器“相信我,我知道我在做什么”。 它不会更改基础对象的types。 方法componentsSeparatedByString返回一个NSArray,而不是一个可变的数组。 如果您尝试对结果数组进行变异,您将会遇到无法识别的select器消息。 通过转换,编译器相信你的对象在运行时真的是一个可变数组,但是不会。

这会崩溃:

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

但是,这个代码:

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

做正确的事情 它不会强制转换指针,而是调用一个方法,该方法将NSArray作为input并返回一个具有相同内容的可变数组。 因此,第二行将工作,因为第一行接受来自componentsSeparatedByString的不可变数组,并使用它来创build一个可变数组。

NSArray投射到NSMutableArray是不好的做法。 如果你幸运的话,它可能会工作,因为数组是用NSMutableArray构造的,但是你不能依赖它。

如果你想从NSArray NSMutableArray ,使用mutableCopy

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

从NSArray投射到NSMutableArray是不好的做法吗?

是。 接近无意义,真的。

types转换不会以任何方式改变对象,它只是告诉编译器它应该把对象看作是新types的一个实例。 但在运行时,对象保持完全一样。 你可以将一个NSArray转换成一个NSMutableArray但是它不会把这个对象转换成一个NSMutableArray 。 它仍然是同一types的同一个对象。

你的误解似乎是关于铸造的本质。 铸造不会改变对象,它只是告诉编译器假装它是这种types的对象。 如果这个对象真的不是一个NSMutableArray,那么就不会让它变成一个。

 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

公开声明为不可变的对象可能已被私人创build为可变的。 在这种情况下,如果你从不可变公有types转换为私有可变types,一切都会正常工作。 如果对象没有被创build为可变的,那么这样的演员将不会得到你想要的。

componentsSerparatedByString的情况下,这表明方法实现只在需要的时候才会创build一个可变数组 – 即,如果它必须向数组添加多个对象的话。 如果它只find一个对象,你得到一个NSArray,如果它发现多个,你得到一个NSMutableArray。 这是作为用户故意隐藏的实现细节。

界面告诉你在任何情况下都期望一个NSArray,并且在所有情况下这都会工作。

你不应该依靠这样的细节来得到你想要的。 坚持公共API,就是这样。

正如布莱恩·陈指出的那样,现在可能不会突破,但是未来可能会这样做

当你这样做的时候:

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

该数组仍然保持不变,如果您从NSMutableArray类发送消息它将崩溃。 技巧(NSMutableArray*)只是使编译器很高兴。

在第二种情况下:

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

你不CAST,你创build一个新的数组对象。

当然,你不需要这样的arrays。 NSMutableArray对象是已经NSArray就像派生类的任何对象同时是一个基类的对象

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

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

千万不要这样做:

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

这将完全混淆所有开发=)

在第一种情况下, componentsSeparatedByString:方法是专门返回一个NSArray ,它不能被转换为可变types。 如果你想要变化,你将不得不这样做:

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

第二个是调用NSMutableArray类的arrayWithArray:方法,这意味着它正在创build一个NSMutableArray的实例。 这就是为什么它的作品。 你可以把一个NSMutableArray成一个NSArray ,但是不能NSArray ,因为NSMutableArrayNSArray一个子类。

铸造对物体没有任何作用。 例:

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

它会编译,但variables鼠标不是NSString。 这是NSArray。 你可以简单地通过写作来检查它

 po mouse 

在控制台。

创build一个对象的可变副本的唯一方法是对其调用“mutableCopy”方法:

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