2013-06-20 47 views
0

The problematic application, simplified调试和发布配置之间的不同块行为

我的程序完美工作。我向你保证,我的生活,0个错误。自豪地,我尝试使用TestFlight将应用程序打包为一个.ipa文件以便临时分发给我的beta测试人员。

程序没有工作。应该发生的动画从未发生过。网络代码中断。美妙地淡出音乐的按钮根本没有做任何事情。

事实证明,罪魁祸首是新的和闪亮的块。当我在模拟器或我的设备上测试我的程序时,我使用默认的“Debug”构建配置。但是,当我将它存档以供分发(并且我相信稍后将其提交给App Store)时,XCode使用另一种“发布”配置。进一步研究,不同之处在于优化级别(可以在XCode的Build Settings中找到它):调试使用无(-O0),但版本使用最快,最小(-Os)。我没有知道,它是最快,最小,并且不起作用(tm)。是的,这两个配置之间的块的行为不同。

所以,我着手解决这个问题。我已经简化了我的即将更改世界的应用程序,使其成为我的裸骨,显示在我附加到这篇文章的图像中。视图控制器有一个初始值为0的实例变量x。如果我们按b,它会产生一个线程,它将不断检查x的值,当x变为1时,更改底部标签。我们可以使用按钮更改x的值一个。

这里是我的天真代码(我使用ARC BTW):

@implementation MBIViewController 
{ 
    int _x; 
} 

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 
    // Do any additional setup after loading the view, typically from a nib. 
    _x = 0; 
} 

- (void)updateLabel 
{ 
    self.topLabel.text = [NSString stringWithFormat:@"x: %d", _x]; 
} 

- (IBAction)buttonAPressed:(id)sender { 
    _x = 1; 
    [self updateLabel]; 
} 

- (IBAction)buttonBPressed:(id)sender { 
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
     while (_x != 1) { 
      // keep observing for value change 
     } 
     dispatch_async(dispatch_get_main_queue(), ^{ 
      self.bottomLabel.text = @"b changed me becase x changed!"; 
     }); 
    }); 
} 

@end 

_x是一个实例变量,因此可以合理地认为该块将使用指针,以“自我”访问,不在本地副本上。它适用于调试配置!

但它不适用于发布版本。所以也许该块是使用本地副本毕竟?好吧,让我们明确地使用自我:

while (self->_x != 1) { 
    // keep observing for value change 
} 

无法在发布。好吧,让我们直接使用指针访问该死的变量:

int *pointerToX = &_x; 
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
    while (*pointerToX != 1) { 
     // keep observing for value change 
    } 
    // other codes 
}); 

仍然无法正常工作。这是当我想到智能优化编译器假定在这个多线程世界中没有任何可能的方式时,比较的结果会发生变化,所以也许它会将其替换为总是TRUE或其他伏都教。

现在,当我用这个,事情开始工作:所以

while (_x != 1) { 
    // keep observing for value change 
    NSLog(@"%d", _x); 
} 

,绕过编译器优化执行的比较,我使出做一个getter:

- (int)x 
{ 
    return _x; 
} 

然后检查使用该吸气剂的值:

while (self.x != 1) { 
    // keep observing for value change 
} 

它现在可以工作,因为self.x实际上是一个ca我们会发现一个函数,编译器有足够的礼貌让这个函数能够真正完成它的工作。不过,我认为这是一个相当复杂的方式来做这么简单的事情。如果您正面临着“观察块内价值变化”的任务,还有没有其他方式可以编码它,您将使用另一种模式?非常感谢!

回答

1

如果您使用变量并且不在循环中对其进行修改,那么编译器优化会导致对变量的实际访问进行优化,因为您的语句可以在编译时事先进行计算。

为了防止出现这种情况,您可以使用“volatile”关键字,它可以防止编译器应用此类优化。

它可以与getter和setters一起工作,因为那样你需要发送一条消息给你的实例,它充当了一个同步点。

+0

哇,易挥发的关键​​字的作品!我记得曾经在C书上读过它,从未想过我会用它!谢谢 – agro1986

+0

哇......确实.. :) +1表示:) – TonyMkenu

-1

尝试声明_x如下:

,其也以块使用
__block int _x; 

通常变量被复制。这将向编译器指出,如果_x在块中被修改,则更改应该在其外部可见。它可能会解决您的问题。

+0

'__block'只适用于局部变量 – newacct

相关问题