在Visual Studio中使用MonoTouch開發(fā)iOS應(yīng)用:開發(fā)體驗(yàn)
新建項(xiàng)目
根據(jù)我的個(gè)人習(xí)慣,我會(huì)先創(chuàng)建一個(gè)空白的解決方案。首先在Mac OS X中打開MonoDevelop,然后在菜單中選擇File - New- Solution,在彈出對話框的Other分類中選擇Blank Solution模板,并填寫合適的位置和名稱:

然后便是創(chuàng)建iPhone應(yīng)用程序項(xiàng)目。還是剛才的對話框,選擇C#- iPhone and iPad分類下的iPhone Window-based Project模板。同樣,在對話框下方填寫合適的位置和名稱,我的習(xí)慣是將所有的源代碼統(tǒng)一放在src目錄下(在解決方案中也會(huì)創(chuàng)建一個(gè)src目錄與之對應(yīng)):

點(diǎn)擊OK。下一步是額外的項(xiàng)目配置,可以直接點(diǎn)擊OK。此時(shí)我們就會(huì)發(fā)現(xiàn)MonoDevelop里展示出的項(xiàng)目文件:

其中Main.cs里包含了項(xiàng)目的啟動(dòng)代碼及一個(gè)AppDelegate類,MainWindow.xib是主窗口的界面文件,而 MainWindow.xib.designer.cs文件則是MonoDevelop根據(jù)xib文件中的標(biāo)記所自動(dòng)創(chuàng)建的C#代碼,在絕大部分情況下我們不會(huì)去修改它。
編輯界面
雙擊MainWindow.xib文件,便會(huì)打開Interface Builder。下圖左為Library窗口(近似于VS中的Toolbox);中間上方是可視化的UI編輯器,下方則是對象管理器,顯示了界面中定義的對象;右側(cè)便是用來修改屬性的Inspector窗口(近似于VS中的Properties窗口):

首先,在Library窗口上方選擇Objects,并將一個(gè)Round Rect Button拖動(dòng)至UI編輯器,雙擊,輸入Hello World:

然后,在Library窗口上方選擇Classes,在上方列表中選擇AppDelegate,并在下方下拉框中選取Outlets,并使用下方加號添加一個(gè)id,叫做ButtonCounter:

接著便是個(gè)比較有趣的操作。在對象管理器里選中App Delegate對象,并在Inspector上方選擇Connections,再將ButtonCounter右側(cè)的小圓點(diǎn)拖動(dòng)至按鈕,這會(huì)將ButtonCounter這個(gè)id與按鈕關(guān)聯(lián)起來,如下圖:

在Interface Builder中保存,回到MonoDevelop,打開MainWindow.xib.designer.cs文件,便可以看到其中在AppDelegate中生成的ButtonCounter屬性:
- private MonoTouch.UIKit.UIButton __mt_ButtonCounter;
- [MonoTouch.Foundation.Connect("ButtonCounter")]
- private MonoTouch.UIKit.UIButton ButtonCounter {
- get {
- this.__mt_ButtonCounter = ((MonoTouch.UIKit.UIButton)
- (this.GetNativeField("ButtonCounter")));
- return
- this.__mt_ButtonCounter; }
- set { this.__mt_ButtonCounter = value;
- this.SetNativeField("ButtonCounter", value);
- }}
可見,MonoDevelop根據(jù)xib的內(nèi)容,自動(dòng)生成了一些C#代碼。AppDelegate是個(gè)Partial Class,它的另一部分在Main.cs文件中,一會(huì)兒我們便會(huì)使用這里的ButtonCounter定義。
配置Visual Studio 雖然MonoDevelop的sln和csproj文件的格式與Visual Studio兼容(包括2005、2008、2010三個(gè)版本的VS),但是VS無法識別iPhone應(yīng)用程序的項(xiàng)目模板,因此如果您直接打開 iOS101.sln則會(huì)加載失敗。因此,我們需要并行地創(chuàng)建一些sln和csproj,其中大部分內(nèi)容與MonoDevelop創(chuàng)建的內(nèi)容保持同步。
例如,我創(chuàng)建了iOS101.VS.sln及iPhoneApp.UI.VS.csproj(一個(gè).NET 2.0的Class Library)兩個(gè)文件,它們分別與iOS101.sln和iPhoneApp.UI.csproj放在同樣的目錄下。值得注意的是 iPhoneApp.UI.VS.csproj文件,如果您直接在VS里創(chuàng)建這個(gè)項(xiàng)目文件,它的默認(rèn)命名空間里也會(huì)包含“VS”,您可能需要手動(dòng)修改一下。由于要和MonoDevelop中的項(xiàng)目保持一致的“可編譯通過性”,我們還需要引用MonoTouch SDK里提供的dll。于是我在iOS101目錄中創(chuàng)建了lib/monotouch目錄,并使用如下命令復(fù)制所有的MonoTouch提供的dll文件:
cp /Developer/MonoTouch/usr/lib/mono/2.1/*.dll ~/Projects/iOS101/lib/monotouch 然后,編輯iPhoneApp.UI.VS.csproj的程序集引用和項(xiàng)目文件,最終結(jié)果差不多是這樣的。請注意MonoTouch中xib文件的類型為Page,而VS中則需要設(shè)為None:
- <?xml version="1.0" encoding="utf-8"?>
- <Project ...> ...
- <ItemGroup>
- <Reference Include="monotouch">
- <HintPath>..\..\lib\monotouch\monotouch.dll</HintPath>
- </Reference>
- <Reference Include="System">
- <HintPath>..\..\lib\monotouch\System.dll</HintPath>
- </Reference>
- <Reference Include="System.Core">
- <HintPath>..\..\lib\monotouch\System.Core.dll</HintPath>
- </Reference>
- </ItemGroup>
- <ItemGroup>
- <None Include="Info.plist"
- />
- <Compile Include="Main.cs"
- />
- <None Include="MainWindow.xib"
- />
- <Compile Include="MainWindow.xib.designer.cs">
- <DependentUpon>MainWindow.xib</DependentUpon>
- </Compile>
- </ItemGroup>
- ...</Project>
在VS的結(jié)果則類似于:

試著編譯一下,通過則表示配置成功。
編寫代碼
這里您是否有些疑惑,為什么上面創(chuàng)建的是一個(gè).NET 2.0項(xiàng)目呢?這樣我們還能夠使用C# 3.0中的高級特性嗎?答案是肯定的,只要我們使用的是Visual Studio 2008或是2010,則即使是針對.NET 2.0所編寫的代碼,VS也會(huì)使用C# 3.0的編譯器,因?yàn)槲覀兌贾榔鋵?shí)C# 3.0只需要一點(diǎn)點(diǎn)框架和類庫的支持(擴(kuò)展方法)。您甚至可以使用C# 4.0的部分特性,例如參數(shù)的默認(rèn)值,命名參數(shù)等等。可惜您無法使用C# 4.0的動(dòng)態(tài)性,因?yàn)樗枰狣LR和Microsoft.CSharp.dll,又涉及到大量的動(dòng)態(tài)代碼生成,我對此沒什么信心和意愿。當(dāng)然您感興趣的話也可以嘗試一下。
我在這里使用.NET 2.0的原因,是希望可以盡可能減少對系統(tǒng)程序集的依賴,而盡量使用MonoTouch所提供的dll。例如現(xiàn)在,除了mscorlib以外,所有的程序集都與Windows上所安裝的.NET Framework無關(guān),這保證了我們編寫的代碼可以在MonoTouch兼容。
現(xiàn)在就來開始編寫代碼吧,您可以在VS里打開Main.cs,在AppDelegate的FinishedLaunching方法中添加如下代碼,使之成為:
- public
- override
- bool FinishedLaunching(UIApplication app, NSDictionary options){
- int i =
- 0;
- this.ButtonCounter.TouchDown +=
- delegate
- {
- this.ButtonCounter.SetTitle((++i).ToString(), UIControlState.Normal);
- };
- window.MakeKeyAndVisible();
- return
- true;}
FinishedLaunching方法在程序啟動(dòng)時(shí)調(diào)用,此時(shí)我們?yōu)锽uttonCounter添加一個(gè)TouchDown事件(類似于Click)添加一個(gè)處理函數(shù)。這里用到了C#中的匿名函數(shù)特性,并捕獲外部的變量i,每次點(diǎn)擊按鈕都將i加一,并顯示在按鈕上。在這里我們使用.NET中比較常用方式添加事件處理,事實(shí)上您也可以在Interface Builder中定義一個(gè)Action,并把它與Button的TouchDown事件關(guān)聯(lián)起來。這個(gè)Action會(huì)表現(xiàn)為一個(gè)Partial Method,您可以在代碼里補(bǔ)全其實(shí)現(xiàn)。
保存代碼后您便可以回到MonoDevelop中,為了能夠在iPhone模擬器里運(yùn)行,您還要修改一個(gè)參數(shù)。對iPhoneApp.UI點(diǎn)擊右鍵,打開 Options對話框,在左側(cè)選中Build - iPhone Build類別,并將右側(cè)的SDK version設(shè)為4.0,如下:

點(diǎn)擊OK保存并關(guān)閉對話框。此時(shí)可以選擇菜單Run - Run,或直接使用快捷鍵Command(即Win鍵)+ Alt + Enter便會(huì)編譯項(xiàng)目,并打開模擬器執(zhí)行程序。在默認(rèn)情況可能打開的iPad模擬器,您可以在Hardware - Device中選擇iPhone或iPhone 4。運(yùn)行效果如下:

試著點(diǎn)擊按鈕查看效果吧。
單元測試及其他
如果您想調(diào)試代碼,只需要在MonoDevelop中設(shè)置端點(diǎn),并選擇菜單Run - Debug,或直接使用快捷鍵Command + Enter便可以對模擬器進(jìn)行調(diào)試。但是如果是要單元測試呢?這問題也不大,MonoDevelop自帶NUnit項(xiàng)目,您可以創(chuàng)建這樣一個(gè)單元測試項(xiàng)目,刪除其默認(rèn)引用,換之為MonoTouch SDK里所提供的程序集,同樣您可以在Visual Studio中開發(fā)單元測試代碼,但是調(diào)試執(zhí)行必須在MonoDevelop里進(jìn)行,因?yàn)镸onoTouch提供的程序集都是Mac下的Mono實(shí)現(xiàn),它們在Windows下的作用只是為Visual Studio提供必要的元數(shù)據(jù),使我們能夠享受到智能提示之類的便利,想要在Windows里運(yùn)行則是不行的。
但是,事實(shí)上我們也可以將Visual Studio里面的項(xiàng)目定義為.NET Framework 3.5項(xiàng)目,并直接使用.NET提供的程序集,對于MonoTouch里額外的程序集,例如System.Json.dll,則面向.NET 3.5自己重新構(gòu)建一遍即可(源代碼可以使用.NET Reflector獲得或是利用Mono上的開源代碼)。這么做的優(yōu)勢在于,對于那些與MonoTouch無關(guān)的代碼,我們都可以在Visual Studio里進(jìn)行調(diào)試與測試了。于是乎,我們可以在代碼開發(fā)階段盡可能留在熟悉而強(qiáng)大的環(huán)境中,對開發(fā)效率有很大幫助。
這種做法也有缺點(diǎn),例如,雖然MonoTouch提供的類庫與.NET 3.5兼容,但事實(shí)上我并不能百分之百保證這點(diǎn),因此在.NET 3.5里可以編譯通過的代碼,也有可能無法在MonoTouch里編譯執(zhí)行。此外,這種方法也會(huì)讓您無法使用Mono程序集中對.NET的擴(kuò)展(主要是 Mono命名空間下的類庫)。不過這兩個(gè)理論上問題到目前為止還沒有給我造成什么困擾,我也只有在需要在查看模擬器運(yùn)行效果時(shí)才回到Mac及 MonoDevelop中。
有些朋友看到System.Json可能會(huì)有些熟悉,因?yàn)樗赟ilverlight開發(fā)中也有出現(xiàn)。您說的沒錯(cuò),事實(shí)上MonoTouch里的程序集版本號與Silverlight一樣,都是2.0.5.0,甚至連強(qiáng)簽名都是一致的。只可惜Silverlight里的類庫是.NET 3.5的子集,例如所有同步的IO操作都被去除了,因此我們很難使用Silverlight來開發(fā)MonoTouch程序。當(dāng)然,有了 Silverlight,對我們開發(fā)MonoTouch也是有所幫助的,這點(diǎn)以后再談。
最后,您應(yīng)該已經(jīng)意識到,我們需要在VS的項(xiàng)目文件與MonoDevelop的項(xiàng)目文件直接做同步,這個(gè)同步包括程序集引用與代碼文件兩方面。如果您覺得手動(dòng)編輯比較麻煩的話,就寫一個(gè)自動(dòng)同步的小程序咯——不會(huì)?那么還是先別搞MonoTouch了,從編程基礎(chǔ)學(xué)起吧。