系結概觀Objective-C
系結程序運作方式的詳細數據
系 Objective-C 結連結庫以搭配 Xamarin 使用,需要三個步驟:
撰寫 C# 「API 定義」來描述原生 API 如何在 .NET 中公開,以及其如何對應至基礎 Objective-C。 這是使用標準 C# 建構完成的,例如
interface
和各種系結 屬性 (請參閱這個 簡單的範例)。在 C# 中撰寫「API 定義」之後,即可編譯它以產生「系結」元件。 這可以在命令行上完成,或在 Visual Studio for Mac 或 Visual Studio 中使用系結專案。
該「系結」元件接著會新增至您的 Xamarin 應用程式專案,因此您可以使用您定義的 API 來存取原生功能。 系結專案與應用程式專案完全分開。
注意
步驟 1 可以在 Objective Sharpie 的協助下自動化。 它會檢查 Objective-C API 併產生建議的 C# 「API 定義」。您可以自定義 Objective Sharpie 所建立的檔案,並在系結專案中使用它們來建立系結元件。 Objective Sharpie 本身不會建立系結,這隻是較大型程式的選擇性部分。
您也可以閱讀其運作方式的更多技術詳細數據,以協助您撰寫系結。
命令行系結
您可以使用 btouch-native
for Xamarin.iOS (或 bmac-native
如果您使用 Xamarin.Mac)直接建置系結。 其運作方式是將您手動建立的 C# API 定義(或使用 Objective Sharpie)傳遞至命令行工具(btouch-native
適用於 iOS 或 bmac-native
Mac)。
叫用這些工具的一般語法如下:
# Use this for Xamarin.iOS:
bash$ /Developer/MonoTouch/usr/bin/btouch-native -e cocos2d.cs -s:enums.cs -x:extensions.cs
# Use this for Xamarin.Mac:
bash$ bmac-native -e cocos2d.cs -s:enums.cs -x:extensions.cs
上述命令會在目前目錄中產生檔案 cocos2d.dll
,而且會包含您可以在專案中使用的完整系結連結庫。 如果您使用系結專案,Visual Studio for Mac 會使用此工具來建立系結專案(如下所述)。
系結專案
系結專案可以在Visual Studio for Mac 或 Visual Studio 中建立(Visual Studio 僅支援 iOS 系結),並可讓您更輕鬆地編輯和建置系結的 API 定義(而不是使用命令行)。
請遵循此 入門指南 ,瞭解如何建立和使用系結項目來產生系結。
Objective Sharpie
Objective Sharpie 是另一個獨立的命令行工具,可協助建立系結的初始階段。 它不會自行建立系結,而是自動執行為目標原生連結庫產生 API 定義的初始步驟。
閱讀 Objective Sharpie 檔,瞭解如何將原生連結庫、原生架構和 CocoaPods 剖析成可內建至系結中的 API 定義。
系結的運作方式
您可以使用 [Register] 屬性、 [匯出] 屬性和 手動 Objective-C 選取器調用 ,手動系結新的 (先前未系結) Objective-C 類型。
首先,尋找您想要系結的類型。 為了討論目的(和簡單性),我們將系結 NSEnumerator 類型(已在 Foundation.NSEnumerator 中系結;下列實作僅供範例之用)。
其次,我們需要建立 C# 類型。 我們可能會想要將此專案放入命名空間中;由於 Objective-C 不支援命名空間,因此我們必須使用 [Register]
屬性來變更 Xamarin.iOS 向運行時間註冊 Objective-C 的類型名稱。 C# 類型也必須繼承自 Foundation.NSObject:
namespace Example.Binding {
[Register("NSEnumerator")]
class NSEnumerator : NSObject
{
// see steps 3-5
}
}
第三,檢閱檔, Objective-C 並針對您想要使用的每個選取器建立 ObjCRuntime.Selector 實例。 請將這些專案放在類別主體中:
static Selector selInit = new Selector("init");
static Selector selAllObjects = new Selector("allObjects");
static Selector selNextObject = new Selector("nextObject");
第四,您的類型必須提供建構函式。 您必須將建構函式調用鏈結至基類建構函式。 屬性 [Export]
允許 Objective-C 程式代碼呼叫具有指定選取器名稱的建構函式:
[Export("init")]
public NSEnumerator()
: base(NSObjectFlag.Empty)
{
Handle = Messaging.IntPtr_objc_msgSend(this.Handle, selInit.Handle);
}
// This constructor must be present so that Xamarin.iOS
// can create instances of your type from Objective-C code.
public NSEnumerator(IntPtr handle)
: base(handle)
{
}
第五,為步驟 3 中宣告的每個選取器提供方法。 這些會用來在原生物件上叫用 objc_msgSend()
選取器。 請注意,使用 Runtime.GetNSObject() 將轉換成 IntPtr
適當類型的 NSObject
(sub-) 類型。 如果您想要從程式代碼呼叫 Objective-C 方法,成員必須是虛擬的。
[Export("nextObject")]
public virtual NSObject NextObject()
{
return Runtime.GetNSObject(
Messaging.IntPtr_objc_msgSend(this.Handle, selNextObject.Handle));
}
// Note that for properties, [Export] goes on the get/set method:
public virtual NSArray AllObjects {
[Export("allObjects")]
get {
return (NSArray) Runtime.GetNSObject(
Messaging.IntPtr_objc_msgSend(this.Handle, selAllObjects.Handle));
}
}
將所有專案放在一起:
using System;
using Foundation;
using ObjCRuntime;
namespace Example.Binding {
[Register("NSEnumerator")]
class NSEnumerator : NSObject
{
static Selector selInit = new Selector("init");
static Selector selAllObjects = new Selector("allObjects");
static Selector selNextObject = new Selector("nextObject");
[Export("init")]
public NSEnumerator()
: base(NSObjectFlag.Empty)
{
Handle = Messaging.IntPtr_objc_msgSend(this.Handle,
selInit.Handle);
}
public NSEnumerator(IntPtr handle)
: base(handle)
{
}
[Export("nextObject")]
public virtual NSObject NextObject()
{
return Runtime.GetNSObject(
Messaging.IntPtr_objc_msgSend(this.Handle,
selNextObject.Handle));
}
// Note that for properties, [Export] goes on the get/set method:
public virtual NSArray AllObjects {
[Export("allObjects")]
get {
return (NSArray) Runtime.GetNSObject(
Messaging.IntPtr_objc_msgSend(this.Handle,
selAllObjects.Handle));
}
}
}
}