为什么当所有变量都可变时尝试使用replaceOccurrencesOfString尝试变更不可变对象:
非常简单的代码,我可以说它在Xcode 4.1中按照预期工作,但在Xcode 4.2中中断。下面是有问题的代码:为什么当所有变量都可变时尝试使用replaceOccurrencesOfString尝试变更不可变对象:
-(void)mergeDevData2Email:(NSMutableString *)target codeArray:(NSArray *)array1 valueArray:(NSArray *)array2 {
NSUInteger n = 0;
for (NSMutableString *aCode in array1) {
if ([array2 count] > n) {
NSMutableString *arg = [array2 objectAtIndex:(NSUInteger)n];
NSLog(@"Target isKindOf NSMutableString: %@", ([target isKindOfClass:[NSMutableString class]]) ? @"YES" :@"NO");
NSLog(@"aCode isKindOf NSMutableString: %@", ([aCode isKindOfClass:[NSMutableString class]]) ? @"YES" :@"NO");
NSLog(@"arg isKindOf NSMutableString: %@", ([arg isKindOfClass:[NSMutableString class]]) ? @"YES" :@"NO");
[target replaceOccurrencesOfString:aCode withString:arg options:NSLiteralSearch range:NSMakeRange(0, [target length])];
n++;
}
else {
break;
}
}
}
这就是NSLogs显示:
2011-11-03 15:42:59.967 TestProg [30413:C503]目标isKindOf的NSMutableString:YES
2011 -11-03 15:42:59.968 TestProg [30413:C503] ACODE isKindOf的NSMutableString:YES
2011-11-03 15:42:59.969 TestProg [30413:C503] ARG isKindOf的NSMutableString:YES
当我执行[target replaceOcurances ...行代码我碰撞-
编程接收信号:“SIGABRT”。
随着在控制台日志以下 -
2011-11-03 15:43:26.828 TestProg [30413:C503] *终止应用程序由于未捕获的异常 'NSInvalidArgumentException',原因:“尝试mutate与replaceOccurrencesOfString不可变的对象:withString:options:range:'
我的问题是,我在哪里试图改变一个不可变的对象?其次,为什么在Xcode 4.1中执行得很好?当然,所有玩家都看到了Xcode 4.1的可变性。 Xcode 4.2 有什么区别?我在这里错过了一些微妙的东西。
我怀疑有些字符串并不是真正可变的字符串(可能是“目标”,因为这是您要修改的字符串)。这让我很困惑,但“isKindOf:”并没有区分可变字符串和不可变字符串。我相信你的NSLog查询将返回YES,即使字符串不可变。
如果停在调试器中,您应该能够检查对象并确定它们是否确实是可变的(“真实”类名应该与对象一起显示)。
至于为什么这工作在4.1而不是4.2,很难说。这可能是一些系统例程返回一个NSString用来返回一个NSMutableString,但不再。
如果我是正确的,你将需要去堆栈找出目标来自哪里。在某些时候,它可能已经从NSString转换为NSMutableString。
这是一个链接,备份我关于isKindOf的声明:... http://stackoverflow.com/questions/1788690/objective-c-how-to-check-if-variable-is-nsarray-or-nsmutablearray – Ron
那么,我相信你是关于isKindOf的。和保罗一样。但是我已经将目标反映的变量定义为NSMutableString变量。它就是这样......我很难理解如何按摩或替换代码,以实现我想要的功能。有什么建议么 ?谢谢。 – Ric
只需要检查一下更多的东西......你说你将它定义为一个NSMutableString,但它是从哪里创建的?仅仅因为某些东西被声明为NSMutableString并不意味着指针就是那个对象。编译器应该能够捕获指针被误判的情况,但这并不完美。你停在调试器中,看看“目标”对象是什么样子?调试器说它是什么类?你知道实际创建该对象的代码行吗? – Ron
查阅Apple文档isKindOfClass:。
它基本上是说不要使用这种支票类集群,并接着说
如果您调用返回一个类簇的方法,该方法返回的确切类型是最好的指标你可以用这个对象做什么。
这是完全可能的,他们改变了在这个实例中SDK类之间从类集群返回的类型。
在“target”中传递的变量被定义并用作NSMutableString的每个位置。一个地方的方法,之前所讨论的方法中调用,变量是从文件的内容加载,并在该方法我,从缺乏经验,使用的语句:
self.messageBody = fileContents;
fileContents是一个NSString的。哎呀。
这显然为具有不同内存地址的messageBody创建了一个新的内存位置,并且不是可变的。问题 - 这是否实际上是一个新对象?如果是这样,我猜它也会造成内存泄漏,因为第一个实例不能再被释放。
所以当我执行所讨论的方法时,由“target”引用的对象不再是可变的,我的replaceOccurancesOfString语句崩溃了。
这并不回答为什么它在Xcode 4.1中执行所需的异常,但在Xcode 4.2中正确地崩溃。由于罗恩的建设性刺激,我找到了这个问题。 Thx给出。
很高兴你解决了你的问题!你也问过内存泄漏,可能你没有泄漏内存。它取决于如何定义属性“messageBody”,但是如果它是“保留”属性,那么当您分配给self.messageBody时,旧对象将“释放”,并且新对象将“保留”。至于为什么它会在XCode4.1而不是XCode4.2中崩溃,这可能是因为您在升级时更改了SDK。旧的SDK可能会返回一个真正是NSMutableString的NSString,所以你的代码运气好。在新的SDK中,它返回了导致崩溃的NSString。 – Ron
'isKindOfClass'将返回'YES',如果接收者是给定类或其任何类的实例,所以'[@“这是不可变的'isKindOfClass:[NSMutableString class]]'将返回'YES' 。 – wulong