我的程序完美工作。我向你保證,我的生活,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我們會發現一個函數,編譯器有足夠的禮貌讓這個函數能夠真正完成它的工作。不過,我認爲這是一個相當複雜的方式來做這麼簡單的事情。如果您正面臨着「觀察塊內價值變化」的任務,還有沒有其他方式可以編碼它,您將使用另一種模式?非常感謝!
哇,易揮發的關鍵字的作品!我記得曾經在C書上讀過它,從未想過我會用它!謝謝 – agro1986
哇......確實.. :) +1表示:) – TonyMkenu