開發"憤怒的小鳥"的Lua語言:Wax框架詳解

來源: 51CTO  發布時間: 2011-10-01 17:53  閱讀: 9005 次  推薦: 2   原文鏈接   [收藏]  
摘要:我們都知道Objective-C和Cocoa語言可以開發iOS應用,但是一年前,蘋果決定在iOS系統上使用Lua語言。Wax框架的想法很簡單:凡是Objective-C能做的,Lua也能做!考慮使用像Lua這樣一門簡單而高效的編程語言,構建原生iPhone應用程序有許多充分的理由,而本文將深入探討Wax具有的一些好處,同時演示把Lua與Xcode 4和iOS軟件開發工具包(SDK)集成起來必不可少的實際步驟。

  2011年6月的編程語言排行榜Lua語言一軍突起,一舉進入前十名。這與一年前蘋果決定在iOS系統上使用Lua語言密不可分。但是,你了解如何用Lua語言在iOS上開發應用嗎?這里將向各位介紹Lua語言的iOS應用開發框架Wax,其中在iOS平臺上無比火爆的《憤怒的小鳥》就是由Lua語言用Wax開發的。全文共分兩部分,第一部分將帶您深入探討Wax具有的一些好處,同時演示把Lua與Xcode 4和iOS軟件開發工具包(SDK)集成起來必不可少的實際步驟。第二部分將逐步介紹如何用Wax構建一個簡單的應用程序,顯示Twitter上的當前趨勢話題列表,可以用按鈕來更新內容。

Wax框架及憤怒的小鳥

  Wax是什么?

  Wax for iPhone這種框架在開發時,旨在把Lua腳本語言和原生Objective-C應用編程接口(API)結合起來。這意味著,你可以從Lua里面,使用任何和全部的Objective-C類及框架。

  從技術上來講,Wax結合了Objective-C類和原生C代碼。Lua語言嵌入了C語言,然后Objective-C類并入到其中。

  為什么使用Wax?

  Wax是免費的、開源的。與其他一些基于Lua的移動開發解決方案不同,Wax是個開源框架,只需要你花一點點時間就可以上手,不需要花錢。不喜歡Wax的工作方式,或者發現實施方面的缺陷?源代碼可免費獲取,你總是可以改動源代碼,以滿足自己的需要。

  可以利用原生API。這意味著,為教Objective-C而編寫的教程很容易由Lua for Wax來改動和編寫。這還意味著,你的應用程序在外觀感覺上總是如同原生應用程序,不過又得到了用Lua這種高效腳本語言編寫代碼可以節省時間的好處。

  可以使用Xcode。這意味著,模擬器和設備部署都輕而易舉,不會輕易與未來的iOS版本決裂。

  可以利用所有現有的Objective-C庫。如果你有一個Objective-C類是以前編寫的,不需要改動,就可以將它用在Lua中只要把它放入到Xcode。Three20之類的庫也是一樣。只要按照正常指令來添加庫,就可以使用Lua代碼訪問它們。

  可以利用Wax Lua模塊。Wax有幾個內置的Lua模塊,使得異步HTTP請求和JavaScript對象標注(JSON)創建/解析極其容易而快速(因為模塊是用C編寫的)。

  沒必要管理內存。不再需要操心內存分配之類的事務。Wax為你處理這一切。

  Lua類型自動轉換成對應的Objective-C類型,反之亦然。 這意味著,如果你調用了需要NSString和NSInteger的某個方法,但傳送了Lua字符串和Lua整數,Wax會為你搞定轉換工作。這種轉換功能強大,甚至可以處理復雜的Objective-C特性,比如選擇器。

  你可以利用所有上述特性。不需要精挑細選。你獲得所有特性!

  OK,實在太棒了!我該如何安裝Wax?

  首先你需要Xcode和iPhone SDK。要是你還沒有這些東西,趕緊弄一份!

  用Xcode創建項目

  我們先創建一個新的基于Windows的項目,名為WaxApplication。別忘了把設備設置成iPhone:

WaxApplication

WaxApplication

  通過Finder瀏覽到你保存該項目的文件夾。創建三個新的文件夾:wax、scripts和Classes。你的文件夾看起來應該像這樣:

通過Finder瀏覽到你保存該項目的文件夾

  設置Wax(第一部分,處理文件)

  首先,下載源代碼的壓縮包。Wax放在GitHub上(https://github.com/probablycorey/wax),那樣下載源代碼就很容易。從這里下載壓縮包。

  現在,解壓縮剛下載的文件。瀏覽到剛解壓縮的文件夾。它會有probablycorey-wax-124ca46之類的名稱。

  你的屏幕現在看起來應該像這樣:

解壓縮剛下載的文件

  現在,執行下列操作:

  ◆ 拷貝lib和bin文件夾,把它們粘貼到位于WaxApplication項目文件夾里面的wax文件夾。

  ◆ 將xcode-template/Classes/ProtocolLoader.h拷貝到WaxApplication項目文件夾。

  ◆ 拷貝xcode-template/scripts/文件夾,將它放到WaxApplication項目文件夾里面。

  ◆ 打開WaxApplication項目文件夾里面的wax/lib/extensions/文件夾。刪除SQLite和xml文件夾,下圖所示:

你的屏幕

  你的屏幕應該看起來像這樣:

  設置Wax(第二部分,配置項目)

  現在用Finder選擇Classes、scripts和wax文件夾,把它們拖入到Xcode項目中。把它們放到顯示Wax Application和1 target, iOS SDK X.X的那個條下方。不要勾選顯示Copy items into destination group’s folder(if needed)的復選框。點擊完成。

  現在點擊顯示Wax Application和1 target, iOS SDK 4.3的那個條。接著采取下列步驟:

  ◆ 在右邊窗格中,尋找Targets標題,點擊WaxApplication。點擊Build Phases(構建階段)選項卡。點擊Copy Bundle Resources(復制捆綁資源),清除所有lua文件。

  ◆ 在右下角,先點擊Add Build Phase(添加構建階段),再點擊Add Run Script(添加運行腳本)。

  ◆ 將Shell設成/bin/zsh

  ◆ 將Shell下面的文本區域設成$PROJECT_DIR/wax/lib/build-scripts/copy-scripts.sh。

  你的屏幕現在看起來像這樣:

打開main.m

  改動main.m

  在左邊窗格中,打開名為WaxApplication的文件夾。接下來,打開Supporting Files文件夾。接著,打開main.m,把文件的內容換成如下:

   //這是發生奇跡的地方!
   // Wax并不使用nib文件來裝入主視圖,一切在AppDelegate.lua文件里面完成
   #import <UIKit/UIKit.h>
   #import "wax.h"
   #import "wax_http.h"
   #import "wax_json.h"
   #import "wax_filesystem.h"
   int main(int argc, char *argv[]) {
   NSAutoreleasePool * pool =[[NSAutoreleasePool alloc] init];
    
   wax_start("AppDelegate.lua", luaopen_wax_http, luaopen_wax_json, luaopen_wax_filesystem, nil);
    
   int retVal = UIApplicationMain(argc, argv, nil, @"AppDelegate");
   [pool release];
   return retVal;
   }

  別忘了保存文件!

  刪除不必要的文件

  刪除MainWindow.xib、WaxApplicationAppDelegate.h和WaxApplicationAppDelegate.m三個文件。打開WaxApplication/Supporting Files/WaxPallication-Info.plist,然后刪除鍵是Main nib file base name的那一行。

  測試安裝的Wax

  按↵(命令+回車鍵),或者按左上角的Run,就可以在模擬器中運行應用程序。要是一切正常,你會看到一個簡單的應用程序會說Hello Lua!。

  要是你沒看到這個消息,檢查之前的步驟,看看有沒有步驟漏了。

  查看Lua

  展開Scripts文件夾,打開AppDelegate.lua。你會看到運行該應用程序的Lua代碼。

  你可能會先注意到,沒有語法高亮。遺憾的是,對于Xcode中的Lua語法高亮問題,我還沒有發現穩定的解決方案(是你發現了,請留言告訴我!)。

  接下來你可能會注意到,沒有方括號,不過使用了像UIScreen和UIWindow這些類。那是由于你在使用Lua構建一個AppDelegate類;在蘋果和蘋果的代碼看來,你在使用Objective-C、構建Objective-C類!

  方法名稱

  你可能還注意到奇怪的方法名稱colorWithRed_green_blue_alpha。要是你熟悉Objective-C,就知道方法名稱可以有冒號。Lua中的函數名稱不能有冒號。為了補償這個差異,凡是Objective-C中隔開方法名稱的地方,在Lua中都換成下劃線。比如說:

  Objective-C中的colorWithRed:green:blue:alpha對應于Lua中的colorWithRed_green_blue_alpha。

  Objective-C中的selectRowAtIndexPath:animated:scrollPosition:對應于Lua中的selectRowAtIndexPath_animated_scrollPosition。

  面向對象的模型

  Lua的另一個問題是,它沒有像Objective-C那樣的繼承體系。Lua中根本沒有類。為了克服這個問題,Wax突出顯示了放在每個Wax Lua文件最前面的一個函數:waxClass。在默認的AppDelegate.lua中,這一行看起來像這樣:

   waxClass{"AppDelegate", protocols = {"UIApplicationDelegate"}}

  想通過Lua創建一個Objective-C類,就要使用waxClass{CLASS NAME, PARENT_CLASS}這個函數。你添加到該Lua文件的所有之后的函數(在同一個文件里面)都會作為實例方法,自動添加到新的類。

  AppDelegate.lua的這一行顯示,還可以定義你的類定義哪些協議。

  雖然waxClass解決了定義Objective-C可以使用的類這個問題,但還是存在一個問題:由于Lua沒有類,它沒有像Objective-C那樣的動態自變量。為了克服這個問題,Wax自動將每個方法的第一個變量作為類的當前實例。你可以發現,當你查看AppDelegate.lua中的applicationDidFinishLaunching時,第一個變量是自變量,即使Objective-C版的這個方法只有1個變量。然而,如果你非得將類的當前實例作為每個方法的第一個變量來傳送,就會很煩人,于是添加了一些語法上的便利(syntactical sugar)。不是使用.操作符在Lua中進行方法調用,而是使用了:操作符:

local view = UIView.initWithFrame(CGRect(0, 0, 100, 100))

  --以下一模一樣

   view:addSubview(someView)
   
iew.addSubview(view, someView)

  值得一提的另一個重要方面是,Wax不支持Objective-C屬性。Wax迫使Lua和Objective-C只與方法進行聯系。

  -- 這不行

someView.frame

  -- 你而是需要使用getter/setter方法

   View:frame() some
  
View:setFrame(someFrame)

  只用于Lua的變量

  你可以使用點.操作符,為任何Objective-C對象創建成員變量。不像冒號:操作符(用于對Objective-C類/實例調用方法),點.操作符可以針對對象的Lua方面,動態創建成員變量(對象的Objective-C方面對這些變量一無所知)。在對象的生命周期之內,都可以使用成員變量。

  輸出到控制臺

  AppDelegate.lua還顯示了你如何可以編寫調試文本、輸出到控制臺。你可以使用函數puts。

  內存管理

  我之前說過,使用Lua的話,你根本沒必要分配、保留和釋放內存。你在調用任何初始化器之前,根本不需要調用內存分配。實際上,如果你這么做的話,程序可能會出現內存泄漏。

  太棒了!接下來做什么?

  你已經深入了解了專門針對Wax的Lua的基本知識,就可以準備編寫iPhone應用程序了!

  在這個教程的第二個部分,我們將只用幾行Lua,就可以編寫出擁有刷新按鈕的一個Twitter示例應用程序。

  看完這個教程是不是你也有信心打造出自己的《憤怒的小鳥》呢?

小貼士

Lua程序設計語言 是一個簡潔、輕量、可擴展的腳本語言。Lua讀作/'lua/(嚕啊),是葡萄牙語中"Luna"(月亮)的意思。

Lua是一種輕量語言,它的官方版本只包括一個精簡的核心和最基本的庫。這使得Lua體積小、啟動速度快。它用標準C語言編寫并以源代碼形式開放,編譯后僅僅一百余K,可以很方便的嵌入別的程式里。和許多"大而全"的語言不一樣,網路通訊、圖形界面等都沒有默認提供。但是Lua可以很容易地被擴展:由宿主語言(通常是C或C++)提供這些功能,Lua可以使用它們,就像是本來就內置的功能一樣。事實上,現在已經有很多成熟的擴展模塊可供選用。

Lua的目標是成為一個很容易嵌入其它語言中使用的語言。大多數程序員也認為它的確做到了這一點。

很多應用程序使用Lua作為自己的嵌入式腳本語言,以此來實現可配置性、可擴展性。這其中包括大話西游II、仙境傳說、魔獸世界、戰錘40k、博德之門、軒轅劍外傳漢之云等,在移動領域最著名的便是《憤怒的小鳥》。

  第四步:UITableViewController數據方法

  我們的應用程序可以啟動,這很好,但我們想要顯示一些數據。為了顯示這些數據,所有UITableViewController必須實施幾個方法,告訴設備顯示什么數據。其中第一個方法是numberOfSectionsInTableView:,它會返回將在表中顯示的群組數量。對該應用程序來說,這一步很容易,因為我們只需要一個表段,即擁有當前趨勢的那個表段。

   function numberOfSectionsInTableView(self, tableView)
  
return1
   end

  是不是很容易?現在我們得實施tableView_numberOfRowsInSection方法,它告訴設備某個特定的分組會有多少行。對該應用程序來說,這同樣很容易,因為我們只有一個表段。記得我們如何用init方法對Lua表進行初始化嗎?只要計數該表中的表項數量,就知道該表需要顯示多少行:

   function tableView_numberOfRowsInSection(self, tableView, section)
   
return #self.trends
  
end

  這使用Lua簡寫方法來計數表中的表項數量。如果你不熟悉Lua表,下面有幾個要點:

  1. 大多數語言中被稱為詞典的東西在Lua中被稱為表。

  2. 大多數語言中被稱為數組的東西被稱為帶有序數字鍵的表。

  3. 數組使用從1開始的索引,而幾乎其他每種語言使用從0開始的索引。

  接下來是tableView_titleForHeaderInSection方法。該方法告訴設備顯示什么作為某群組的標題。你只要返回某個指定群組的字符串,標題之后會神奇地出現在表行上方: 

   function tableView_titleForHeaderInSection(self, tableView, section)
  if section == 0 then
  return "Currently Trending Topics"
  end
  return nil
  end

  相當簡單。現在我們只要往表格填充從Twitter的服務器取來的數據。如果你熟悉Objective-C中的UITableViewControllers,就會認識這下一個方法:

  function tableView_cellForRowAtIndexPath(self, tableView, indexPath)
  local identifier = "TwitterTableViewControllerCell"
  local cell = tableView:dequeueReusableCellWithIdentifier(identifier) or
   UITableViewCell:initWithStyle_reuseIdentifier(UITableViewCellStyleDefault, identifier)
  local object = self.trends[indexPath:row() +1] -- 必須是+1,因為Lua數組從1開始
   cell:textLabel():setText(object)
  return cell
  end

  這個方法要復雜一點。首先,我們定義了對同一種類型,但可能有不同內容的所有表格單元(cell)來說很獨特的標識符。這種情況下,我們稱之為TwitterTableViewControllerCell。接下來,我們使用Lua簡寫方法,獲得UITableViewCell的實例。注意夾在這兩個方法調用之間的or。如果第一個方法調用的結果不是false或nil, cell就被設成第一個方法調用的值。否則,cell會被設成是第二個方法調用的結果。

  我們這么做是為了節省內存。這樣一來,設備每次只要為屏幕上10個左右的表格單元分配內存,而不是為數據源里面可能擁有的數千個表格單元分配內存。當然,我們不會有數千行要顯示,但這仍是個有必要養成的好習慣。接下來,我們把表格單元的內容設成從self.trends數組的合適部分獲取的趨勢。我們知道,該索引從來不會超出self.trends的范圍,因為我們通過方法tableView_numberOfRowsInSection,將數組大小告訴給了設備。最后,我們返回剛創建的表格單元。如果你現在按Run,它應該看起來像這樣:

返回剛創建的表格單元

  第五步:從Twitter裝入數據

  現在說說真正展現Wax魅力的好玩部分:從互聯網、或者更準確地說從Twitter的服務器裝入JSON數據。先不妨創建一個名為loadDataFromTwitter的新方法。該方法會從Twitter的服務器獲取JSON數據,然后為表重新裝入新數據。

  function loadDataFromTwitter(self)
   UIApplication:sharedApplication():setNetworkActivityIndicatorVisible(true) -- show spinner
   wax.http.request{"http://api.twitter.com/1/trends.json", callback =function(json, response)
   UIApplication:sharedApplication():setNetworkActivityIndicatorVisible(false) -- hide spinner
  if response:statusCode() == 200 then
   self.trends = {} -- Reset the list of trends when the trends are refreshed
  for index,value in ipairs(json["trends"]) do-- iterate over a table with numerical keys
  table.insert(self.trends, value["name"]) -- append the value to the "array"
  end
  end
   self:tableView():reloadData()
  end}
  end

  是的,就這么簡單。你定義了請求的URL以及請求完畢后執行的回調。Wax自動確認服務器在運行JSON后,會將JSON文本自動轉換成Lua表。這使得顯示網絡活動指示器(設備右上角靠近無線信號指示器的圖標)異常容易。返回的JSON看起來像這樣。鍵trends保存一組對象,這些對象包含趨勢名稱和訪問提到該趨勢的所有Twitter消息的URL。

  趨勢名稱存儲到self.trends變量里面后,重新裝入tableView,它可以再次調用我們之前定義的所有數據方法。這導致趨勢在表中顯示,非常類似最終產品。

  如果你立即試圖運行該應用程序,看上去沒什么不同。那是因為該方法從未調用。如果從viewDidLoad:里面調用該方法,我們就能確保總是可以顯示最新趨勢。把這行添加到viewDidLoad:方法末行的前一行:

   self:loadDataFromTwitter()

  如果你點擊Run,應用程序看起來有點像這樣(你得等幾秒鐘裝入趨勢,請留意那個活動指示器!):

請留意那個活動指示器

  第六步:添加重新裝入按鈕

  該應用程序相當棒。不過,要是有重新裝入按鈕讓你可以顯示最新趨勢,就更好了。幸好,這很容易實現。

  不妨把重新裝入按鈕放到屏幕的右上角。蘋果其實提供了上面有刷新圖標的按鈕,以圖方便,就用這個按鈕吧。先開始用viewDidLoad:方法創建一個按鈕。把下面這行添加到loadDataFromTwitter調用的前面。

  local button = UIBarButtonItem:initWithBarButtonSystemItem_target_action(UIBarButtonSystemItemRefresh, self, "loadDataFromTwitter")

  這創建了一個UIBarButtonItem:一旦按下按鈕,就會對當前對象實例調用loadDataFromTwitter方法。如果你想嘗試其他風格。

  我們已創建好了按鈕,現在需要把它添加到我們的界面上。使用UITableViewController使得這項工作輕而容易,我們只要對導航欄對象實例調用setRightBarButtonItem:方法,就像這樣(這行位于上面給出的那一行后面):

   self:navigationItem():setRightBarButtonItem(button)

  如果你各方面都做好了,完成的應用程序應該看起來像這樣:

完成的應用程序

  第七步:額外好處

  這個項目一個有意思的擴展就是制作更顯眼的裝入指示器。這可能需要把UIActivityIndicatorView放到其中一個按鈕位置。

  結論

  我希望你覺得這篇教程深入淺出地介紹了Wax。如果你想看到有關某個課題的更多Wax教程,歡迎給我留言。

2
0
 
 
 

文章列表

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()