Udostępnij za pośrednictwem


Objective-C Omówienie powiązań

Szczegółowe informacje o sposobie działania procesu powiązania

Objective-C Powiązanie biblioteki do użycia z platformą Xamarin obejmuje trzy kroki:

  1. Napisz definicję interfejsu API języka C#, aby opisać sposób uwidocznienia natywnego interfejsu API na platformie .NET i sposobu mapowania go na bazowe Objective-C. Odbywa się to przy użyciu standardowych konstrukcji języka C#, takich jak interface i różnych atrybutów powiązania (zobacz ten prosty przykład).

  2. Po napisaniu "definicji interfejsu API" w języku C#skompilujesz go w celu utworzenia zestawu "powiązania". Można to zrobić w wierszu polecenia lub przy użyciu projektu powiązania w Visual Studio dla komputerów Mac lub Visual Studio.

  3. Ten zestaw "wiązanie" jest następnie dodawany do projektu aplikacji platformy Xamarin, dzięki czemu można uzyskać dostęp do funkcji natywnej przy użyciu zdefiniowanego interfejsu API. Projekt powiązania jest całkowicie oddzielony od projektów aplikacji.

    Uwaga

    Krok 1 można zautomatyzować za pomocą aplikacji Objective Sharpie. Analizuje Objective-C interfejs API i generuje proponowany język C# "Definicja interfejsu API". Możesz dostosować pliki utworzone przez aplikację Objective Sharpie i użyć ich w projekcie powiązania (lub w wierszu polecenia), aby utworzyć zestaw powiązania. Objective Sharpie nie tworzy powiązań samodzielnie, jest to tylko opcjonalna część większego procesu.

Możesz również zapoznać się z bardziej szczegółowymi informacjami technicznymi dotyczącymi sposobu jego działania, co pomoże Ci w pisaniu powiązań.

Powiązania wiersza polecenia

Możesz użyć narzędzia btouch-native dla platformy Xamarin.iOS (lub bmac-native jeśli używasz platformy Xamarin.Mac) do bezpośredniego kompilowania powiązań. Działa przez przekazanie definicji interfejsu API języka C#utworzonych ręcznie (lub przy użyciu narzędzia Objective Sharpie) do narzędzia wiersza polecenia (btouch-native dla systemu iOS lub bmac-native mac).

Ogólna składnia wywoływania tych narzędzi to:

# 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

Powyższe polecenie spowoduje wygenerowanie pliku cocos2d.dll w bieżącym katalogu i będzie zawierać w pełni powiązaną bibliotekę, której można użyć w projekcie. Jest to narzędzie, które Visual Studio dla komputerów Mac używa do tworzenia powiązań, jeśli używasz projektu powiązania (opisanego poniżej).

Wiązanie projektu

Projekt powiązania można utworzyć w programie Visual Studio dla komputerów Mac lub Visual Studio (program Visual Studio obsługuje tylko powiązania systemu iOS) i ułatwia edytowanie i kompilowanie definicji interfejsu API dla powiązania (a nie przy użyciu wiersza polecenia).

Postępuj zgodnie z tym przewodnikiem wprowadzającym, aby dowiedzieć się, jak utworzyć i użyć projektu powiązania do utworzenia powiązania.

Narzędzie Objective Sharpie

Objective Sharpie to kolejne, oddzielne narzędzie wiersza polecenia, które pomaga w początkowych etapach tworzenia powiązania. Nie tworzy powiązania samodzielnie, a raczej automatyzuje początkowy krok generowania definicji interfejsu API dla docelowej biblioteki natywnej.

Zapoznaj się z dokumentami Objective Sharpie, aby dowiedzieć się, jak analizować biblioteki natywne, struktury natywne i cocoaPods w defintions interfejsu API, które mogą być wbudowane w powiązania.

Jak działa powiązanie

Można użyć atrybutu [Register], atrybutu [Export] i wywołania selektora ręcznego Objective-C w celu ręcznego powiązania nowych (wcześniej niezwiązanych) Objective-C typów.

Najpierw znajdź typ, który chcesz powiązać. Dla celów dyskusji (i uproszczenia) powiążemy typ NSEnumerator (który został już powiązany w foundation.NSEnumerator; implementacja poniżej jest tylko na przykład).

Po drugie, musimy utworzyć typ języka C#. Prawdopodobnie chcemy umieścić to w przestrzeni nazw; ponieważ Objective-C nie obsługuje przestrzeni nazw, musimy użyć atrybutu [Register] , aby zmienić nazwę typu zarejestrowaną w środowisku uruchomieniowym platformy Objective-C Xamarin.iOS. Typ języka C# musi również dziedziczyć z obiektu Foundation.NSObject:

namespace Example.Binding {
    [Register("NSEnumerator")]
    class NSEnumerator : NSObject
    {
        // see steps 3-5
    }
}

Po trzecie zapoznaj się z dokumentacją Objective-C i utwórz wystąpienia ObjCRuntime.Selector dla każdego selektora, którego chcesz użyć. Umieść je w treści klasy:

static Selector selInit       = new Selector("init");
static Selector selAllObjects = new Selector("allObjects");
static Selector selNextObject = new Selector("nextObject");

Po czwarte, typ będzie musiał podać konstruktory. Należy połączyć wywołanie konstruktora z konstruktorem klasy bazowej. Atrybuty [Export] umożliwiają Objective-C kod wywoływania konstruktorów z określoną nazwą selektora:

[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)
{
}

Po piąte, podaj metody dla każdego selektora zadeklarowanego w kroku 3. Będą one używane objc_msgSend() do wywoływania selektora w obiekcie natywnym. Zwróć uwagę na użycie obiektu Runtime.GetNSObject(), aby przekonwertować obiekt IntPtr na typ odpowiednio wpisany NSObject (sub-). Jeśli chcesz, aby metoda można było wywołać z Objective-C kodu, element członkowski musi być wirtualny.

[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));
    }
}

Łączenie wszystkich elementów:

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));
            }
        }
    }
}