考虑这个代码:
static NSString *staticString = nil; int main (int argc,const char * argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; if (staticString == nil) { staticString = [[NSArray arrayWithObjects:@"1",@"2",@"3",nil] componentsJoinedByString:@","]; } [pool drain]; NSLog(@"static: %@",staticString); return 0; }
我期待这个代码崩溃.相反,它记录:
2011-01-18 14:41:06.311 EmptyFoundation[61419:a0f] static: static:
但是,如果我将NSLog()更改为:
NSLog(@"static: %s",[staticString UTF8String]);
然后它崩溃了.
编辑更多信息:
排水池后:
NSLog(@"static: %@",staticString); //this logs "static: static: " NSLog(@"static: %@",[staticString description]); //this crashes
所以显然在字符串上调用一个方法是足够好让它崩溃的.在这种情况下,为什么不记录字符串直接导致它崩溃? NSLog()是否应该调用-description方法?
第二个“静态”来自哪里?为什么这不会崩溃?
结果:
Kevin Ballard和Graham Lee都是正确的. Graham在意识到NSLog()并没有调用-description(正如我错误地假设)时是正确的,Kevin几乎绝对是正确的,这是一个复制格式字符串和va_list的一个奇怪的堆栈相关的问题.
> NSLogging和NSString不调用-description.格雷厄姆优雅地展现了这一点,如果你跟踪核心基金会的采伐记录,你会发现是这种情况. NSLog内部的任何回溯显示它调用NSLogv => _CFLogvEx => _CFStringCreateWithFormatandArgumentsAux => _CFStringAppendFormatandArgumentsAux. _CFStringAppendFormatAndArgumentsAux()
(第5365行)是所有魔法的地方.您可以看到手动通过以查找所有的%替换.如果替换的类型是CFFormatObjectType,描述函数不为零,并且替换尚未被另一个类型处理,则最终只会调用描述复制函数.由于我们已经表明该描述没有被复制,所以可以合理地假定NSString处理得更早(在这种情况下,它可能要做一个原始的字节副本),这导致我们相信…
>凯文推测,这里有一个堆栈错误.指向自动释放的字符串的指针被替换成一个不同的对象,这恰好是一个NSString.所以,它不会崩溃.奇怪的.但是,如果我们将静态变量的类型更改为其他类型,就像NSArray一样,则会调用-description方法,并且程序会按预期方式崩溃.
如何真正和完全陌生要点凯文是对行为根本原因的最正确的,并且对格雷厄姆的态度来纠正我的谬论.我希望能接受两个答案…