What’s New in Xcode 5

Asset catalogs (圖片結構)

  1. 在XCode5,因為要支援在不同設備使用不同解析度的圖片,我們可能有很多種不同版本且不同檔名的圖片。這時便可以使用Xcode5的新功能Asset catalogs,它會提供一個介面,讓我們可以將一組圖片設定為一個群組,以及要使用的裝置對象。
    如下圖
    2013-11-22_173500
    然後在程式裡使用

    來使用圖檔。
  2. 這個功能最大的好處就是,圖片不再需要強制要用名稱來代表針對的裝置,如@2x, ~iphone,~ipad或-568h,而可以由使用者來定義那些圖是針對那種裝置的。
  3. 假使將發佈目標設定為IOS7,Xcode會將asset catalogs編成二進位檔案,這將可以讓APP的下載時間縮短。

Image slicing

  1. 現在XCode新增對圖片的”九宮格縮放”設定,這是為了讓同一張圖片可以針對不同的裝置、不同解析度的狀況下做縮放,而不致讓圖片變型。
    2013-11-22_174607
    下圖是選擇Stretches和Tiles的差異,可以看出,是中間的圖片的拉長方式有所差異。
    2013-11-22_175913
  2. 這個功能可以使圖片可以輕易縮放至任意大小,只需設定center mode以及把素材使用至專案裡就好。

Auto Layout improvements

  1. 在iOS7的autoLayout有很大的改變,幾乎所有的設定都可以在storybaord上面來做。差異點大置有:
    1. Interface Builder不再會在移動物件後,自動改變constraints,但可以選擇是使用原本設定或是接受新的條件
    2. 可以輕易的設定兩個UIView之間的constraints(按control+拖曳)
    3. There are new controls to solve common Auto Layout problems, such as the Pin
      and Resolve Auto layout Issues buttons in interface builder, which let you
      clear constraints, reset to the suggested constraints in Interface Builder, add
      missing constraints, updates constraints, update frames, and more
    4. 有更直觀的設定constraints介面
      2013-11-22_181904

Preview window

XCode5可以預覽APP在ios6及ios7的顯示差異,首先點Assistant Editor(右上方)
2013-11-22_182338
然後點下圖紅圈處
2013-11-22_182353

再點右下的控制項來選擇要預覽的版本
2013-11-22_182138

Language improvements

  1. @import允許只單一import一個類別,如:
  2. instancetype:和id相同功能,但只能用在傳回的參數上。它代表著是自己的類別或自己的子類別,當若是在alloc init時,沒有傳回自己類別或自己的子函數類別時,編譯器會提示錯誤。如:

    此時若NSString * car = [Car car];
    會出現Incompatiable pointer types initializing 'NSString *' with an expression of type 'Car *'的警告訊息

Documentation improvements

  1. 右邊頁籤有quick help(點option+alt也可以跳窗方試顯示help)
    螢幕快照 2013-11-21 下午5.56.33
  2. 可在自定函數上面使用//增加註解,或用/*! — */增加更詳細的註解,如:

Debugging improvements

  1. Data Tips: 下中斷點時,游標移到變數上,可以看到此時變數的值。
    Debugging1
  2. Quick Look:讓變數的內容以圖形化的方式呈現,例如
    2013-11-22_1839162013-11-22_183930
  3. 在Debug介面裡新増了CPU和memory的使用量。也可以自己增加要監控的屬性,如用電量、iCloud 活躍度、OpenGL使用的frame rates。
  4. 點選Product > Perform Action > Analyze file name可分析單一檔案的效能

Source control improvements

Performance improvements

AIR記憶體監控工具 – Scout

記憶體監控相關工具

Scout是一款針對用以監控記憶體狀態的程式,它不但可以監控電腦上面的swf的記憶體狀況,也可以監看使用air開發,運行在手機上的app的記憶體和gpu使用狀況。
在Scout之前,了解swf的記憶體使用狀況有幾個方式

  1. 內建的Profile功能
    2013-10-11_161104
    Profile可以監控現有的FLASH裡每一個CLASS占的記憶體比例,預設的設定會忽略AS內建的類別。如果要打開的話,可以選擇選單列裡的Window=>Preferences=>Flash Builder=>Profiler=>Exclusion Filter或是Inclusion Filters去排除或增加要觀察的class種類。
    這個工具若是用按2013-10-11_171747的方式執行,則只能針對FLEX本身的專案來做觀察。如果專案架構是外部的SWF檔案,則可以先切換到Profile工作模式(如圖:2013-10-11_171854),然後選擇上方選單列的Profile=>Profile External Application=>New,去選擇要觀察的SWF檔案。
    有關這個工具的介紹請見: Flex記憶體監控程式-Profile
  2. windows的工作管理員
    監控執行緒的執行狀況,缺點是無法仔細的了解是那一個Class造成memory leak。
  3. Hi-ReS-Stats  (https://github.com/mrdoob/Hi-ReS-Stats)
    很常被見到的一個外掛程式碼,可以簡單的使用

    來觀察FPS的運行速度、記憶體的使用狀況是否正常。嵌入後會在畫面上多出如下圖這樣的資訊欄位
    hires_stats
  4. Scout  (http://gaming.adobe.com/technologies/scout/)
    最後就是今天要介紹的Adobe Scout工具,Adobe開發這個,主要是為了當開發者在使用Adobe AIR開發手機APP時,能夠更精準的掌握SWF運行的狀況以及GPU的狀況。因此Adobe官方便提供了這一項免費工具,讓APP開發者可以更仔細的監控效能的狀況。

Scout的優點

上面介紹了這麼多的工具,那麼Scout的優勢為何呢?

  1. 仔細(Details)
    Scout可以提供詳細、階層性的資訊,讓開發者一目了然自己的程式的GPU資訊及記憶體使用狀況。
    除了Profile的記憶體監控功能外,Scout還可以提供GPU運算的相關數字及報表。
    在上面所列的其他三項工具,只有Hi-ReS-Stats有顯示FPS,可以讓開發者了解FPS速度是否正常,可觀察何時影格速度會變慢,並檢查是否有什麼動畫讓畫面停住了。其餘的都只能單純的監控程式使用的記憶體狀況,而無法了解到動畫處理的記憶體使用狀況。
    在flash裡,動畫的運算、圖形處理等,在很多時候其實是造成畫面Lag的主要元兇,因此,或許很多時後我們會發現動畫不知為何播放速度變慢了,但是觀察Profile,記憶體的使用狀況卻很正常,這時很可能便是GPU Memory不足。
    有關要如何做才能提高動畫的效能,相關議題可以參考下面這篇文章:
    http://claire-chang.com/1063-提升Flash效能的幾個注意事項
  2. 可擴展性(Extensible)
    Adobe有提供相關的API,當原本Scout提供的資訊無法滿足需求時,開發者可以在ActionScript裡面寫程式,去自行丟出想觀察的額外資訊,並且只要幾行程式碼就可以做到。(請參見Telemetry類別)
  3. 跨平台(Cross-platform)
    可在Mac及Windows上運行,並能讓開發者開發Andriod及iOS APP時更容易觀察其效能狀況。
  4. 輕量化(Lightweight)
    Scout只有12MB,很輕並且運行的很快,並且可以運行於一般的Flash Player,不用使用Debug版本也可以。

 開始使用Scout

  1.  開啟SWFs的telemetry功能:將Enable detailed telemetry選項勾起來
    2013-10-11_181303
    PS: 此時大家可能會發現,咦~不對呀!我的Flex專案怎麼沒這個選項?
    是的,這個功能只有在AIR專案上才會有,非AIR專案是沒有這個選項的。
    所以,那一般Flash檔案要如何使用Scout呢?
    這時後就需要透過工具去開啟swf的Telemetry功能,詳細方法請見下面的文章:
    Enable Advanced Telemetry on Flex or old SWFs with SWF Scout Enabler
    簡單來說,便是下載SWF Scout Enabler,然後選取要觀察的SWF檔案,把它的Telemetry打開。
  2. 執行Scout,要觀察一個swf,可觀察遠端或在本機的檔案。是用Scout去監控運作在其他台電腦或是手機上的APP上的資訊會需要較多的設定。
    要執行Scout的電腦需要有

    • Flash Player 11.4 (plugin or standalone) or Adobe AIR 3.4.
    • The Adobe Scout desktop application.

    [觀察目標]
    (一) 本機檔案
    只要將Scout打開,就可以看到現在在電腦中正在運行的SWF檔案的相關資訊了。
    (二) 其他台電腦上檔案
    如果要去觀察在其他台電腦上運作的SWF檔案的效能狀況,可以經由.telemetry.cfg檔案的設定去做到(但需要同網域)。
    檔案位置如下:

    • MacOS: ~/.telemetry.cfg
    • Windows: %HOMEDRIVE%%HOMEPATH%\.telemetry.cfg

    在修改之後,.telemetry.cfg可能會長的像這樣

    (三) 手機或移動裝置上的APP

    1. 確定手機與執行Scout的電腦在弄一個WIFI網路下
    2. 手機下載Adobe Scout檔案(iPhone在此下載Android在此下載)
    3. 打開手機上的Scout應用程式,這時他會搜尋同WIFI下的電腦,選擇我們執行Scout的電腦,然後按連線
    4. 到電腦裡選擇自己想看到的數據資料
    5. 運行有開啟Telemetry的手機APP應用程式
      adobe-scout-getting-started-fig04

    先介紹到這邊,下一篇會再介紹該如何去使用或設定Scout的相關功能。

參考資料:

  1. Getting started with Adobe Scout
  2. Enable Advanced Telemetry on Flex or old SWFs with SWF Scout Enabler
  3. Telemetry – AS3
  4. Adobe Scout

Flex記憶體監控程式-Profile

Flash Builder裡面大家最廣泛用來監控記憶體使用狀況的工具應該就是Profile了
Profile位於執行鈕的右邊,如下圖:
2013-08-27_160230

這邊提供幾個可能你按下Profile結果卻無法正常執行的一些討論串
Flex Builder – Profiler – Can’t run profiler

這個討論串有給一些嘗試的除錯方法

  1. 更改port號碼
  2. 是否SWF本身有錯誤?PreloadSwf 應位於本地端
  3. 換一個瀏覽器! (Preferences/General/Web Browser)也許 Firefox無法支援(我有遇過開不了的問題,我自己是換一個瀏覽器就解決了PS: 原本是firefox換成IE)
  4. 指定的瀏覽器是否有安裝debug版本Player?
  5. 設定mm.cfg檔案的值 (請看這邊 http://jpauclair.net/2010/02/10/mmcfg-treasure/)

設定開啟瀏覽器的地方在Window>Preference>General>Web Brower
2013-08-27_161918

Profile的設定則在這邊(兩個enable的選項要記得勾選),port之類的更改也在此區更改
2013-08-27_162200

接下來,請選擇工作區

2013-08-27_162621

切到Profile模式之後,如果我們想觀看外部SWF的記憶體使用狀況,
可以按Profile>Profile External Application,一樣可以進入觀查模式
2013-08-27_162737

2013-08-27_163808

在執行Profile時,左上的欄位可選擇要觀察的物件,
在profile視窗裡,可以設定中斷點,然後用右上的去控制繼續執行、暫停等等
2013-08-27_164013

在Memory Usage可以顯示現在所耗的記憶體的狀況
2013-08-27_163936

Live Objects裡觀察現在在記憶體內的物件以及它的值
2013-08-27_163948

如果還想開其他的頁籤,也可以由Window=>Show View>Other>Flash Prifile去叫出其他觀察視窗。
2013-08-27_164904

AS3的事件傳遞機制(Event、dispatchEvent及addEventListener)

當事件被發送出來之後。Event一般來説都會有一個Flow。 Flow分三個部分:

  1. Capture(捕獲階段)
  2. Targeting(目標階段)
  3. Bubbling(冒泡階段)

其關係圖如下:(來源為http://www.adobe.com/devnet/actionscript/articles/event_handling_as3.html)

efAzj

值得一提的是,在FLASH裡,只有和UI相關的物件,會有上圖所示的目標及補獲階段的事件流

一般像是Timer、Loader事件,是直接進入目標階段,並不會有上圖所示的事件流的流程。
在宣告Event時,也可以先指定事件是否要完整的跑完全部的流程。

宣告事件的語法及及參數意義如下:

參數說明(官方文件)

  1. type:String是要發送的事件的識別名稱EX:Event.COMPLETE
  2. bubbles:Boolean預設值是false,這個值是用來設定是否要有冒泡階段,如果傳false,代表他不會跑完全部的流程,只會從Capture到target階段就停止
  3. cancelable:Boolean預設值是false,這個值是用來設定是否這個事件可以被event.preventDefault();取消,如果設定為true的話,代表此事件是可以被取消的(稍候在dispatchEvent會更詳述這部份)。
    常用的可以取消的事件有(cancelable為true):   FocusEvent.MOUSE_FOCUS_CHANGEFocusEvent.KEY_FOCUS_CHANGETextEvent.TEXT_INPUT

而發送事件則是用這一段程式碼:

在發送事件時,要注意,假使今天我們是在STAGE裡面有一個box物件,那當我們用box.dispatchEvent(event);
即使事件是用box發送的,事件還是會從stage > root > box這樣跑。(請見上圖)
假如在建立Event時,bubbles設為true,那在上圖跑的流程為stage > root > box > root > stage
而若bubbles設為false,跑的流程則是stage > root > box

當我們用root.dispatchEvent(event);
bubbles設為true,上圖跑的流程為stage > root > stage
bubbles設為false,流程為stage > root

由此可知,事件流只會到目標(Target),就會停止往下傳
假如今天box裡面有一個物件button,若是用box.dispatchEvent(event)
button物件是不會接到事件流的。(因為到目標階段便會開始bubbles或停止)
並且假如今天root裡同時有box和box2兩個物件,
假使我們用box.dispatchEvent(event),則box2也不會接到事件。

至於第三個在建立Event的參數cancelable,不論值是true或false,都不會影響事件流的流程。
那他的作用是做什麼的呢?

我們可以發現,dispatchEvent有回傳一個布林值,cancelable就是在影響這個布林值的傳回參數。
今天我們假如要創建一個物件,但是要讓使用者有權力去阻止這個事件發生後的後續發展時,可以這樣寫

假使使用者在監聽的途中呼叫 event.preventDefault();,並且EVENT的cancelable為true時,dispatchEvent回傳的值就會是false,便不會執行trace("success!");那塊區塊。但假使EVENT的cancelable為false時,不論你在事件執行中有沒有呼叫event.preventDefault(),dispatchEvent回傳的值就會是true

一般我們會在傳遞事件的途中,去將事件攔截下來。增加監聽事件的程式碼如下

官網關於addEventListener的說明如下

addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void

傳入的參數意義如下:

  1. type(String):事件名稱
  2. listener(Function):要執行的Function
  3. useCapture(Boolean):這個和本篇要說的事件流有關,當今天傳入的值為true,則只能在補獲階段去抓取事件,在冒泡階段是聽不到的。如果將 useCapture 設置為 true,則偵聽器只在捕獲階段處理事件,而不在目標或冒泡階段處理事件。
    如果 useCapture 為 false,則偵聽器只在目標冒泡階段處理事件
    要在所有三個階段都偵聽事件,需註冊 addEventListener 兩次:一次將 useCapture 設置為 true,一次將 useCapture 設置為 false。當今天若useCapture為true時,並不會聽到target階段時的事件但若為false時,也可以聽到target階段時的事件

    假使今天我們用box.dispatchEvent(event);來發送事件,
    然後box的監聽事件的useCapture設為true。ex : box.addEventListener(MouseEvent.CLICK, rootClick, true);
    這樣rootClick事件並不會被呼叫到。

    若box的監聽事件的useCapture設為false 。ex : box.addEventListener(MouseEvent.CLICK, rootClick, false);
    這樣rootClick事件便被呼叫到。

  4. priority(int):若今天同時有很多個監聽器同時監聽同一事件,可用這個值來設定那一個監聽器應該被優先執行。數字愈高代表會愈快執行該事件偵聽程式。
  5. useWeakReference(Boolean):是否使用弱關連。若是用弱關連,當被監聽的物件所指到的變數被指向記憶體的其他地方,這個關係也會一併被取消(物件會被GC回收)。但如果傳進的值是false,當今天被監聽的物件的其他關連被指向別處時,該物件不會被GC回收,需要手動removeEventListener時,該物件才會被GC回收。

除了上述的幾個參數外,還有幾個函數可以中斷事件流的流程。
那就是stopPropagation()stopImmediatePropagation()

那這兩個函數有什麼差別呢?

下圖可以很清楚的解釋差異:
stopPropagation():會把同一階層的其他事件跑完才停止。
5MYe3

stopImmediatePropagation():立刻停止之後所有的事件流。
jleAX

假如今天box同時有兩個監聽函數如下

則由於priority值的關係,eventMouseDownHandler2會先被執行,eventMouseDownHandler1在之後才被呼叫
那若是在eventMouseDownHandler2裡面呼叫event.stopPropagation(),eventMouseDownHandler1還是會被執行,才將事件流中斷。
但是若在eventMouseDownHandler2裡面呼叫event.stopImmediatePropagation(),則eventMouseDownHandler1就不會被呼叫到

相關資源

  1. AS3.0的事件機制(詳細)
  2. AS3筆記-事件流(event flow)
  3. Event propagation
  4. Introduction to event handling in ActionScript 3.0

Flex裡綁定(Bindable)相關函數及使用方式

在flex裡,最強大的標籤應該就是[Bindable]的綁定標籤了
因為某次的需求,我需要研究將Bindable綁定至函數
也順便研究了ChangeWatcher和BindingUtils的使用

【BindingUtils】
官方的說明在此:
http://help.adobe.com/zh_TW/FlashPlatform/reference/actionscript/3/mx/binding/utils/BindingUtils.html
這是Flex內綁定的工具,裡面有兩個屬性,一個是綁定到函數(bindSetter),另一個則是綁定到某物件的某屬性(bindProperty)

使用範例如下
1. 綁定到函數(bindSetter)

2. 綁定到某物件的某屬性(bindProperty)

【ChangeWatcher】
官方的說明在此:
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/binding/utils/ChangeWatcher.html
因為此次我們要綁定的函數裡是有帶多個參數的,因此BindingUtils的bindSetter便無法使用
這時就需要使用BindingUtils所用的ChangeWatcher來自己做綁定的動作
ChangeWatcher的使用方式如下

根據官方文件watch的傳入的東西依序為”要綁定的物件”、”要綁定的屬性”、”要綁定的函數”

下面便是我根據這些所寫的小範例
MyBindingUtils.as

完整範例檔案可按此下載