我开始调试一些试图找出错误的代码。当我从调试器尝试p tlEntries
时,我得到了
<variable optimized away by compiler>
if
语句中停止时显示消息。以下是我的代码:
NSArray *tlEntries = [[NSArray alloc] initWithArray:[self fetchJSONValueForURL:url]];
for (NSDictionary *info in tlEntries)
{
if ([info objectForKey:@"screen_name"] != nil)
NSLog(@"Found %@ in the timeline", [info objectForKey:@"screen_name"]);
}
早期的调试让我确信网址确实返回了有效的NSArray
,但我不明白为什么tlEntries
被“优化掉”。
答案 0 :(得分:17)
正确的解决方案是以不同的方式声明变量,如下所示:
volatile NSArray *tlEntries;
实际上,volatile关键字正好用于告知编译器它不能尝试以任何方式优化与该变量相关的代码。 亲切的问候。
答案 1 :(得分:6)
编译器可能注意到你只在开头使用了两次tlEntries,并且在循环中根本不使用它。如果我没记错的话,循环会创建一个枚举对象,而不是保持对容器对象的引用。所以tlEntries应该对第一行有效,但其余部分则有效。
想法:您可以强制编译器通过在函数后面的某处使用tlEntries来保留它。像
这样的东西NSPrint(@"IGNORE THIS LINE %p", tlEntries);
更好的想法:您可以将优化设置为-O0。强烈建议您调试代码。如果使用“Debug”而不是“Release”构建,它应自动设置为-O0,但您可以更改它。
答案 2 :(得分:3)
当启用编译器优化时,通常将变量置于寄存器或其他技巧(如语句重新排序)中来“优化”变量。如果您使用-O
之外的任何-O0
标记,则可以进行此操作。
我认为在代码中添加对变量的额外引用不会阻止这种情况发生。 (如果有的话,编译器可能会更加努力,因为优化它的潜在收益更大。)
作为临时解决方法,您可以声明变量“volatile”。这通常不是一个好的长期解决方案,因为它会阻止编译器执行涉及该变量的任何优化。
另一种解决方法是使用良好的老式日志记录。类似的东西:
NSLog(@"Entries initialized as: %@", tlEntries);
最后,您还可以使用-O0
进行编译。许多人建议将此用于 Debug 项目配置文件。虽然它阻止了优化,但它使调试变得更容易。单步执行语句实际上是可预测的,可以查看变量。不幸的是,我认为它与Apple发布的gcc版本相比具有相当令人讨厌的副作用:当-O0
生效时,您无法获得有关在初始化之前使用变量的警告。 (我个人觉得这个警告很有用,我很愿意忍受调试不太方便的痛苦。)
P.S。发布的代码段中有内存泄漏;为清楚起见,应增加一行:
[tlEntries release];
答案 3 :(得分:1)
假设您以后从未使用此变量(如果编译器对其进行了优化,这似乎是合理的),您可以用来解决问题的一个非常重要的方法(类似于Dietrich的示例,虽然对您的程序更好)是一个:
[tlEntries release];
否则,你肯定会泄漏那些记忆。这将使编译器看到稍后使用的对象(与NSPrint一样),因此不会对其进行优化。