具体做法是:
self.words = (NSMutableArray*)[self.text componentsSeparatedByString:@" "];
只要有分隔符,就可以正常工作。我看到该方法返回包含在NSArray中的原始字符串,如果没有的话。这个单元素NSArray固执地拒绝被强制转换为NSMutableArray。
但是,当我这样做时:
self.words = [NSMutableArray arrayWithArray:self.words];
它运作得很好。
这里有什么我想念的吗?从NSArray转换为NSMutableArray是不好的做法吗?
答案 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
,但不能反过来,因为NSMutableArray
是NSArray
的子类。
答案 8 :(得分:0)
Casting对对象没有任何作用。例如:
NSString *mouse = (id)@[@"mouse"];
它会编译,但变量鼠标不是NSString。这是NSArray。你可以通过写
来检查它po mouse
在控制台中。
创建对象的可变副本的唯一方法是在其上调用'mutableCopy'方法:
NSArray *array = @[@"a"];
NSMutableArray *mutableCopy = [array mutableCopy];