Sdílet prostřednictvím


Objective-C Přehled vazeb

Podrobnosti o fungování procesu vazby

Vytvoření vazby Objective-C knihovny pro použití s Xamarinem provede tři kroky:

  1. Napište "definici rozhraní API" jazyka C#, která popisuje, jak je nativní rozhraní API vystaveno v .NET a jak se mapuje na podkladový Objective-C. To se provádí pomocí standardních konstruktorů jazyka C# jako interface a různých atributů vazby (viz tento jednoduchý příklad).

  2. Jakmile napíšete "definici rozhraní API" v jazyce C#, zkompilujete ho tak, aby vytvořilo sestavení "binding". To lze provést na příkazovém řádku nebo pomocí vazbového projektu v Visual Studio pro Mac nebo sadě Visual Studio.

  3. Toto sestavení "binding" se pak přidá do projektu aplikace Xamarin, abyste měli přístup k nativním funkcím pomocí rozhraní API, které jste definovali. Projekt vazby je zcela oddělený od projektů aplikace.

    Poznámka:

    Krok 1 lze automatizovat pomocí Objective Sharpie. Prozkoumá Objective-C rozhraní API a vygeneruje navrženou definici rozhraní API v jazyce C#. Soubory vytvořené Objective Sharpie můžete přizpůsobit a použít je v projektu vazby (nebo na příkazovém řádku) k vytvoření sestavení vazby. Objective Sharpie sama o sobě nevytová vazby, je to jen volitelná část většího procesu.

Můžete si také přečíst další technické podrobnosti o tom, jak to funguje, což vám pomůže se zápisem vazeb.

Vazby příkazového řádku

K přímému btouch-native sestavení vazeb můžete použít Xamarin.iOS (nebo bmac-native pokud používáte Xamarin.Mac). Funguje předáním definic rozhraní API jazyka C#, které jste vytvořili ručně (nebo pomocí Objective Sharpie) do nástroje příkazového řádku (btouch-native pro iOS nebo bmac-native pro Mac).

Obecná syntaxe pro vyvolání těchto nástrojů je:

# 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

Výše uvedený příkaz vygeneruje soubor cocos2d.dll v aktuálním adresáři a bude obsahovat plně vázanou knihovnu, kterou můžete použít v projektu. Toto je nástroj, který Visual Studio pro Mac používá k vytvoření vazeb, pokud používáte projekt vazby (popsaný níže).

Vytvoření vazby projektu

Projekt vazby lze vytvořit v Visual Studio pro Mac nebo sadě Visual Studio (Visual Studio podporuje pouze vazby pro iOS) a usnadňuje úpravu a vytváření definic rozhraní API pro vazbu (versus použití příkazového řádku).

Postupujte podle této úvodní příručky a zjistěte, jak vytvořit a použít projekt vazby k vytvoření vazby.

Objective Sharpie

Objective Sharpie je další samostatný nástroj příkazového řádku, který pomáhá s počátečními fázemi vytváření vazby. Nevytváří vazbu sama o sobě, ale automatizuje počáteční krok generování definice rozhraní API pro cílovou nativní knihovnu.

Přečtěte si dokumentaci Objective Sharpie a zjistěte, jak analyzovat nativní knihovny, nativní architektury a CocoaPods do definic rozhraní API, které je možné integrovat do vazeb.

Jak funguje vazba

K ručnímu vytvoření vazby nových (dříve nevázaných) Objective-C typů je možné použít atribut [Register], atribut [Export] a ruční Objective-C vyvolání selektoru.

Nejprve vyhledejte typ, který chcete svázat. Pro účely diskuze (a jednoduchost) vytvoříme vazbu typu NSEnumerator (který již byl vázán v Foundation.NSEnumerator; implementace níže je určena pouze pro příklady).

Za druhé, musíme vytvořit typ C#. Pravděpodobně to budeme chtít umístit do oboru názvů; protože Objective-C obory názvů nepodporuje, budeme muset pomocí atributu [Register] změnit název typu, který Xamarin.iOS zaregistruje Objective-C v modulu runtime. Typ C# musí také dědit ze foundation.NSObject:

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

Za třetí si projděte Objective-C dokumentaci a vytvořte instance ObjCRuntime.Selector pro každý selektor, který chcete použít. Umístěte je do těla třídy:

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

Čtvrtý typ bude muset poskytnout konstruktory. Je nutné zřetězit volání konstruktoru do konstruktoru základní třídy. Atributy [Export] umožňují Objective-C volání konstruktorů se zadaným názvem selektoru:

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

Páté, zadejte metody pro každý selektor deklarovaný v kroku 3. Ty se použijí objc_msgSend() k vyvolání selektoru v nativním objektu. Všimněte si použití runtime.GetNSObject() k převodu IntPtr na odpovídající typ NSObject (dílčí)typ. Pokud chcete, aby metoda byla voláná z Objective-C kódu, člen musí být virtuální.

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

Seskupování všech:

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