iOS中怎么判断可变和不可变的坑(更正版)
iOS中怎么判断可变和不可变的坑
怎么判断NSString和NSMutableString呢
看题
BOOL result = [@"123" isKindOfClass:[NSMutableString class]]; // A:YES B:NO
送分题一看就选B的。然而正确答案却是A(这里提及下涉及的两个概念:类簇,工厂模式)
看控制台弄出来的结果
id str0 = [NSString alloc];//NSPlaceholderString->NSString id str1 = [[NSString alloc] init];//__NSCFConstantString->__NSCFString->NSMutableString->NSString id str3 = [NSString stringWithFormat:@"123"];//NSTaggedPointerString->NSString id str4 = [NSMutableString alloc];//NSPlaceholderMutableString->NSMutableString->NSString id str5 = [NSMutableString new];//__NSCFString->NSMutableString->NSString
字符串常量,也就是str1那种创建方式得到的类型是__NSCFConstantString并且明目张胆的是NSMutableString的子类。无论如何请勇敢的质疑苹果脑残的设计。并且后面的Array和Dictionary就不存在这种脑残的地方。我们无法知道到底黑盒子里有多少这种子类,根据倒推法:
所以现在判断一个字符串是可变的这么写就行了
BOOL isMutable = [str isMemberOfClass:NSClassFromString(@"__NSCFString")];//请注意是isMemberOfClass:这个方法不要用成isKindOfClass:
把Array的控制台结果也弄出来简单的看一下
NSArray* arr0 = [[NSArray alloc] init];//__NSArray0->NSArray NSArray* arr1 = [NSArray arrayWithObject:@"123"];//__NSArrayI->NSArray NSMutableArray* arr3 = [[NSMutableArray alloc] init];//__NSArrayM->NSMutableArray->NSArray
可以发现虽然NSArray也子嗣众多,但不会出现String那种近亲乱的情况。
判断Array是不可变的这么写就行了,不需要写字符串的类型
BOOL notMutable = [arr isKindOfClass:[NSArray class]]&&![arr isKindOfClass:[NSMutableArray class]];
NSDictionary的情况同NSArray。
转注出:原文
===========更正===========================
上面的方法在实际使用中被证明是错的,看如下两个方法
//在有的版本中执行结果如下
@(123).description;//__NSCFString->NSMutableString->NSString [NSString stringWithFormat:@"123%d",123]//__NSCFString->NSMutableString->NSString
就是说这两种情况从外部审查类型来看,根本和[NSMutableString new]的效果是一样的,而且是响应下面的方法的
[xxx respondsToSelector:@selector(appendFormat:)];
但是实际的情况是一调用就崩溃了。不听老人言吃亏在眼前,真的是最打脸的道理最朴素。一个不开源的东西,我们就是喜欢在外面赌博。
思考了很久我发现了解决之道,大道果然至简:我不知道它怎么实现的,但是苹果知道……
所以:
id copyed = [xxx copy]; if(copyed == xxx){ @"不可变".nslog(); }else{ @"可变的".nslog(); }
如果一个对象是可变的,copy之后会返回新对象,我们比较这两个指针就可以了。里面是如何实现的,我们不再关心。