为什么你有时候会把一个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
,因为NSMutableArray
是NSArray
一个子类。
铸造对物体没有任何作用。 例:
NSString *mouse = (id)@[@"mouse"];
它会编译,但variables鼠标不是NSString。 这是NSArray。 你可以简单地通过写作来检查它
po mouse
在控制台。
创build一个对象的可变副本的唯一方法是对其调用“mutableCopy”方法:
NSArray *array = @[@"a"]; NSMutableArray *mutableCopy = [array mutableCopy];