2

非常简单的代码,我可以说它在 Xcode 4.1 中按预期工作,但在 Xcode 4.2 中中断。这是有问题的代码:

-(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: 是

2011-11-03 15:42:59.968 TestProg[30413:c503] aCode isKindOf NSMutableString: 是

2011-11-03 15:42:59.969 TestProg[30413:c503] arg isKindOf NSMutableString: 是

当我执行 [target replaceOcurances... 代码行时,我崩溃了-

节目接收信号:“SIGABRT”。

在控制台日志中使用以下内容 -

2011-11-03 15:43:26.828 TestProg[30413:c503] *由于未捕获的异常“NSInvalidArgumentException”而终止应用程序,原因:“尝试使用 replaceOccurrencesOfString:withString:options:range: 来改变不可变对象”

我的问题是,我在哪里尝试改变不可变对象?其次,为什么这在 Xcode 4.1 中执行得很好?当然,所有玩家在 Xcode 4.1 中看起来都是可变的。Xcode 4.2 有什么区别?我在这里遗漏了一些微妙的东西。

4

3 回答 3

3

我怀疑某些字符串并不是真正可变的字符串(可能是“目标”,因为这是您要修改的字符串)。这也让我困惑了一段时间,但是“isKindOf:”并没有区分可变字符串和非可变字符串。我相信即使字符串不可变,您的 NSLog 查询也会返回 YES。

如果您在调试器中停止,您应该能够检查对象并确定它们是否真的是可变的(“真实的”类名应该与对象一起显示)。

至于为什么这在 4.1 而不是 4.2 中起作用,很难说。可能是某些返回 NSString 的系统例程用于返回 NSMutableString 但不再返回。

如果我是正确的,您将需要向上堆栈以找出目标的来源。在某些时候,它可能已经从 NSString 转换为 NSMutableString。

于 2011-11-03T23:30:19.533 回答
0

检查 Apple 文档中的isKindOfClass:

它基本上说不要对类集群使用这种检查并继续说

如果您调用返回类簇的方法,则该方法返回的确切类型是您可以使用该对象做什么的最佳指标。

他们完全有可能在 SDK 之间更改了此实例中类集群返回的类型。

于 2011-11-03T23:30:02.937 回答
0

在“target”中传递的变量被定义并在每个地方都用作 NSMutableString。在讨论的方法之前调用的方法中的一个位置,变量是从文件的内容中加载的,并且在该方法中,由于缺乏经验,我使用了以下语句:

self.messageBody = fileContents;

fileContents 是一个 NSString。哎呀。

这显然为 messageBody 创建了一个具有不同内存地址的新内存位置,并且不是可变的。问题-这是否使它实际上成为一个新对象?如果是这样,我猜它也会造成内存泄漏,因为第一个实例无法再被释放。

所以当我执行讨论的方法时,“target”引用的对象不再是可变的,我的 replaceOccurancesOfString 语句崩溃了。

这并不能回答为什么它在 Xcode 4.1 中按预期执行,但在 Xcode 4.2 中正确崩溃的异常情况。由于罗恩的建设性推动,我想到了这一点。谢谢。

于 2011-11-04T06:19:55.943 回答