共用方式為


系結概觀Objective-C

系結程序運作方式的詳細數據

系 Objective-C 結連結庫以搭配 Xamarin 使用,需要三個步驟:

  1. 撰寫 C# 「API 定義」來描述原生 API 如何在 .NET 中公開,以及其如何對應至基礎 Objective-C。 這是使用標準 C# 建構完成的,例如 interface 和各種系結 屬性 (請參閱這個 簡單的範例)。

  2. 在 C# 中撰寫「API 定義」之後,即可編譯它以產生「系結」元件。 這可以在命令行完成,或在 Visual Studio for Mac 或 Visual Studio 中使用系結專案。

  3. 該「系結」元件接著會新增至您的 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));
            }
        }
    }
}