Enable the built-in FTP server in OSX 10.7

OSX 10.7 “Lion” 取消了內建的 FTP 伺服器功能 1,但其實只是從 GUI 拿掉,目前仍然可以透過 Terminal 啟用:

要停用 FTP 伺服器則是用:


  1. 如果不是非得用 FTP 的話,其實應該考慮改用 SCP 會比較安全,方法是在系統偏好設定→共享中,啟用「遠端登入」。 

iOS Programming Tips (5)

Protocol/Delegate

Protocol 是 Delegate 的介面,定義了 Delegate 必須實作什麼,用其他語言的概念來說明,Delegate 就像是 Callback。Delegate 不一定需要 Protocol,不過最好是要有,程式看起來會比較清楚。

Block

Block 是 iOS 4 以後加入的 Syntax Sugar,它其實就是 anonymous function,我覺得這應該可以用來取代比較沒有復用性的 Delegate,有的時候採用 Block 的寫法能讓程式更清楚易懂,例如 UIView 的 beginAnimation vs. animateWithDuration 兩種寫法我就覺得 Block 方便太多了。

Block 的缺點是有時候不能下中斷點,例如 iPhone Simulator + GDB 的情況,Debug 起來比較不方便,不過我猜也有可能是我沒設定好之類的。

Notification Center

Notification Center 就是 Event/Listener,iOS 中共有四種 Notification Center,分別是 NSNotificationCenter、NSDistributedNotificationCenter、DarwinNotificationCenter 及 TelephonyNotificationCenter。這很適合用來處理全域事件、降低物件耦合性,例如在自定類別中呼叫 UIViewController 更新畫面。

Base SDK? iOS Deployment Target?

Base SDK 是你的 App 可以支援的最新 SDK 版本,而 iOS Deployment Target 是你的 App 可以支援的最老 SDK 版本,所以 Base SDK 最好設定為 Latest SDK。

[UIDevice uniqueIdentifier] is not UUID

它不是 UUID,雖然在 Simulator 中它是,但是在 Device 中則是 UDID,也就是你在 Xcode Organizer 看到的 Identifier。

iOS Programming Tips (4)

Beautiful Formatting

Coding Style 有兩份文件可以參考,Apple 的 Coding Guidelines for Cocoa 以及 Google 的 Objective-C Style Guide

要自動整理程式碼,可使用 Uncrusitify。使用前必須先有一份設定檔,Tyler Neylon 提供了他的 Uncrustify 設定檔Tony Arnold 提供了給 Xcode 4 使用的 Automator Service,可以更方便地在 Xcode 中執行 Uncrustify。

Run You App on a Device

開發 iOS App,使用實機來測試是必須的。以下列出將 App 放到 iDevice 上的操作流程。

  1. 購買 $99 的 iOS Developer Program。
  2. 使用 Keychain 建立開發憑證授權要求
    1. 使用 Keychain 建立憑證授權要求。
    2. 點選選單中的「鑰匙圈存取」→「憑證輔助程式」→「從憑證授權要求憑證…」。
    3. 輸入你的電子郵件位址、名稱,然後圈選「儲存到硬碟」。
    4. 按下「繼續」將產生出的憑證授權要求檔案儲存起來,這個時候你的 Keychain 中會多出兩把名稱相同的金鑰,一個是公鑰、一個是密鑰,所以我想如果要在另一台 Mac 上使用,可能會需要轉移這兩把金鑰。
  3. 要求開發憑證授權
    1. 在 iOS Dev Center 找到 iOS Provisioning Portal,點選超連結進入。
    2. 點選左側主選單的 “Certificates”,在 Development 頁面上傳剛才製作好的憑證授權要求。
    3. 等你的憑證授權要求被 iOS Developer Program 的 Admin 或 Agent 核准以後,會在 Your Certificate 中多出一個 “Download” 的按鈕,將這個憑證下載回來後,直接滑鼠雙擊就能安裝。
    4. 在等待核准的時候,可以先下載 WWDR 憑證並安裝。
  4. 註冊你的 iDevice
    1. 連接你的 iDevice,然後開啟 Xcode 的 Organizer。
    2. 點選 “Use for development”。
    3. 在左側主選單中你的裝置上按右鍵,然後點選 “Add Device to Provisioning Portal”,用這個方法可以把註冊裝置以及安裝 Team Provisioning Profile 一次完成,當然這也可以分別手動在 Web 上操作,或者是我聽說在 Run Project 的時候 Xcode 也會自動問你要不要安裝 Provisioning Profile。
  5. 設定 Code Signing Identity
    1. 在 Project Settings 找到 Code Signing Identity。
    2. 可能會有一大堆,全部設定為 Automatic Profile Selector 中 iPhone Developer。

應該就這樣。

iOS Programming Tips (3)

Debugging Bad Memory Access Issues

當發生 EXC_BAD_ACCESS 時(程式試圖存取不應該存取的記憶體),通常 Debugger 會直接死掉,什麼訊息也沒有。啟用 NSZombie 能夠提供更詳細的 Callstack,迅速找到問題。啟用方法為:

  1. 點選 Group & Files 中的 Executables。
  2. 右上會出現現有的 Excutables,在上面按右鍵,選擇 Get Info。
  3. 切換到 Arguments 頁籤,在下方新增一個 Variable,名稱叫做 NSZombieEnabled,值為 YES

Auto-completion

Xcode 的自動完成功能很方便,但是只能列出一個近似的選項,是這樣嗎?其實按 Esc 就可以列出所有可能的選項。

How Reference Counting Works?

雖然 Objective-C 2.0 加入了 Garbage Collection 機制,但是 Mac 才有,iOS 沒有,iOS 只有 Reference Counting。

Reference Counting 的運作是基於 ownership。當程式要使用物件時,必須取得物件的 ownership,一個物件可以有很多 owner;而當程式不再使用物件時,則需要放棄 ownership。直到物件沒有任何 owner 時,物件就會自動被 dealloc。

取得物件的 ownership 的方法可分為兩種,其一是透過 alloc、new、copy 產生出物件。如果物件是從其他來源獲得,而不是由 alloc、new、copy 產生的話,則可以使用 retain 來取得物件的 ownership。要放棄物件的 ownership,則使用 release,雖然非 owner 也能呼叫這個 method,但這樣相當容易發生問題,請不要這樣作。

我們希望 owner 自己 release 自己的 ownership,但如果物件要作為函式回傳值的話,物件就必須要等到對方接收到物件並取得 ownership 之後才能 release,物件若在函式內就 release 掉,對方就可能收不到物件。為了解決這個問題,可以使用 autorelease1,讓函式只暫時地擁有物件的 ownership,在 event 結束以後的某個時點,物件會自動被 release。對方接收到物件後,必須用記得 retain 取得 ownership、或是用 copy 複製一份物件,以免未來物件 autorelease 後發現沒有 owner,就會被 dealloc。

另一個更好的解法則是不要使用 alloc、new、copy 產生物件,例如使用 NSString 的 stringWithFormat、NSArray 的 arrayWithObjects。以這種方式產生出的物件本身就已經是能夠 autorelease 的,好處是可以節省一些 code。

iOS Programming Tips (2)

What’s Nib Files?

Nib 檔 是由 Interface Builder 產生的文件,內容包含了介面的描述。過去 Nib 檔的副檔名就是 .nib,分為一個 XML 檔及一個二進位檔案,而 Interface Builder 3 以後預設改為使用一個 .xib 檔案的格式,實際上最後仍然會編譯成 .nib 檔。雖然副檔名變更了,不過 Xcode 介面中許多地方仍然採用「Nib 檔」這個名稱,對於剛接觸的開發者可能會造成誤解。

Memory Management with NSAutoreleasePool

Cocoa Framework 有個 NSAutoreleasePool 類別,使用方法很簡單,首先要 init 出一個 NSAutoreleasePool 物件,最後 release 這個物件,這時在 init 到 release 之間如果有可以 autorelease 的物件,他們就會自動被 release 掉,另外如果程式執行途中想要命令 NSAutoreleasePool 自動釋放目前不再使用的物件的話,則可以呼叫 drain。不過許多教學是說要 release 掉現有的 NSAutoreleasePool 然後馬上重新 init 一個,我不知道原因是什麼?

如果你使用 Xcode 提供的專案範本的話,它會在 main() 裡面使用這個類別,而由於 main() 是程式的進入點,所以這個 NSAutoreleasePool 會自動釋放掉程式中「幾乎」所有的物件佔用的資源——之所以說「幾乎」是因為如果物件是由 alloc、new、copy 產生出來或是有 retain 過這個物件,就不會自動被釋放 1,必須使用 release 或 autorelease 來釋放,慣例上 release 或 autorelease 必須由物件的 owner 來呼叫。

如果要手動釋放的話,則可以呼叫 release,但如果函式要回傳一個物件,這個物件就不可能由函式來 release,而需要在呼叫此函式的對方取得物件後才將它 release,以上是 C 的慣例。Objective-C 的慣例則是在函式回傳物件以前,先呼叫 autorelease 標示物件可以被 autorelease,然後再將物件傳遞出去,這樣對方就不需要管理記憶體。當下次 NSAutoreleasePool 執行 drain 或 release 時,已經不再使用的物件才會被銷燬。


  1. 這樣子好像幾乎都還是要自己釋放嘛… orz 

iOS Programming Tips (1)

其實以下這些 Mac Programming 應該也適用,都是很基本的東西,只是作個筆記。

Run Static Analyzer

Static Analyzer 可以用來抓出潛在的記憶體洩漏風險、多餘的變數等問題。Xcode 有內建一個 Static Analyzer,是基於 Clang Static Analyzer 修改來的。直接就能使用!或者也可以照著 Clang Static Analyzer 網站上建議的,手動安裝他們提供的最新版。

執行的方法為 Build / Build And Analyze。

Set Global Breakpoint on objc_exception_throw

意思就是說在丟出 Exception 的時候中斷程式,光用想像的就覺得超實用的啊!

新增的方法是到 Run / Show / Breakpoints,在 “Double-Click for Symbol” 上點兩下,然後填入 objc_exception_throw12

Treat Warnings as Errors

Warnings 表示沒有 Compile Error,但是卻有 Runtime Error 的風險,所以建議勾選這個選項。

這個選項的位置在 Project / Edit Project Settings,Build 頁籤當中。

Use LLVM Compiler if Possible

LLVM 編譯器在 Xcode 3.2 當中已內建,穩定程度已經足夠,並且預期能夠產生比 GCC 更小的可執行檔、更快的執行速度,不過實際效果仍然要以測試為準。LLVM GCC 是 GCC-compatible 的 LLVM,若無必要可以直接選用 LLVM compiler。Xcode 3.2 內建的 LLVM compiler 同樣比較舊,需要的話也可以自行編譯最新版 LLVM compiler 來使用。

這個選項的位置在 Project / Edit Project Settings,Build 頁籤當中,名稱叫做 “C/C++ Compiler Version”。

Use Instruments for Profiling

Instruments 是包含於 Xcode 之中的一個 App,它可以用來記錄、分析程式的運作,有助於最佳化程式效能。3

不要修改 Node.JS 的 require.paths

根據 Node.JS 的文件,Node.JS 載入模組的方法有兩種,一種是從相對路徑中載入,另一種則是從 require.paths 尋找。

如果想要在專案中維護一份模組,以利於隨時隨地 clone 下來就能開發,不用分別在不同機器上安裝模組,依照 Python 的慣例我們會直接修改 sys.path,但在 Node.JS 中並不建議修改 require.path,未來版本的 Node.JS 可能會拿掉 require.path,取而代之,可以採用這樣的方式:

其實 require('http') 這樣的 require 會首先嘗試搜尋目前路徑下的 node_modules 資料夾,例如以下的資料夾結構:

如果要在 app.js 中使用 express 模組,直接寫 require('express'),就會載入 node_modules/express/index.js。express 模組中使用了 require('connect'),由於 express 是 node_modules 下一層資料夾,所以它會自動搜尋它自己旁邊的資料夾。

其實我還試過這樣的架構……

這樣我就可以在 app.js 中寫 require('vendor/express'),而 express 中仍然可以繼續寫 require('connect'),但後來我覺得這樣的結構有點惡搞 XD

Node.JS 自動重新載入程式

目前 Node.JS 執行的方式不像常見的 Script 語言,如 PHP、Python、Ruby、Perl 那樣,修改程式後,只要重新整理瀏覽器就能看到結果,而是必須關閉 Node、重新執行。

開發中必須不斷重複重新啟動的動作實在是很苦,本來我是想用 watchr 來輔助,後來發現其實已經有人寫好了模組:node-supervisor

安裝

以下只記錄 Mac 的情況。

實際安裝的位置會因為執行指令當時的位置而有所不同,例如我在 /Users/bcse 安裝,最後會安裝到 /Users/bcse/node_module/supervisor

接下來為了可以直接執行 supervisor,不用執行 node path_to_supervisor,還要執行

這句指令要在安裝目錄中執行才行,例如 /Users/bcse/node_module/supervisor

使用方法

基本上都照預設值就好,不用多設定什麼參數。

在 Google App Engine 上解析 HTML

解析 XML/HTML 的 Library 有很多,但大部份都只支援 Well-formed XML,遇到 Mal-formed XML 就無法解析,Standard Library 裡面的都屬於此類。可以接受 Mal-formed XML 的 Library 則有以下這些:

lxml
據說是目前 Python 最好的 XML Parser,但不是純 Python 寫的,不能在 Google App Engine 上使用1有人開 ticket 請 Google 裝,不過優先度並不高。
html5lib
HTML5 標準函式庫,在查詢元素方面除了介接 Beautiful Soup、ElementTree、lxml 等既有 Library 以外,還額外提供了一個新的 simpletree 格式,其目標是提供一個最基本的實作,並沒有擴充的打算,查詢起來費時又費力。
Beautiful Soup
相當老牌的 XML Parser,有自己的一套查詢元素的作法。

所以解決方案有這些:

Beautiful Soup
這是 dependency 最低的作法,Beautiful Soup 自己的查詢方法其實也還不錯用,但由於查詢經常是使用正規表達式描述,當 HTML 格式變動的時候維護成本可能會比較大。
html5lib + ElementTree
此作法的原理是讓 html5lib 將原始 HTML 處理成 Well-formed 格式2,然後再用 ElementTree 來作查詢,ElementTree 查詢的方法非常類似 XPath3,很人性化。
Beautiful Soup + ElementTree + ElementSoup
此作法的原理是讓 BeautifulSoup 將原始 HTML 處理成 Well-formed 格式,然後再用 ElementTree 來作查詢。ElementSoup 則是用來幫忙把 Beautiful Soup 格式轉換為 ElementTree 格式。

目前我是用 Beautiful Soup。最後我決定在本地端 parse 完再丟上去… XD


  1. Google App Engine SDK 1.5.5 以後的版本新增了 Python 2.7 的支援,如果指定使用 Python 2.7 的話,就能使用系統提供的 lxml。 

  2. html5lib 的原理是由它來處理原始資料、製成 DOM、ElementTree 的格式,然後再用 DOM、ElementTree 來查詢,所以解析時間並不會比 Beautiful Soup 快。 

  3. ElementTree 1.3 版以前還不支援對屬性查詢,而 Python 是在 2.7 版才將內建的 ElementTree 更新為 1.3,不過我們可以從 Python SVN 取得最新版的 ElementTree,放到 Google App Engine 上使用,缺點是速度沒有 cElementTree 快。 

第一次安裝 APK 就上手

在 Android 手機安裝自製 APK 有兩種方法。

  1. 使用第三方程式,如 ASTRO File Manager
  2. 手動安裝。

第一種方法太簡單了,這裡只介紹第二種方法。

  1. 安裝 JDK,如果只安裝 JRE 是不夠的。如果作業系統是 Windows 7 64bit,需要依序安裝 JDK 32bit 及 JDK 64bit 兩個版本,缺一不可。
  2. 安裝 Android SDK,照著 Installer 跑完即可。
  3. 安裝 Google USB Driver,使用剛才安裝的 Android SDK 當中的 SDK Manager,在 Available packages › Third party Add-ons › Google Inc. add-ons 找到 Google USB Driver 安裝。
  4. 設定你的手機,到 Settings › Application Settings 設定「允許未知來源」,然後到 Settings › SD Card and Phone Storage 設定「不作為 USB 磁碟使用」或者是「僅用於充電」。
  5. 將手機透過 USB 接上電腦,順利的話驅動程式會自動安裝好。不順利的話,就到裝置管理員手動安裝驅動程式,驅動程式位於 C:\Program Files (x86)\Android\android-sdk\extras\google\usb_driver
  6. 在命令提示字元當中執行 C:\Program Files (x86)\Android\android-sdk\platform-tools\adb install path\file.apk
  7. 大功告成!