綁定概述
在 Windows/Linux 平台上, .Net/Mono 可以通過平台調用 (P/Invoke) 技術調用本地類庫, 通過互操作 (Interop) 技術調用 COM 組件, 在 iOS 平台上, MonoTouch 也有類似的技術, 可以調用 iOS 的 CocoaTouch 類庫, 這種技術在 MonoTouch 叫做綁定 (Binding) , 整個 monotouch.dll 就是用綁定技術完成的。
互聯網上有很多熱心網友提供的 CacoaTouch 類庫, 如果想使用這些類庫, 完全用 C# 重寫是不可取的, 所以就要用到 MonoTouch 的綁定技術。
綁定技術聽起來高深, 其實仔細研究起來, 其實並不難。 接下來, 以 KKGridView 為例, 說明怎樣綁定 CocoaTouch 類庫項目。
准備 MonoTouch 綁定項目
新建一個名稱為 KKGridView 的空白解決方案, 作為工作區, 再新建一個綁定項目, 名稱為 Binding , 項目建好之后, 設置綁定項目的默認命名空間為 MonoTouch.KKGrid , 並設置項目的輸出為 KKGridView , 相關截圖如下:
綁定項目默認結構如下, 包含兩個文件: ApiDeginition.cs 和 StructsAndEnums.cs , 其中 ApiDefinition 用於綁定 CacoaTouch 類庫定義的 interface 、 delegate 與 protocol 及其成員, 而 StructsAndEnums 用於綁定 ApiDefinition 所需的結構、 枚舉以及其它。 這兩個文件的編譯方式是不同的, 所以對應的 C# 類型必須對號入座才行。
獲取 KKGridView 源代碼並編譯
KKGridView 在 GitHub 上的主頁是 https://github.com/kolinkrewinkel/KKGridView.git , 使用 git 可以輕松獲取其源代碼。 打開一個命令行窗口, 切換到綁定項目目錄, 輸入下面的命令:
git clone https://github.com/kolinkrewinkel/KKGridView.git
等命令行運行完畢, 源代碼就獲取好了, 接下來要編譯 KKGridView , 接着輸入下面的命令:
cd KKGridView xcodebuild -project KKGridView.xcodeproj -target KKGridView -sdk iphonesimulator -configuration Release clean build xcodebuild -project KKGridView.xcodeproj -target KKGridView -sdk iphoneos -configuration Release clean build lipo -create -output libKKGridView.a build/Release-iphonesimulator/libKKGridView.a build/Release-iphoneos/libKKGridView.a
現在打開 MonoDevelop 將最終生成的 libKKGridView.a 添加到綁定項目 , 現在可以開始進行綁定了。
綁定 Objective-C 類型至 C#
綁定的語法定義為:
[BaseType(typeof(TypeBase))] interface MyType [: Prodocol1, Protocol2] { IntPtr Constructor(string foo); }
MyType 與 ObjC 的類型對應, TypeBase 與 ObjC 的基類對應, Protocol1 、 Prodocol2 與 ObjC 類型實現的協議對應。
interface
ObjC 的 interface 定義如下:
@interface KKGridView : UIScrollView @end
對應的綁定語法如下:
[BaseType(typeof(UIScrollView))] interface KKGridView { }
protocol
ObjC 的 protocol 定義語法如下:
@protocol KKGridViewDataSource <NSObject> @end
或者
@protocol KKGridViewDelegate <NSObject , UIScrollViewDelegate> @end
ObjC 的 protocol 與 C# 的 interface 有些類似, 但是 protocol 中定義的方法有兩種, optional 和 required , 又有點兒像抽象類, MonoTouch 將其綁定為類, 並添加 ModelAttribute 標記, 對應的綁定語法分別為:
[Model, BaseType(typeof(NSObject))] interface KKGridViewDataSource { } [Model, BaseType(typeof(UIScrollViewDelegate))] interface KKGridViewDelegate { }
instance method
實例方法綁定為對應的 C# 實例方法:
- (NSString *)gridView:(KKGridView *)gridView titleForHeaderInSection:(NSUInteger)section;
[Export("gridView:titleForHeaderInSection:")] string GridViewTitleFoHeaderInSection(KKGridView gridView, uint section);
如果是 protocol 的 required 方法, 則在對應的 C# 方法上添加 Abstract 標記, 例如:
- (NSUInteger)gridView:(KKGridView *)gridView numberOfItemsInSection:(NSUInteger)section;
[Abstract, Export("gridView:numberOfItemsInSection:")] uint GridViewNumberOfItemsInSection(KKGridView gridView, uint section);
class method
ObjC 中的 class method 與 C# 中的靜態方法概念一致, 因此綁定為 C# 的靜態方法, 例如:
+ (id)cellForGridView:(KKGridView *)gridView;
[Static, Export("cellForGridView:")] KKGridViewCell CellFroGridView(KKGridView gridView);
property
ObjC 的屬性通常由 setPropertyName 、 propertyName 兩個方法組成, 綁定為 C# 的屬性:
@property (nonatomic) BOOL allowsMultipleSelection;
[Export("allowsMultipleSelection")] bool AllowsMultipleSelection { get; set; }
如果不是由默認的兩個方法組成, 例如:
@property (nonatomic, getter = isSelected) BOOL selected;
對應的綁定為:
[Export("selected")] bool Selected { [Bind("isSelected")]get; set; }
enum
枚舉的綁定是最容易的, 不過要放在 enums.cs 文件中, 例如:
typedef enum { KKGridViewAnimationFade, KKGridViewAnimationResize, KKGridViewAnimationSlideLeft, KKGridViewAnimationSlideTop, KKGridViewAnimationSlideRight, KKGridViewAnimationSlideBottom, KKGridViewAnimationExplode, KKGridViewAnimationImplode, KKGridViewAnimationNone } KKGridViewAnimation;
public enum KKGridViewAnimation { Fade, Resize, SlideLeft, SlideTop, SlideRight, SlideBottom, Explode, Implode, None }
添加 Makefile
# 定義一些常量 PROJECT_ROOT=KKGridView PROJECT=$(PROJECT_ROOT)/$(PROJECT_ROOT).xcodeproj BUILD_ROOT=$(PROJECT_ROOT)/Build TARGET=$(PROJECT_ROOT) SDK=lib$(TARGET).a BTOUCH=/Developer/MonoTouch/usr/bin/btouch SMCS=/Developer/MonoTouch/usr/bin/smcs XBUILD=/Developer/usr/bin/xcodebuild # 從github獲取源代碼 $(PROJECT_ROOT): git clone https://github.com/kolinkrewinkel/$(PROJECT_ROOT).git cd $(PROJECT_ROOT) && git pull # 編譯模擬器版本 simulator: $(PROJECT_ROOT) mkdir -p libs $(XBUILD) -project $(PROJECT) -target $(TARGET) -sdk iphonesimulator -configuration Release clean build mv -f $(BUILD_ROOT)/Release-iphoneSimulator/lib$(TARGET).a ./libs/lib$(TARGET)-simulator.a # 編譯設備版本 iphoneos: $(PROJECT_ROOT) mkdir -p libs $(XBUILD) -project $(PROJECT) -target $(TARGET) -sdk iphoneos -configuration Release clean build mv -f $(BUILD_ROOT)/Release-iphoneos/lib$(TARGET).a ./libs/lib$(TARGET)-iphoneos.a # 講兩個版本合成為一個 sdk: lipo -create -output $(SDK) libs/lib$(TARGET)-simulator.a libs/lib$(TARGET)-iphoneos.a # 編譯 MonoTouch 組件 asm: # 使用 btouch 編譯出的 dll 文件總是無法運行, 不知是怎么回事, 只能用 MonoDevelop 進行編譯, 所以把這里注釋掉了。 #$(BTOUCH) -d=MONOTOUCH -out:bin/$(TARGET).dll api.cs -s:enum.cs --link-with=$(SDK),$(SDK) # 清理 clean: rm -rf $(PROJECT_ROOT) libs ios *.a *.dll *.stamp # 全部任務 all: clean simulator iphoneos sdk asm
綁定項目源代碼
KKGridView 的全部綁定源代碼放在 GitHub , 地址為 https://github.com/beginor/MonoTouch.KKGridView , 有興趣的可以圍觀。