共用方式為


逐步解說:系結 iOS Objective-C 連結庫

重要

我們目前正在調查 Xamarin 平臺上的自定義系結使用方式。 請接受 這項調查 ,以通知未來的開發工作。

本文提供針對現有 Objective-C 連結庫 InfColorPicker 建立 Xamarin.iOS 系結的實作逐步解說。 其涵蓋的主題包括編譯靜態 Objective-C 庫、系結靜態庫,以及在 Xamarin.iOS 應用程式中使用系結。

在 iOS 上工作時,您可能會遇到想要取用第三方 Objective-C 連結庫的情況。 在這些情況下,您可以使用 Xamarin.iOS 系結專案 來建立 C# 系結 ,讓您在 Xamarin.iOS 應用程式中取用連結庫。

一般而言,在iOS生態系統中,您可以找到3種類別的連結庫:

  • 做為先行編譯的靜態庫檔案,擴展名 .a 與其標頭(s) (.h 檔案) 一起。 例如, Google 的分析連結庫
  • 做為先行編譯架構。 這隻是包含靜態庫、標頭,有時使用 .framework 擴充功能的其他資源的資料夾。 例如, Google 的 AdMob Library
  • 就像原始碼檔案一樣。 例如,包含 Just .m.h Objective C 檔案的連結庫。

在第一個和第二個案例中,已經有先行編譯的CocoaTouch靜態庫,因此在本文中,我們將著重於第三個案例。 請記住,在您開始建立系結之前,請一律檢查連結庫所提供的授權,以確保您可以自由系結它。

本文提供使用 開放原始碼 InfColorPickerObjective-C 專案建立系結專案的逐步解說,不過本指南中的所有資訊都可以調整為搭配任何第三方Objective-C連結庫使用。 InfColorPicker 連結庫提供可重複使用的檢視控制器,可讓用戶根據其 HSB 表示法選取色彩,讓使用者更容易選擇色彩。

Example of the InfColorPicker library running on iOS

我們將涵蓋在 Xamarin.iOS 中取用此特定 Objective-C API 所需的所有必要步驟:

  • 首先,我們將使用 Xcode 建立 Objective-C 靜態庫。
  • 然後,我們會將此靜態庫與 Xamarin.iOS 系結。
  • 接下來,示範 Objective Sharpie 如何藉由自動產生 Xamarin.iOS 系結所需的部分 API 定義來減少工作負載。
  • 最後,我們將建立使用系結的 Xamarin.iOS 應用程式。

範例應用程式將示範如何使用強式委派,在 InfColorPicker API 和 C# 程式代碼之間進行通訊。 當我們瞭解如何使用強委派之後,我們將討論如何使用弱式委派來執行相同的工作。

需求

本文假設您已熟悉 Xcode 和語言, Objective-C 而且您已閱讀我們的 系結 Objective-C 檔。 此外,需要下列專案才能完成呈現的步驟:

  • Xcode 和 iOS SDK - 必須在開發人員的電腦上安裝並設定 Apple 的 Xcode 和最新的 iOS API。
  • Xcode 命令行工具 - Xcode 命令行工具 必須針對目前安裝的 Xcode 版本安裝(請參閱下方的安裝詳細數據)。
  • Visual Studio for Mac 或 Visual Studio - 應在開發電腦上安裝及設定最新版本的 Visual Studio for Mac 或 Visual Studio。 開發 Xamarin.iOS 應用程式需要 Apple Mac,而且在使用 Visual Studio 時,您必須連線到 Xamarin.iOS 組建主機
  • 最新版的 Objective Sharpie - 從這裡下載的 Objective Sharpie 工具目前的複本。 如果您已安裝 Objective Sharpie,您可以使用 將它更新為最新版本 sharpie update

安裝 Xcode 命令行工具

如上所述,我們將在本逐步解說中使用 Xcode 命令行工具(特別是 makelipo)。 make此命令是一個非常常見的 Unix 公用程式,會使用 makefile 來自動編譯可執行的程式和連結庫,以指定程式應該如何建置。 此命令 lipo 是用來建立多架構檔案的OS X命令行公用程式;它會將所有硬體架構使用的多個 .a 檔案合併成一個檔案。

根據 Apple 使用 Xcode 的命令行建置常見問題檔,在 OS X 10.9 和更新版本中,[Xcode 喜好設定] 對話框的 [下載] 窗格不再支援下載命令行工具。

您必須使用下列其中一種方法來安裝工具:

  • 安裝 Xcode - 當您安裝 Xcode 時,它隨附於所有命令行工具。 在OS X 10.9 填充碼中(安裝在 中 /usr/bin),可以將隨附 /usr/bin 的任何工具對應至 Xcode 內的對應工具。 例如, xcrun 命令可讓您從命令行尋找或執行 Xcode 內的任何工具。

  • 終端機應用程式 - 從終端機應用程式 ,您可以執行 xcode-select --install 命令來安裝命令行工具:

    • 啟動終端機應用程式。
    • 輸入 xcode-select --install 並按 Enter,例如:
    Europa:~ kmullins$ xcode-select --install
    
    • 系統會要求您安裝命令列工具,按下 [ 安裝 ] 按鈕: Installing the command line tools

    • 工具將會從 Apple 的伺服器下載並安裝: Downloading the tools

  • Apple 開發人員 的下載 - 命令行工具套件提供 Apple Developer 的 下載網頁。 使用您的 Apple ID 登入,然後搜尋並下載命令列工具: Finding the Command Line Tools

安裝命令行工具之後,我們已準備好繼續進行逐步解說。

逐步解說

在本逐步解說中,我們將討論下列步驟:

  • 建立靜態庫 - 此步驟牽涉到建立 InfColorPickerObjective-C 程式代碼的靜態連結庫。 靜態庫會有 .a 擴展名,而且會內嵌到連結庫專案的 .NET 元件中。
  • 建立 Xamarin.iOS 系結專案 - 一旦有靜態庫,我們將用它來建立 Xamarin.iOS 系結專案。 系結專案是由我們剛才建立的靜態庫和 C# 程式代碼形式的元數據所組成,說明如何使用 Objective-C API。 此元數據通常稱為 API 定義。 我們將使用 Objective Sharpie 來協助我們建立 API 定義。
  • 將 API 定義 正規化 - Objective Sharpie 會執行協助我們的絕佳工作,但無法執行所有作業。 我們將討論一些我們需要對 API 定義進行的變更,才能使用它們。
  • 使用系結連結庫 - 最後,我們將建立 Xamarin.iOS 應用程式來示範如何使用新建立的系結專案。

既然我們瞭解涉及哪些步驟,讓我們繼續進行其餘的逐步解說。

建立靜態庫

如果我們檢查 Github 中 InfColorPicker 的程式代碼:

Inspect the code for InfColorPicker in Github

我們可以在專案中看到下列三個目錄:

  • InfColorPicker - 此目錄包含 Objective-C 項目的程式代碼。
  • PickerSamplePad - 此目錄包含範例 iPad 專案。
  • PickerSample 電話 - 此目錄包含範例 i 電話 專案。

讓我們從 GitHub 下載 InfColorPicker 專案,並將其解壓縮到您選擇的目錄中。 開啟專案的 Xcode 目標 PickerSamplePhone ,我們會在 Xcode Navigator 中看到下列項目結構:

The project structure in the Xcode Navigator

此專案可藉由將 InfColorPicker 原始碼(在紅色方塊中)直接新增至每個範例專案,以達到程式代碼重複使用。 範例專案的程式代碼位於藍色方塊內。 由於此特定專案未提供靜態庫,因此必須建立 Xcode 專案來編譯靜態庫。

第一個步驟是讓我們將 InfoColorPicker 原始程式碼新增至靜態庫。 若要達成此目的,讓我們執行下列動作:

  1. 啟動 Xcode。

  2. 從 [檔案] 功能表中,選取 [新增>專案...]:

    Screenshot shows Project selected from the New menu of the File menu.

  3. 選取 [架構與連結庫]、[Cocoa Touch Static Library] 範本,然後按兩下 [下一步] 按鈕:

    Select the Cocoa Touch Static Library template

  4. 針對 [項目名稱] 輸入 InfColorPicker ,然後按下一步[ 下一步] 按鈕:

    Enter InfColorPicker for the Project Name

  5. 選取要儲存專案的位置,然後按下 [ 確定] 按鈕。

  6. 現在,我們需要將來源從 InfColorPicker 專案新增至靜態庫專案。 因為 InfColorPicker.h 檔案已存在於靜態庫中(根據預設),因此 Xcode 不允許我們覆寫它。 從 Finder,流覽至從 GitHub 解壓縮的原始專案中的 InfColorPicker 原始程式碼,複製所有 InfColorPicker 檔案,並將其貼到新的靜態庫專案中:

    Copy all of the InfColorPicker files

  7. 返回 Xcode,以滑鼠右鍵按兩下 InfColorPicker 資料夾,然後選取 [ 將檔案新增至 “InfColorPicker...”

    Adding files

  8. 從 [新增檔案] 對話框,瀏覽至我們剛才複製的 InfColorPicker 原始碼檔案,選取它們全部,然後按兩下 [ 新增 ] 按鈕:

    Select all and click the Add button

  9. 原始碼將會複製到我們的專案中:

    The source code will be copied into the project

  10. 從 Xcode 專案導覽器中,選取 InfColorPicker.m 檔案並批注出最後兩行(因為撰寫此連結庫的方式,因此不會使用此檔案):

    Editing the InfColorPicker.m file

  11. 我們現在需要檢查連結庫是否需要任何架構。 您可以在自述檔中找到這項資訊,或開啟提供的其中一個範例專案。 此範例會使用 Foundation.frameworkUIKit.frameworkCoreGraphics.framework ,讓我們新增它們。

  12. 選取 InfColorPicker 目標 > 建置階段 ,然後展開 [ 連結二進位與連結庫 ] 區段:

    Expand the Link Binary With Libraries section

  13. +使用 按鈕開啟對話框,讓您新增上面所列的必要框架架構:

    Add the required frames frameworks listed above

  14. [ 鏈接二進位與連結庫 ] 區段現在看起來應該像下圖:

    The Link Binary With Libraries section

此時我們很接近,但我們並沒有完全完成。 靜態庫已建立,但我們需要建置它,以建立 Fat 二進位檔,其中包含 iOS 裝置和 iOS 模擬器所需的所有架構。

建立 Fat 二進位檔

所有 iOS 裝置都有由經過一段時間開發的 ARM 架構所支援的處理器。 每個新架構都新增了新的指示和其他改善,同時仍維持回溯相容性。 iOS 裝置具有armv6、armv7、armv7s、arm64 指令集 –雖然armv6 不再使用。 iOS 模擬器不是由 ARM 提供電源,而是 x86 和 x86_64電源模擬器。 這表示必須為每個指令集提供連結庫。

Fat 連結庫是 .a 包含所有支援架構的檔案。

建立胖二進位檔是三個步驟的程式:

  • 編譯靜態庫的 ARM 7 和 ARM64 版本。
  • 編譯 x86 和x84_64版本的靜態庫。
  • lipo使用命令行工具,將兩個靜態庫合併成一個。

雖然這三個步驟相當簡單,但在連結庫收到更新或我們需要錯誤修正時 Objective-C ,可能需要在未來重複這些步驟。 如果您決定將這些步驟自動化,它會簡化 iOS 系結專案的未來維護和支援。

有許多工具可用來自動化這類工作 - 殼層腳本、 rakexbuild 和 make。 安裝 Xcode 命令行工具時, make 也會安裝 ,因此這是將用於本逐步解說的建置系統。 以下是一個 Makefile ,可用來建立可在 iOS 裝置上運作的多架構共用連結庫,以及任何連結庫的模擬器:

XBUILD=/Applications/Xcode.app/Contents/Developer/usr/bin/xcodebuild
PROJECT_ROOT=./YOUR-PROJECT-NAME
PROJECT=$(PROJECT_ROOT)/YOUR-PROJECT-NAME.xcodeproj
TARGET=YOUR-PROJECT-NAME

all: lib$(TARGET).a

lib$(TARGET)-i386.a:
	$(XBUILD) -project $(PROJECT) -target $(TARGET) -sdk iphonesimulator -configuration Release clean build
	-mv $(PROJECT_ROOT)/build/Release-iphonesimulator/lib$(TARGET).a $@

lib$(TARGET)-armv7.a:
	$(XBUILD) -project $(PROJECT) -target $(TARGET) -sdk iphoneos -arch armv7 -configuration Release clean build
	-mv $(PROJECT_ROOT)/build/Release-iphoneos/lib$(TARGET).a $@

lib$(TARGET)-arm64.a:
	$(XBUILD) -project $(PROJECT) -target $(TARGET) -sdk iphoneos -arch arm64 -configuration Release clean build
	-mv $(PROJECT_ROOT)/build/Release-iphoneos/lib$(TARGET).a $@

lib$(TARGET).a: lib$(TARGET)-i386.a lib$(TARGET)-armv7.a lib$(TARGET)-arm64.a
	xcrun -sdk iphoneos lipo -create -output $@ $^

clean:
	-rm -f *.a *.dll

您選擇的純文本編輯器中輸入 Makefile 命令,並以 YOUR-PROJECT-NAME 更新區段,並以專案名稱更新這些區段。 請務必確保完全貼上上述指示,並保留指示內的索引標籤。

將名稱 Makefile 的檔案儲存到與上述所建立 InfColorPicker Xcode 靜態庫相同的位置:

Save the file with the name Makefile

開啟 Mac 上的終端機應用程式,並流覽至 Makefile 的位置。 輸入 make 終端機,按 Enter 鍵, 然後執行 Makefile

Sample makefile output

當您執行 Make 時,您會看到許多文字捲動。 如果一切正常運作,您會看到 BUILD SUCCEEDEDlibInfColorPicker-armv7.a檔案libInfColorPickerSDK.alibInfColorPicker-i386.a會複製到與 Makefile 相同的位置

The libInfColorPicker-armv7.a, libInfColorPicker-i386.a and libInfColorPickerSDK.a files generated by the Makefile

您可以使用下列命令來確認 Fat 二進位檔內的架構:

xcrun -sdk iphoneos lipo -info libInfColorPicker.a

這應該會顯示下列內容:

Architectures in the fat file: libInfColorPicker.a are: i386 armv7 x86_64 arm64

此時,我們已完成 iOS 系結的第一個步驟,方法是使用 Xcode 和 Xcode 命令行工具和 make lipo建立靜態庫。 讓我們移至下一個步驟,並使用 Objective-Sharpie 來自動為我們建立 API 系結。

建立 Xamarin.iOS 系結專案

在我們可以使用 Objective-Sharpie 將系結程式自動化之前,我們需要建立 Xamarin.iOS 系結專案來存放 API 定義(我們將使用 Objective-Sharpie 來協助我們建置),併為我們建立 C# 系結。

讓我們執行下列動作:

  1. 啟動 Visual Studio for Mac。

  2. 從 [檔案] 選單中,選取 [新增>解決方案...]:

    Starting a new solution

  3. 從 [新增方案] 對話框中,選取 [鏈接庫>iOS 系結專案]:

    Select iOS Binding Project

  4. 按一下 [下一步] 按鈕。

  5. 輸入 “InfColorPickerBinding” 作為 [專案名稱 ],然後按兩下 [ 建立 ] 按鈕以建立方案:

    Enter InfColorPickerBinding as the Project Name

將會建立解決方案,並包含兩個預設檔案:

The solution structure in the Solution Explorer

  • ApiDefinition.cs - 此檔案將包含定義 Objective-C API 如何包裝在 C# 中的合約。
  • Structs.cs - 此檔案會保存介面和委派所需的任何結構或列舉值。

我們將在稍後的逐步解說中使用這兩個檔案。 首先,我們需要將 InfColorPicker 連結庫新增至系結專案。

在系結專案中加入靜態庫

現在我們已經備妥基底系結項目,我們需要新增我們針對 InfColorPicker 連結庫所建立的 Fat Binary 連結庫。

請遵循下列步驟來新增連結庫:

  1. 以滑鼠右鍵按兩下 Solution Pad 中的 [原生參考 ] 資料夾,然後選取 [ 新增原生參考]:

    Add Native References

  2. 瀏覽至我們稍早製作的 [胖二進位檔],libInfColorPickerSDK.a然後按 [ 開啟 ] 按鈕:

    Select the libInfColorPickerSDK.a file

  3. 檔案將會包含在專案中:

    Including a file

將 .a 檔案新增至專案時,Xamarin.iOS 會自動將檔案的建置動作設定ObjcBindingNativeLibrary,並建立名為 libInfColorPickerSDK.linkwith.cs的特殊檔案。

此檔案包含 LinkWith 屬性,告知 Xamarin.iOS 如何處理我們剛才新增的靜態庫。 此檔案的內容會顯示在下列代碼段:

using ObjCRuntime;

[assembly: LinkWith ("libInfColorPickerSDK.a", SmartLink = true, ForceLoad = true)]

屬性 LinkWith 會識別專案的靜態連結庫和一些重要的連結器旗標。

我們需要做的下一件事是建立 InfColorPicker 專案的 API 定義。 為了本逐步解說的目的,我們將使用 Objective Sharpie 來產生檔案 ApiDefinition.cs

使用 Objective Sharpie

Objective Sharpie 是命令行工具(由 Xamarin 提供),可協助建立將第三方 Objective-C 連結庫系結至 C# 所需的定義。 在本節中,我們將使用 Objective Sharpie 建立 InfColorPicker 專案的初始 ApiDefinition.cs

若要開始使用,讓我們下載 Objective Sharpie 安裝程式檔案,如本指南所述。 執行安裝程式,並遵循安裝精靈中的所有螢幕上提示,在我們的開發計算機上安裝 Objective Sharpie。

成功安裝 Objective Sharpie 之後,讓我們啟動終端機應用程式,並輸入下列命令以取得其提供以協助系結之所有工具的說明:

sharpie -help

如果我們執行上述命令,將會產生下列輸出:

Europa:Resources kmullins$ sharpie -help
usage: sharpie [OPTIONS] TOOL [TOOL_OPTIONS]

Options:
  -h, --helpShow detailed help
  -v, --versionShow version information

Available Tools:
  xcode              Get information about Xcode installations and available SDKs.
  pod                Create a Xamarin C# binding to Objective-C CocoaPods
  bind               Create a Xamarin C# binding to Objective-C APIs
  update             Update to the latest release of Objective Sharpie
  verify-docs        Show cross reference documentation for [Verify] attributes
  docs               Open the Objective Sharpie online documentation

為了進行本逐步解說,我們將使用下列 Objective Sharpie 工具:

  • xcode - 此工具提供我們目前 Xcode 安裝的相關信息,以及我們已安裝的 iOS 和 Mac API 版本。 我們稍後會在產生系結時使用這項資訊。
  • bind - 我們將使用此工具,將 InfColorPicker 專案中的 .h 檔案剖析為初始ApiDefinition.csStructsAndEnums.cs檔案。

若要取得特定 Objective Sharpie 工具的說明,請輸入工具的名稱和 -help 選項。 例如, sharpie xcode -help 傳回下列輸出:

Europa:Resources kmullins$ sharpie xcode -help
usage: sharpie xcode [OPTIONS]+

Options:
  -h, -help           Show detailed help
  -v, -verbose        Be verbose with output

Xcode Options:
  -sdks               List all available Xcode SDKs. Pass -verbose for more
                        details.
  -sdkpath SDK        Output the path of the SDK
  -frameworks SDK     List all available framework directories in a given SDK.

在開始系結程式之前,我們需要在終端 sharpie xcode -sdks機中輸入下列命令,以取得目前已安裝 SDK 的相關信息:

amyb:Desktop amyb$ sharpie xcode -sdks
sdk: appletvos9.2    arch: arm64
sdk: iphoneos9.3     arch: arm64   armv7
sdk: macosx10.11     arch: x86_64  i386
sdk: watchos2.2      arch: armv7

從上述內容中,我們可以看到計算機上已安裝 iphoneos9.3 SDK。 有了這項資訊,我們就可以將 InfColorPicker 專案 .h 檔剖析成初始 ApiDefinition.cs 以及 StructsAndEnums.cs InfColorPicker 專案。

在終端機應用程式中輸入下列命令:

sharpie bind --output=InfColorPicker --namespace=InfColorPicker --sdk=[iphone-os] -scope [full-path-to-project]/InfColorPicker/InfColorPicker [full-path-to-project]/InfColorPicker/InfColorPicker/*.h

其中 [full-path-to-project] 是 InfColorPicker Xcode 專案檔位於電腦所在目錄的完整路徑,而 [iphone-os] 是我們安裝的 iOS SDK,如 命令所sharpie xcode -sdks指出。 請注意,在此範例中,我們傳遞 了 *.h 作為參數,其中包含 此目錄中的所有 頭檔 - 通常您不應該這麼做,而是仔細閱讀頭檔,以尋找參考所有其他相關檔案的最上層 .h 檔案,並直接傳遞至 Objective Sharpie。

提示

針對 自 -scope 變數,傳入具有您要系結之標頭的資料夾。 如果沒有 自 -scope 變數,Objective Sharpie 會嘗試為匯入的任何 iOS SDK 標頭產生系結,例如 #import <UIKit.h>,導致編譯系結專案時可能會產生錯誤的龐大定義檔案。 設定自變數之後 -scope ,Objective Sharpie 將不會為範圍資料夾以外的任何標頭產生系結。

終端機中會產生下列 輸出

Europa:Resources kmullins$ sharpie bind -output InfColorPicker -namespace InfColorPicker -sdk iphoneos8.1 /Users/kmullins/Projects/InfColorPicker/InfColorPicker/InfColorPicker.h -unified
Compiler configuration:
    -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk -miphoneos-version-min=8.1 -resource-dir /Library/Frameworks/ObjectiveSharpie.framework/Versions/1.1.1/clang-resources -arch armv7 -ObjC

[  0%] parsing /Users/kmullins/Projects/InfColorPicker/InfColorPicker/InfColorPicker.h
In file included from /Users/kmullins/Projects/InfColorPicker/InfColorPicker/InfColorPicker.h:60:
/Users/kmullins/Projects/InfColorPicker/InfColorPicker/InfColorPickerController.h:28:1: warning: no 'assign',
      'retain', or 'copy' attribute is specified - 'assign' is assumed [-Wobjc-property-no-attribute]
@property (nonatomic) UIColor* sourceColor;
^
/Users/kmullins/Projects/InfColorPicker/InfColorPicker/InfColorPickerController.h:28:1: warning: default property
      attribute 'assign' not appropriate for non-GC object [-Wobjc-property-no-attribute]
/Users/kmullins/Projects/InfColorPicker/InfColorPicker/InfColorPickerController.h:29:1: warning: no 'assign',
      'retain', or 'copy' attribute is specified - 'assign' is assumed [-Wobjc-property-no-attribute]
@property (nonatomic) UIColor* resultColor;
^
/Users/kmullins/Projects/InfColorPicker/InfColorPicker/InfColorPickerController.h:29:1: warning: default property
      attribute 'assign' not appropriate for non-GC object [-Wobjc-property-no-attribute]
4 warnings generated.
[100%] parsing complete
[bind] InfColorPicker.cs
Europa:Resources kmullins$

InfColorPicker.enums.cs和InfColorPicker.cs檔案將會在我們的目錄中建立:

The InfColorPicker.enums.cs and InfColorPicker.cs files

在上述建立的 Binding 項目中開啟這兩個檔案。 複製InfColorPicker.cs檔案的內容,並將其貼到ApiDefinition.cs檔案中,將現有的namespace ...程式代碼區塊取代為InfColorPicker.cs檔案的內容(讓using語句保持不變):

The InfColorPickerControllerDelegate file

標準化 API 定義

Objective Sharpie 有時有轉譯 Delegates的問題,因此我們必須修改 介面的定義 InfColorPickerControllerDelegate ,並以下列程式代碼取代 [Protocol, Model] 行:

[BaseType(typeof(NSObject))]
[Model]

如此一來,定義看起來會像這樣:

The definition

接下來,我們會對檔案的內容 InfColorPicker.enums.cs 執行相同的動作,複製並貼到檔案中 StructsAndEnums.cs ,讓 using 語句保持不變:

The contents the StructsAndEnums.cs file

您也可以發現 Objective Sharpie 已使用 [Verify] 屬性標註系結。 這些屬性表示您應該藉由比較系結與原始 C/Objective-C 宣告來驗證 Objective Sharpie 執行正確的動作(將在系結宣告上方的批注中提供)。 驗證系結之後,您應該移除 verify 屬性。 如需詳細資訊,請參閱 驗證 指南。

此時,我們的系結項目應該已完成並準備好建置。 讓我們建置我們的系結專案,並確定我們最終不會發生任何錯誤:

建置系結專案,並確定沒有任何錯誤

使用系結

請遵循下列步驟來建立範例 i 電話 應用程式,以使用上面建立的 iOS 系結連結庫:

  1. 建立 Xamarin.iOS 專案 - 將名為 InfColorPickerSample 的新 Xamarin.iOS 專案新增至解決方案,如下列螢幕快照所示:

    Adding a Single View App

    Setting the Identifier

  2. 新增系結項目的參考 - 更新 InfColorPickerSample 專案,使其具有 InfColorPickerBinding 項目的參考

    Adding Reference to the Binding Project

  3. 建立 i 電話 使用者介面 - 按兩下 InfColorPickerSample 專案中的 MainStoryboard.storyboard 檔案,以在 iOS 設計工具中編輯它。 將 Button 新增至檢視並呼叫它ChangeColorButton,如下所示:

    Adding a Button to the view

  4. 新增 InfColorPickerView.xib - InfColorPicker Objective-C 連結庫包含 .xib 檔案。 Xamarin.iOS 不會在系結專案中包含這個 .xib ,這會導致範例應用程式中的運行時間錯誤。 其因應措施是將 .xib 檔案新增至 Xamarin.iOS 專案。 選取 Xamarin.iOS 專案,以滑鼠右鍵按下並選取 [新增>檔案],然後新增 .xib 檔案,如下列螢幕快照所示:

    Add the InfColorPickerView.xib

  5. 當系統詢問時,請將 .xib 檔案複製到專案中。

接下來,讓我們快速查看 中的 Objective-C 通訊協定,以及如何在系結和 C# 程式代碼中處理它們。

通訊協定和 Xamarin.iOS

在 中 Objective-C,通訊協定會定義可用於特定情況的方法(或訊息)。 就概念上講,它們與 C# 中的介面非常類似。 通訊協定與 C# 介面之間的 Objective-C 其中一個主要差異是通訊協定可以有選擇性方法 - 類別不需要實作的方法。 Objective-C@optional會使用 關鍵詞來指出哪些方法是選擇性的。 如需通訊協議的詳細資訊,請參閱 事件、通訊協定和委派

InfColorPickerController 有一個這類通訊協定,如下列代碼段所示:

@protocol InfColorPickerControllerDelegate

@optional

- (void) colorPickerControllerDidFinish: (InfColorPickerController*) controller;
// This is only called when the color picker is presented modally.

- (void) colorPickerControllerDidChangeColor: (InfColorPickerController*) controller;

@end

InfColorPickerController 會使用此通訊協定來通知用戶端使用者已挑選新的色彩,且 InfColorPickerController 已完成。 Objective Sharpie 對應此通訊協定,如下列代碼段所示:

[BaseType(typeof(NSObject))]
[Model]
public partial interface InfColorPickerControllerDelegate {

    [Export ("colorPickerControllerDidFinish:")]
    void ColorPickerControllerDidFinish (InfColorPickerController controller);

    [Export ("colorPickerControllerDidChangeColor:")]
    void ColorPickerControllerDidChangeColor (InfColorPickerController controller);
}

編譯系結連結庫時,Xamarin.iOS 會建立稱為 InfColorPickerControllerDelegate的抽象基類,以虛擬方法實作這個介面。

有兩種方式可以在 Xamarin.iOS 應用程式中實作這個介面:

  • 強委派 - 使用強委派 牽涉到建立 C# 類別,以子類別 InfColorPickerControllerDelegate 和覆寫適當的方法。 InfColorPickerController 會使用此類別的實例與其客戶端通訊。
  • 弱式委派 - 弱式委派是一種稍微不同的技術,涉及在某些類別上建立公用方法(例如 InfColorPickerSampleViewController),然後透過 Export 屬性將該方法公開至InfColorPickerDelegate通訊協定。

強委派提供 Intellisense、類型安全性,以及更佳的封裝。 基於這些原因,您應該使用強委派,而不是弱式委派。

在本逐步解說中,我們將討論這兩種技術:先實作強委派,然後說明如何實作弱式委派。

實作強委派

使用強委派來回應 colorPickerControllerDidFinish: 訊息,以完成 Xamarin.iOS 應用程式:

子類別 InfColorPickerControllerDelegate - 將新類別新增至名為 ColorSelectedDelegate的專案。 編輯類別,使其具有下列程式代碼:

using InfColorPickerBinding;
using UIKit;

namespace InfColorPickerSample
{
  public class ColorSelectedDelegate:InfColorPickerControllerDelegate
  {
    readonly UIViewController parent;

    public ColorSelectedDelegate (UIViewController parent)
    {
      this.parent = parent;
    }

    public override void ColorPickerControllerDidFinish (InfColorPickerController controller)
    {
      parent.View.BackgroundColor = controller.ResultColor;
      parent.DismissViewController (false, null);
    }
  }
}

Xamarin.iOS 會藉由建立稱為 InfColorPickerControllerDelegate的抽象基類來Objective-C系結委派。 這個型別的 ColorPickerControllerDidFinish 子類別,並覆寫 方法來存取 ResultColor 的屬性值 InfColorPickerController

建立 ColorSelectedDelegate 的實例 - 我們的事件處理程式將需要我們在上一個步驟中建立的類型 ColorSelectedDelegate 實例。 編輯 類別 InfColorPickerSampleViewController ,並將下列實例變數新增至 類別:

ColorSelectedDelegate selector;

初始化 ColorSelectedDelegate 變數 - 若要確保selector為有效的實例,請更新 中的 ViewController 方法ViewDidLoad以符合下列代碼段:

public override void ViewDidLoad ()
{
  base.ViewDidLoad ();
  ChangeColorButton.TouchUpInside += HandleTouchUpInsideWithStrongDelegate;
  selector = new ColorSelectedDelegate (this);
}

實作 HandleTouchUpInsideWithStrongDelegate 方法 - 下一步會在使用者觸碰 ColorChangeButton 時實作 的事件處理程式。 編輯 ViewController,並新增下列方法:

using InfColorPicker;
...

private void HandleTouchUpInsideWithStrongDelegate (object sender, EventArgs e)
{
    InfColorPickerController picker = InfColorPickerController.ColorPickerViewController();
    picker.Delegate = selector;
    picker.PresentModallyOverViewController (this);
}

我們先透過靜態方法取得的 InfColorPickerController 實例,並透過 屬性 InfColorPickerController.Delegate知道強委派。 Objective Sharpie 會自動為我們產生這個屬性。 最後,我們呼叫 PresentModallyOverViewController 來顯示檢視 InfColorPickerSampleViewController.xib ,讓使用者可以選取色彩。

執行應用程式 - 此時,我們已完成所有程序代碼。 如果您執行應用程式,您應該能夠變更 的背景色彩 InfColorColorPickerSampleView ,如下列螢幕快照所示:

Running the Application

恭喜! 此時,您已成功建立並系結 Objective-C 連結庫以用於 Xamarin.iOS 應用程式。 接下來,讓我們來瞭解如何使用弱式委派。

實作弱式委派

Xamarin.iOS 除了將系結至特定委派之通訊協定的 Objective-C 類別進行子類別化,也可讓您在任何衍生自 NSObject的類別中實作通訊協定方法,以 裝飾您的方法 ExportAttribute,然後提供適當的選取器。 當您採用此方法時,您會將 類別的實例指派給 屬性, WeakDelegate 而不是 指派給 Delegate 屬性。 弱式委派可讓您彈性地將委派類別帶下不同的繼承階層。 讓我們看看如何在 Xamarin.iOS 應用程式中實作和使用弱式委派。

建立 TouchUpInside 的事件處理程式 - 讓我們為 TouchUpInside [變更背景色彩] 按鈕的事件建立新的事件處理程式。 此處理程式會填入與我們在上一節中建立的 HandleTouchUpInsideWithStrongDelegate 處理程式相同的角色,但會使用弱式委派,而不是強委派。 編輯 類別 ViewController,並新增下列方法:

private void HandleTouchUpInsideWithWeakDelegate (object sender, EventArgs e)
{
    InfColorPickerController picker = InfColorPickerController.ColorPickerViewController();
    picker.WeakDelegate = this;
    picker.SourceColor = this.View.BackgroundColor;
    picker.PresentModallyOverViewController (this);
}

更新 ViewDidLoad - 我們必須變更 ViewDidLoad ,讓它使用剛才建立的事件處理程式。 編輯 ViewController 並變更 ViewDidLoad 為類似下列代碼段:

public override void ViewDidLoad ()
{
    base.ViewDidLoad ();
    ChangeColorButton.TouchUpInside += HandleTouchUpInsideWithWeakDelegate;
}

處理 colorPickerControllerDidFinish:Message - 完成時 ViewController ,iOS 會將訊息 colorPickerControllerDidFinish: 傳送至 WeakDelegate。 我們需要建立可處理此訊息的 C# 方法。 若要這樣做,我們會建立 C# 方法,然後使用 加以 ExportAttribute裝飾。 編輯 ViewController,並將下列方法新增至 類別:

[Export("colorPickerControllerDidFinish:")]
public void ColorPickerControllerDidFinish (InfColorPickerController controller)
{
    View.BackgroundColor = controller.ResultColor;
    DismissViewController (false, null);
}

執行應用程式。 它現在的行為應該與之前完全相同,但它使用弱式委派,而不是強委派。 此時,您已成功完成本逐步解說。 您現在應該已瞭解如何建立及取用 Xamarin.iOS 系結專案。

摘要

本文逐步解說了建立和使用 Xamarin.iOS 系結項目的程式。 首先,我們已討論如何將現有的 Objective-C 連結庫編譯成靜態庫。 然後,我們討論如何建立 Xamarin.iOS 系結專案,以及如何使用 Objective Sharpie 來產生連結庫的 Objective-C API 定義。 我們已討論如何更新和調整產生的 API 定義,使其適合用於公用取用。 完成 Xamarin.iOS 系結專案之後,我們繼續在 Xamarin.iOS 應用程式中取用該系結,重點是使用強委派和弱式委派。