以前找到過一個FlashPlayer在執行NetStream.play的時候崩潰的BUG,沒想到今天又讓我碰到一個AIR的BUG。
和上個BUG不同,這個BUG再現起來相當容易,但我還是找了1天才找到再現的方式。
問題再現
?View
Code ACTIONSCRIPT
12345678910111213141516171819202122232425262728293031323334353637383940414243 |
package{import flash.display.Sprite;import flash.filesystem.File;import flash.text.TextField; /** * 測試在iOS分發包中的unit與int不能比較的問題 */public class IOSUintTest extends Sprite{ public function IOSUintTest() { super(); init(); showInfo(-1 <= ZERO_INT); showInfo(-1 <= ZERO_UINT); showInfo(_num <= ZERO_INT); showInfo(_num <= ZERO_UINT); } private var _tf:TextField; private var _num:int = -1; public static const ZERO_INT:int = 0; public static const ZERO_UINT:uint = 0; private function init():void { _tf = new TextField(); _tf.width = 400; _tf.height = 400; this.addChild(_tf); } private function showInfo($info:*):void { _tf.appendText(String($info) + File.lineEnding); }}} |
地球人都知道,showInfo中的4個比較運算式的值應該都為true。恩,是的,在調試版ipa(target ipa-debug)中,它們的值都是true。
但是,在用於發布的ipa中,它們的值並非都是true!我這裡所說的“用於發布的ipa”,如果用Adobe的話來說,就是“限制分發的臨時包”和“部署到Apple App Store的最終發行包”。
將這種包安裝到iOS裝置上,得到的4個值分別是 true,false,true,false
問題分析問題出在int與uint的比較上。因為AIR打包成ipa,實際上是直接將AIR程式打包成2進位代碼,而不是採取虛擬機器的形式(APK是採取的這種形式)。因此,使用AIR製作的ipa,理論上與使用Objective-C寫的ipa沒有什麼不同。這也是為什麼AIR寫的ipa能堂而皇之的登上App Store的原因。否則,以蘋果那個獨裁政策,不卡死Adobe才怪!
既然是Objective-C代碼,那麼Objective-C的類型轉換規則也同樣適用與這個比較運算式。在Objective-C中,將int -1與uint 0互相比較的時候,會先將-1轉換成uint,得到4294967294,(4294967294 <= 0) 的值應為false。
Objective-C是基於C語言的。在C語言中,這種情況叫做整型提升(integral promotion)。
以下摘自《The C Programming Language》
A character, a short integer, or an integer bit-field, all either signed or not, or an object of enumeration type, may be used in an expression wherever an integer maybe used. If an int can represent all the values of the original type, then the value is converted
to int; otherwise the value is converted to unsigned int. This process is called integral promotion.
在ActionScript中,int與uint比較的時候,是不會進行整型提升的。int和uint都是基於Number,在AVM中,或許本來就是一回事。
從這個觀點上說,這並不是BUG,而是不同語言的特性所致。但是,Adobe既然在大力推廣AIR開發iOS應用,就要考慮到不同語言之間的差別,避免出現這種容易被忽視的錯誤。
這個BUG說起來簡單,但是在一個已經存在的大型項目中發現這樣的小錯誤,還是非常困難的,我就找了整整1天!
困難的關鍵點在於,快速發布的允許調試的ipa檔案(target ipa-debug)中,並不會出現整型提升的問題。這就導致調試的時候正常的程式,在發布的時候不正常。這絕對是Adobe的工作失誤。
為了找到問題,我不得不自己寫一個調試資訊面板顯示在項目中,並不斷地打包來測試專案中不同位置的運算式的值。每次打包要花費20分鐘!這真讓人發瘋。