Referenční příručka k typům vazeb

Tento dokument popisuje seznam atributů, které můžete použít k přidávání poznámek k souborům kontraktů rozhraní API pro řízení vazby a vygenerovaného kódu.

Kontrakty rozhraní API Xamarin.iOS a Xamarin.Mac se většinou zapisují v jazyce C# jako definice rozhraní, které definují způsob, jakým Objective-C se kód zobrazí v jazyce C#. Tento proces zahrnuje kombinaci deklarací rozhraní a některých základních definic typů, které může kontrakt rozhraní API vyžadovat. Úvod k typům vazeb najdete v našich doprovodných knihovnách vazebObjective-C.

Definice typů

Syntaxe:

[BaseType (typeof (BTYPE))
interface MyType : [Protocol1, Protocol2] {
     IntPtr Constructor (string foo);
}

Každé rozhraní v definici kontraktu [BaseType] , který má atribut deklaruje základní typ pro vygenerovaný objekt. Ve výše uvedené deklaraci MyType se vygeneruje typ třídy C#, který vytvoří vazbu na typ volaný Objective-CMyType.

Pokud zadáte jakékoli typy za typename (v ukázce výše Protocol1 a Protocol2) pomocí syntaxe dědičnosti rozhraní, obsah těchto rozhraní bude vložen, jako by byly součástí smlouvy pro MyType. Způsob, jakým Xamarin.iOS zobrazuje, že typ přijímá protokol, je vložením všech metod a vlastností, které byly deklarovány v protokolu do samotného typu.

Následující příklad ukazuje, jak Objective-C by deklarace byla UITextField definována ve smlouvě Xamarin.iOS:

@interface UITextField : UIControl <UITextInput> {

}

Napíšou se takto jako kontrakt rozhraní API jazyka C#:

[BaseType (typeof (UIControl))]
interface UITextField : UITextInput {
}

Mnoho dalších aspektů generování kódu můžete řídit použitím dalších atributů na rozhraní a také konfigurací atributu [BaseType] .

Generování událostí

Jednou z funkcí návrhu rozhraní API Xamarin.iOS a Xamarin.Mac je, že mapujeme Objective-C třídy delegáta jako události a zpětná volání jazyka C#. Uživatelé si můžou vybrat v jednotlivých instancích bez ohledu na to, jestli chtějí použít Objective-C programovací vzor, tím, že přiřadí vlastnosti, jako Delegate je instance třídy, která implementuje různé metody, které Objective-C modul runtime volá, nebo zvolením událostí a vlastností ve stylu C#.

Podívejme se na jeden příklad použití Objective-C modelu:

bool MakeDecision ()
{
    return true;
}

void Setup ()
{
     var scrollView = new UIScrollView (myRect);
     scrollView.Delegate = new MyScrollViewDelegate ();
     ...
}

class MyScrollViewDelegate : UIScrollViewDelegate {
    public override void Scrolled (UIScrollView scrollView)
    {
        Console.WriteLine ("Scrolled");
    }

    public override bool ShouldScrollToTop (UIScrollView scrollView)
    {
        return MakeDecision ();
    }
}

V předchozím příkladu vidíte, že jsme se rozhodli přepsat dvě metody, jedno oznámení, že došlo k události posouvání, a druhý, který je zpětným voláním, který by měl vrátit logickou hodnotu s scrollView pokynem, jestli se má posunout na začátek nebo ne.

Model jazyka C# umožňuje uživateli vaší knihovny naslouchat oznámením pomocí syntaxe událostí jazyka C# nebo syntaxe vlastností pro připojení zpětných volání, u které se očekává vrácení hodnot.

Takto vypadá kód jazyka C# pro stejnou funkci pomocí lambda:

void Setup ()
{
    var scrollview = new UIScrollView (myRect);
    // Event connection, use += and multiple events can be connected
    scrollView.Scrolled += (sender, eventArgs) { Console.WriteLine ("Scrolled"); }

    // Property connection, use = only a single callback can be used
    scrollView.ShouldScrollToTop = (sv) => MakeDecision ();
}

Vzhledem k tomu, že události nevrací hodnoty (mají návratový typ void), můžete připojit více kopií. Není ShouldScrollToTop to událost, je to spíše vlastnost s typem UIScrollViewCondition , který má tento podpis:

public delegate bool UIScrollViewCondition (UIScrollView scrollView);

Vrátí bool hodnotu, v tomto případě syntaxe lambda nám umožňuje jednoduše vrátit hodnotu z MakeDecision funkce.

Generátor vazeb podporuje generování událostíachm událostem a vlastnostem třídy, jako UIScrollView je její UIScrollViewDelegate (dobře volejte tyto třídy modelu), se provádí anotací definice [BaseType] s Events parametry a Delegates parametry (popsané níže). Kromě přidávání poznámek [BaseType] k těmto parametrům je nutné informovat generátor o několika dalších součástech.

U událostí, které přebírají více než jeden parametr (v Objective-C konvenci je to, že první parametr ve třídě delegáta je instance objektu odesílatele), musíte zadat název, který chcete, aby vygenerovaná EventArgs třída byla. To se provádí s atributem [EventArgs] deklarace metody ve vaší třídě Modelu. Příklad:

[BaseType (typeof (UINavigationControllerDelegate))]
[Model][Protocol]
public interface UIImagePickerControllerDelegate {
    [Export ("imagePickerController:didFinishPickingImage:editingInfo:"), EventArgs ("UIImagePickerImagePicked")]
    void FinishedPickingImage (UIImagePickerController picker, UIImage image, NSDictionary editingInfo);
}

Výše uvedená deklarace vygeneruje UIImagePickerImagePickedEventArgs třídu, která je odvozena z EventArgs obou parametrů UIImage , a také NSDictionary. Generátor vytvoří toto:

public partial class UIImagePickerImagePickedEventArgs : EventArgs {
    public UIImagePickerImagePickedEventArgs (UIImage image, NSDictionary editingInfo);
    public UIImage Image { get; set; }
    public NSDictionary EditingInfo { get; set; }
}

Pak zveřejňuje následující položky ve UIImagePickerController třídě:

public event EventHandler<UIImagePickerImagePickedEventArgs> FinishedPickingImage { add; remove; }

Metody modelu, které vracejí hodnotu, jsou vázány odlišně. Ty vyžadují jak název vygenerovaného delegáta jazyka C# (podpis pro metodu), tak i výchozí hodnotu, která se má vrátit v případě, že uživatel neposkytuje implementaci. Definice je například ShouldScrollToTop následující:

[BaseType (typeof (NSObject))]
[Model][Protocol]
public interface UIScrollViewDelegate {
    [Export ("scrollViewShouldScrollToTop:"), DelegateName ("UIScrollViewCondition"), DefaultValue ("true")]
    bool ShouldScrollToTop (UIScrollView scrollView);
}

Výše uvedený příkaz vytvoří UIScrollViewCondition delegáta s podpisem, který byl uveden výše, a pokud uživatel neposkytuje implementaci, návratová hodnota bude pravdivá.

Kromě atributu [DefaultValue] můžete také použít [DefaultValueFromArgument] atribut, který směruje generátor k vrácení hodnoty zadaného parametru [NoDefaultValue] ve volání nebo parametru, který dává generátoru pokyn, že neexistuje výchozí hodnota.

BaseTypeAttribute

Syntaxe:

public class BaseTypeAttribute : Attribute {
        public BaseTypeAttribute (Type t);

        // Properties
        public Type BaseType { get; set; }
        public string Name { get; set; }
        public Type [] Events { get; set; }
        public string [] Delegates { get; set; }
        public string KeepRefUntil { get; set; }
}

BaseType.Name

Vlastnost slouží Name k řízení názvu, ke kterému bude tento typ vázán na Objective-C světě. Obvykle se používá k zadání názvu typu jazyka C#, který je kompatibilní s pokyny pro návrh rozhraní .NET Framework, ale který se mapuje na název v Objective-C souladu s touto konvencí.

V následujícím případě namapujeme Objective-CNSURLConnection typ na NSUrlConnection, jako pokyny pro návrh rozhraní .NET Framework místo adresy URL použijte adresu URL:

[BaseType (typeof (NSObject), Name="NSURLConnection")]
interface NSUrlConnection {
}

Zadaný název se používá jako hodnota pro vygenerovaný [Register] atribut v vazbě. Pokud Name není zadán, krátký název typu se použije jako hodnota atributu [Register] ve vygenerovaném výstupu.

BaseType.Events a BaseType.Delegates

Tyto vlastnosti slouží k řízení generování událostí ve stylu jazyka C#ve generovaných třídách. Slouží k propojení dané třídy se třídou Objective-C delegáta. Narazíte na mnoho případů, kdy třída používá třídu delegáta k odesílání oznámení a událostí. Například BarcodeScanner by měla doprovodnou BardodeScannerDelegate třídu. Třída BarcodeScanner obvykle má Delegate vlastnost, ke které byste přiřadili instanci BarcodeScannerDelegate , zatímco to funguje, můžete chtít zpřístupnit uživatelům rozhraní událostí podobné jazyku C#, a v takových případech byste použili Events a Delegates vlastnosti atributu [BaseType] .

Tyto vlastnosti jsou vždy nastavené společně a musí mít stejný počet prvků a musí být synchronizované. Pole Delegates obsahuje jeden řetězec pro každého slabě napsaného delegáta, kterého chcete zabalit, a Events pole obsahuje jeden typ pro každý typ, který chcete k němu přidružit.

[BaseType (typeof (NSObject),
           Delegates=new string [] { "WeakDelegate" },
           Events=new Type [] {typeof(UIAccelerometerDelegate)})]
public interface UIAccelerometer {
}

[BaseType (typeof (NSObject))]
[Model][Protocol]
public interface UIAccelerometerDelegate {
}

BaseType.KeepRefUntil

Pokud tento atribut použijete při vytváření nových instancí této třídy, instance tohoto objektu bude zachována po dobu, dokud metoda odkazovaná nebyla KeepRefUntil vyvolána. To je užitečné ke zlepšení použitelnosti vašich rozhraní API, pokud nechcete, aby uživatel odkaz na objekt používal váš kód. Hodnota této vlastnosti je název metody ve Delegate třídě, takže ji musíte použít v kombinaci s vlastnostmi Events a Delegates také.

Následující příklad ukazuje, jak se používá UIActionSheet v Xamarin.iOS:

[BaseType (typeof (NSObject), KeepRefUntil="Dismissed")]
[BaseType (typeof (UIView),
           KeepRefUntil="Dismissed",
           Delegates=new string [] { "WeakDelegate" },
           Events=new Type [] {typeof(UIActionSheetDelegate)})]
public interface UIActionSheet {
}

[BaseType (typeof (NSObject))]
[Model][Protocol]
public interface UIActionSheetDelegate {
    [Export ("actionSheet:didDismissWithButtonIndex:"), EventArgs ("UIButton")]
    void Dismissed (UIActionSheet actionSheet, nint buttonIndex);
}

DesignatedDefaultCtorAttribute

Pokud se tento atribut použije na definici rozhraní, vygeneruje [DesignatedInitializer] atribut u výchozího (vygenerovaného) konstruktoru init , který se mapuje na selektor.

DisableDefaultCtorAttribute

Pokud se tento atribut použije na definici rozhraní, zabrání generátoru v vytváření výchozího konstruktoru.

Tento atribut použijte, pokud potřebujete objekt inicializovat pomocí jednoho z ostatních konstruktorů ve třídě.

PrivateDefaultCtorAttribute

Pokud se tento atribut použije na definici rozhraní, označí výchozí konstruktor jako soukromý. To znamená, že stále můžete vytvořit instanci objektu této třídy interně z vašeho souboru s příponou, ale jen nebude přístupný pro uživatele vaší třídy.

CategoryAttribute

Tento atribut u definice typu slouží k vytvoření vazby Objective-C kategorií a k jejich zveřejnění jako rozšiřujících metod jazyka C#, aby zrcadlil způsob, jakým Objective-C zpřístupňuje funkce.

Kategorie jsou Objective-C mechanismus, který slouží k rozšíření sady metod a vlastností dostupných ve třídě. V praxi se používají k rozšíření funkcí základní třídy (například NSObject) v případě, že je konkrétní architektura propojena (například UIKit), zpřístupňuje jejich metody, ale pouze v případě, že je nová architektura propojena. V některých jiných případech se používají k uspořádání funkcí ve třídě podle funkcí. Jsou podobné metodám rozšíření jazyka C#.

Takto by kategorie vypadala takto Objective-C:

@interface UIView (MyUIViewExtension)
-(void) makeBackgroundRed;
@end

Výše uvedený příklad se nachází v knihovně, která by rozšířila UIView instance s metodou makeBackgroundRed.

K vytvoření vazby těchto atributů můžete použít [Category] atribut v definici rozhraní. Při použití [Category] atributu se význam atributu [BaseType] změní z použití k určení základní třídy, která se má rozšířit, na typ, který se má rozšířit.

Následující příklad ukazuje, jak UIView jsou rozšíření svázaná a převedená na metody rozšíření jazyka C#:

[BaseType (typeof (UIView))]
[Category]
interface MyUIViewExtension {
    [Export ("makeBackgroundRed")]
    void MakeBackgroundRed ();
}

Výše uvedená metoda vytvoří MyUIViewExtension třídu, která obsahuje rozšiřující metodu MakeBackgroundRed . To znamená, že teď můžete volat MakeBackgroundRed libovolnou UIView podtřídu a poskytnout vám stejné funkce, které byste získali Objective-C.

V některých případech najdete statické členy v kategoriích, jako je v následujícím příkladu:

@interface FooObject (MyFooObjectExtension)
+ (BOOL)boolMethod:(NSRange *)range;
@end

To povede k nesprávné definici rozhraní jazyka C#kategorie:

[Category]
[BaseType (typeof (FooObject))]
interface FooObject_Extensions {

    // Incorrect Interface definition
    [Static]
    [Export ("boolMethod:")]
    bool BoolMethod (NSRange range);
}

To není správné, protože k použití BoolMethod rozšíření potřebujete instanciFooObject, ale vytváříte vazbu statického rozšíření ObjC, jedná se o vedlejší účinek z důvodu toho, jak se implementují metody rozšíření jazyka C#.

Jediným způsobem, jak použít výše uvedené definice, je následující ošklivý kód:

(null as FooObject).BoolMethod (range);

Doporučení, aby se tomu zabránilo, je vložit definici BoolMethod uvnitř FooObject samotné definice rozhraní, to vám umožní volat toto rozšíření, jako je zamýšleno FooObject.BoolMethod (range).

[BaseType (typeof (NSObject))]
interface FooObject {

    [Static]
    [Export ("boolMethod:")]
    bool BoolMethod (NSRange range);
}

Pokaždé, když v definici najdeme člena [Static][Category] , vydáme upozornění (BI1117). Pokud opravdu chcete, [Static] aby členové v definicích [Category] , můžete umlčet upozornění pomocí [Category (allowStaticMembers: true)] nebo dekorací člena nebo [Category] definice rozhraní s [Internal].

StaticAttribute

Pokud se tento atribut použije na třídu, pouze vygeneruje statickou třídu, která není odvozena od NSObject, takže [BaseType] atribut bude ignorován. Statické třídy slouží k hostování veřejných proměnných jazyka C, které chcete zveřejnit.

Příklad:

[Static]
interface CBAdvertisement {
    [Field ("CBAdvertisementDataServiceUUIDsKey")]
    NSString DataServiceUUIDsKey { get; }

Vygeneruje třídu jazyka C# s následujícím rozhraním API:

public partial class CBAdvertisement  {
    public static NSString DataServiceUUIDsKey { get; }
}

Definice protokolů a modelů

Modely se obvykle používají implementací protokolu. Liší se v tom, že modul runtime se zaregistruje pouze u Objective-C metod, které byly ve skutečnosti přepsány. V opačném případě nebude metoda registrována.

To obecně znamená, že když podtřídu třídy, která byla označena příznakem ModelAttribute, byste neměli volat základní metodu. Volání této metody vyvolá následující výjimku: Foundation.You_Should_Not_Call_base_In_This_Method. U všech metod, které přepíšete, byste měli implementovat celé chování v podtřídě.

AbstractAttribute

Ve výchozím nastavení nejsou členy, které jsou součástí protokolu, povinné. To uživatelům umožňuje vytvořit podtřídu Model objektu pouhým odvozením z třídy v jazyce C# a přepsáním pouze metod, o které se zajímají. Objective-C Někdy kontrakt vyžaduje, aby uživatel pro tuto metodu poskytuje implementaci (ty jsou označeny direktivou @required v Objective-C). V takových případech byste tyto metody měli označit atributem [Abstract] .

Atribut [Abstract] lze použít buď na metody nebo vlastnosti a způsobí generátor označení vygenerovaného člena jako abstraktní a třída být abstraktní třída.

Z Xamarin.iOS se používá následující:

[BaseType (typeof (NSObject))]
[Model][Protocol]
public interface UITableViewDataSource {
    [Export ("tableView:numberOfRowsInSection:")]
    [Abstract]
    nint RowsInSection (UITableView tableView, nint section);
}

Defaultvalueattribute

Určuje výchozí hodnotu, kterou má vrátit metoda modelu, pokud uživatel neposkytuje metodu pro tuto konkrétní metodu v objektu Model.

Syntaxe:

public class DefaultValueAttribute : Attribute {
        public DefaultValueAttribute (object o);
        public object Default { get; set; }
}

Například v následující imaginární delegát třídy pro Camera třídu poskytujeme ShouldUploadToServer , která by byla vystavena jako vlastnost třídy Camera . Pokud uživatel Camera třídy explicitně nenastaví hodnotu lambda, která může odpovědět na hodnotu true nebo false, bude výchozí hodnota vrácená v tomto případě nepravda, což je hodnota, kterou jsme zadali v atributu DefaultValue :

[BaseType (typeof (NSObject))]
[Model][Protocol]
interface CameraDelegate {
    [Export ("camera:shouldPromptForAction:"), DefaultValue (false)]
    bool ShouldUploadToServer (Camera camera, CameraAction action);
}

Pokud uživatel nastaví obslužnou rutinu v imaginární třídě, bude tato hodnota ignorována:

var camera = new Camera ();
camera.ShouldUploadToServer = (camera, action) => return SomeDecision ();

Viz také: [NoDefaultValue], [DefaultValueFromArgument].

DefaultValueFromArgumentAttribute

Syntaxe:

public class DefaultValueFromArgumentAttribute : Attribute {
    public DefaultValueFromArgumentAttribute (string argument);
    public string Argument { get; }
}

Tento atribut při poskytnutí metody, která vrací hodnotu třídy modelu, dá generátoru pokyn, aby vrátil hodnotu zadaného parametru, pokud uživatel nezadal vlastní metodu nebo lambda.

Příklad:

[BaseType (typeof (NSObject))]
[Model][Protocol]
public interface NSAnimationDelegate {
    [Export ("animation:valueForProgress:"), DelegateName ("NSAnimationProgress"), DefaultValueFromArgumentAttribute ("progress")]
    float ComputeAnimationCurve (NSAnimation animation, nfloat progress);
}

V případě, že se uživatel NSAnimation třídy rozhodl použít některou z událostí nebo vlastností jazyka C# a nenastavil NSAnimation.ComputeAnimationCurve na metodu nebo lambda, vrácená hodnota by byla hodnota předaná v parametru průběhu.

Viz také: [NoDefaultValue], [DefaultValue]

IgnoredInDelegateAttribute

Někdy dává smysl nezpřístupňuje událost nebo delegovat vlastnost z třídy modelu do třídy hostitele, takže přidání tohoto atributu dá generátoru pokyn, aby se zabránilo generování jakékoli metody zdobené s ním.

[BaseType (typeof (UINavigationControllerDelegate))]
[Model][Protocol]
public interface UIImagePickerControllerDelegate {
    [Export ("imagePickerController:didFinishPickingImage:editingInfo:"), EventArgs ("UIImagePickerImagePicked")]
    void FinishedPickingImage (UIImagePickerController picker, UIImage image, NSDictionary editingInfo);

    [Export ("imagePickerController:didFinishPickingImage:"), IgnoredInDelegate)] // No event generated for this method
    void FinishedPickingImage (UIImagePickerController picker, UIImage image);
}

DelegateNameAttribute

Tento atribut se používá v metodách modelu, které vracejí hodnoty k nastavení názvu podpisu delegáta, který se má použít.

Příklad:

[BaseType (typeof (NSObject))]
[Model][Protocol]
public interface NSAnimationDelegate {
    [Export ("animation:valueForProgress:"), DelegateName ("NSAnimationProgress"), DefaultValueFromArgumentAttribute ("progress")]
    float ComputeAnimationCurve (NSAnimation animation, float progress);
}

S výše uvedenou definicí generátor vytvoří následující veřejnou deklaraci:

public delegate float NSAnimationProgress (MonoMac.AppKit.NSAnimation animation, float progress);

DelegateApiNameAttribute

Tento atribut se používá k povolení generátoru změnit název vlastnosti generované ve třídě hostitele. Někdy je užitečné, když název metody třídy FooDelegate dává smysl pro delegování třídy, ale vypadal by liché v hostitelské třídě jako vlastnost.

To je opravdu užitečné (a potřebné), pokud máte dvě nebo více metod přetížení, které dává smysl je pojmenovat tak, jak je ve třídě FooDelegate, ale chcete je vystavit ve třídě hostitele s lepším názvem.

Příklad:

[BaseType (typeof (NSObject))]
[Model][Protocol]
public interface NSAnimationDelegate {
    [Export ("animation:valueForProgress:"), DelegateApiName ("ComputeAnimationCurve"), DelegateName ("Func<NSAnimation, float, float>"), DefaultValueFromArgument ("progress")]
    float GetValueForProgress (NSAnimation animation, float progress);
}

S výše uvedenou definicí generátor vytvoří následující veřejnou deklaraci ve třídě hostitelů:

public Func<NSAnimation, float, float> ComputeAnimationCurve { get; set; }

EventArgsAttribute

U událostí, které přebírají více než jeden parametr (v Objective-C konvenci je první parametr ve třídě delegáta instance objektu odesílatele), musíte zadat název, který chcete, aby vygenerovaná třída EventArgs byla. To se provádí s atributem [EventArgs] deklarace metody ve vaší Model třídě.

Příklad:

[BaseType (typeof (UINavigationControllerDelegate))]
[Model][Protocol]
public interface UIImagePickerControllerDelegate {
    [Export ("imagePickerController:didFinishPickingImage:editingInfo:"), EventArgs ("UIImagePickerImagePicked")]
    void FinishedPickingImage (UIImagePickerController picker, UIImage image, NSDictionary editingInfo);
}

Výše uvedená deklarace vygeneruje UIImagePickerImagePickedEventArgs třídu, která je odvozena z EventArgs a pack oba parametry, a UIImage také NSDictionary. Generátor vytvoří toto:

public partial class UIImagePickerImagePickedEventArgs : EventArgs {
    public UIImagePickerImagePickedEventArgs (UIImage image, NSDictionary editingInfo);
    public UIImage Image { get; set; }
    public NSDictionary EditingInfo { get; set; }
}

Pak zveřejňuje následující položky ve UIImagePickerController třídě:

public event EventHandler<UIImagePickerImagePickedEventArgs> FinishedPickingImage { add; remove; }

EventNameAttribute

Tento atribut se používá k tomu, aby generátor mohl změnit název události nebo vlastnosti vygenerované ve třídě. Někdy je užitečné, když název metody třídy modelu dává smysl pro třídu modelu, ale vypadal by liché v původní třídě jako událost nebo vlastnost.

UIWebView Například používá následující bit z UIWebViewDelegate:

[Export ("webViewDidFinishLoad:"), EventArgs ("UIWebView"), EventName ("LoadFinished")]
void LoadingFinished (UIWebView webView);

Výše uvedené informace zveřejňuje LoadingFinished jako metodu UIWebViewDelegatev , ale LoadFinished jako událost připojit se k :UIWebView

var webView = new UIWebView (...);
webView.LoadFinished += delegate { Console.WriteLine ("done!"); }

ModelAttribute

Když použijete [Model] atribut na definici typu v rozhraní API kontraktu, modul runtime vygeneruje speciální kód, který se zobrazí pouze vyvolání metod ve třídě, pokud uživatel přepsal metodu ve třídě. Tento atribut se obvykle používá pro všechna rozhraní API, která zabalují třídu delegáta Objective-C .

NoDefaultValueAttribute

Určuje, že metoda v modelu neposkytuje výchozí návratovou hodnotu.

To funguje s Objective-C modulem runtime tím, že reaguje na falseObjective-C požadavek modulu runtime a určí, zda je zadaný selektor implementován v této třídě.

[BaseType (typeof (NSObject))]
[Model][Protocol]
interface CameraDelegate {
    [Export ("shouldDisplayPopup"), NoDefaultValue]
    bool ShouldUploadToServer ();
}

Viz také: [DefaultValue], [DefaultValueFromArgument]

Protokoly

Koncept Objective-C protokolu ve skutečnosti v jazyce C# neexistuje. Protokoly se podobají rozhraním jazyka C#, ale liší se v tom, že ne všechny metody a vlastnosti deklarované v protokolu musí být implementovány třídou, která ji přijme. Místo některých metod a vlastností jsou volitelné.

Některé protokoly se obecně používají jako třídy modelu, které by měly být vázány pomocí atributu [Model] .

[BaseType (typeof (NSObject))]
[Model, Protocol]
interface MyProtocol {
    // Use [Abstract] when the method is defined in the @required section
    // of the protocol definition in Objective-C
    [Abstract]
    [Export ("say:")]
    void Say (string msg);

    [Export ("listen")]
    void Listen ();
}

Od Xamarin.iOS 7.0 byla začleněna nová a vylepšená funkce vazby protokolu. Každá definice, která obsahuje [Protocol] atribut, ve skutečnosti vygeneruje tři podpůrné třídy, které výrazně zlepšují způsob, jakým používáte protokoly:

// Full method implementation, contains all methods
class MyProtocol : IMyProtocol {
    public void Say (string msg);
    public void Listen (string msg);
}

// Interface that contains only the required methods
interface IMyProtocol: INativeObject, IDisposable {
    [Export ("say:")]
    void Say (string msg);
}

// Extension methods
static class IMyProtocol_Extensions {
    public static void Optional (this IMyProtocol this, string msg);
    }
}

Implementace třídy poskytuje kompletní abstraktní třídu, kterou můžete přepsat jednotlivé metody a získat plnou bezpečnost typů. Vzhledem k tomu, že jazyk C# nepodporuje více dědičnosti, existují scénáře, kdy můžete vyžadovat jinou základní třídu, ale přesto chcete implementovat rozhraní.

Tady přichází definice vygenerovaného rozhraní. Jedná se o rozhraní, které má všechny požadované metody z protokolu. To umožňuje vývojářům, kteří chtějí implementovat váš protokol, pouze implementovat rozhraní. Modul runtime automaticky zaregistruje typ jako přijetí protokolu.

Všimněte si, že rozhraní uvádí pouze požadované metody a zveřejňuje volitelné metody. To znamená, že třídy, které přijímají protokol, získají úplnou kontrolu typů požadovaných metod, ale budou muset u volitelných metod protokolu použít slabé psaní (ručně pomocí atributů Export a shodný podpis).

Aby bylo vhodné využívat rozhraní API, které používá protokoly, vytvoří nástroj vazby také třídu metody rozšíření, která zveřejňuje všechny volitelné metody. To znamená, že pokud používáte rozhraní API, budete moct považovat protokoly za všechny metody.

Pokud chcete v rozhraní API použít definice protokolu, budete muset do definice rozhraní API napsat prázdná rozhraní kostry. Pokud chcete použít MyProtocol v rozhraní API, musíte to udělat takto:

[BaseType (typeof (NSObject))]
[Model, Protocol]
interface MyProtocol {
    // Use [Abstract] when the method is defined in the @required section
    // of the protocol definition in Objective-C
    [Abstract]
    [Export ("say:")]
    void Say (string msg);

    [Export ("listen")]
    void Listen ();
}

interface IMyProtocol {}

[BaseType (typeof(NSObject))]
interface MyTool {
    [Export ("getProtocol")]
    IMyProtocol GetProtocol ();
}

Výše uvedené informace jsou potřeba, protože v době IMyProtocol vazby neexistuje, proto potřebujete poskytnout prázdné rozhraní.

Přijetí rozhraní generovaných protokolem

Kdykoli implementujete jedno z rozhraní generovaných pro protokoly, například takto:

class MyDelegate : NSObject, IUITableViewDelegate {
    nint IUITableViewDelegate.GetRowHeight (nint row) {
        return 1;
    }
}

Implementace požadovaných metod rozhraní se exportuje se správným názvem, takže je ekvivalentní tomuto:

class MyDelegate : NSObject, IUITableViewDelegate {
    [Export ("getRowHeight:")]
    nint IUITableViewDelegate.GetRowHeight (nint row) {
        return 1;
    }
}

To bude fungovat pro všechny požadované členy protokolu, ale existuje zvláštní případ s volitelnými selektory, o které je potřeba vědět.

Volitelné členy protokolu jsou při použití základní třídy považovány za identické:

public class UrlSessionDelegate : NSUrlSessionDownloadDelegate {
	public override void DidWriteData (NSUrlSession session, NSUrlSessionDownloadTask downloadTask, long bytesWritten, long totalBytesWritten, long totalBytesExpectedToWrite)

ale při použití rozhraní protokolu je nutné přidat [Export]. Integrované vývojové prostředí (IDE) ho přidá prostřednictvím automatického dokončování, když ho přidáte s přepsáním.

public class UrlSessionDelegate : NSObject, INSUrlSessionDownloadDelegate {
	[Export ("URLSession:downloadTask:didWriteData:totalBytesWritten:totalBytesExpectedToWrite:")]
	public void DidWriteData (NSUrlSession session, NSUrlSessionDownloadTask downloadTask, long bytesWritten, long totalBytesWritten, long totalBytesExpectedToWrite)

Mezi těmito dvěma za běhu je malý rozdíl v chování:

  • Uživatelé základní třídy (V příkladu NSUrlSessionDownloadDelegate) poskytují všechny povinné a volitelné selektory, které vracejí rozumné výchozí hodnoty.
  • Uživatelé rozhraní (INSUrlSessionDownloadDelegate v příkladu) reagují pouze na přesné selektory, které jsou k dispozici.

Některé vzácné třídy se zde můžou chovat odlišně. V téměř všech případech je však bezpečné použít jednu z těchto věcí.

Vkládání protokolů

I když svážete existující Objective-C typy, které byly deklarovány jako přijetí protokolu, budete chtít vložit protokol přímo. Uděláte to tak, že pouze deklaruje váš protokol jako rozhraní bez jakéhokoli [BaseType] atributu a vypíše protokol v seznamu základních rozhraní pro vaše rozhraní.

Příklad:

interface SpeakProtocol {
    [Export ("say:")]
    void Say (string msg);
}

[BaseType (typeof (NSObject))]
interface Robot : SpeakProtocol {
    [Export ("awake")]
    bool Awake { get; set; }
}

Definice členů

Atributy v této části se použijí na jednotlivé členy typu: vlastnosti a deklarace metody.

AlignAttribute

Slouží k zadání hodnoty zarovnání pro návratové typy vlastností. Některé vlastnosti přebírají ukazatele na adresy, které musí být zarovnány na určitých hranicích (v Xamarin.iOS k tomu dochází například u některých GLKBaseEffect vlastností, které musí být zarovnané na 16 bajtů). Tuto vlastnost můžete použít k dekoraci getter a použít hodnotu zarovnání. Obvykle se používá s typy OpenTK.Vector4 a OpenTK.Matrix4 typy při integraci s Objective-C rozhraními API.

Příklad:

public interface GLKBaseEffect {
    [Export ("constantColor")]
    Vector4 ConstantColor { [Align (16)] get; set;  }
}

VzhledAttribute

Atribut [Appearance] je omezen na iOS 5, kde byl představen správce vzhledu.

Atribut [Appearance] lze použít pro libovolnou metodu nebo vlastnost, které se účastní architektury UIAppearance . Pokud se tento atribut použije na metodu nebo vlastnost třídy, přesměruje generátor vazeb na vytvoření třídy vzhledu silného typu, která se používá ke stylu všech instancí této třídy nebo instancí, které splňují určitá kritéria.

Příklad:

public interface UIToolbar {
    [Since (5,0)]
    [Export ("setBackgroundImage:forToolbarPosition:barMetrics:")]
    [Appearance]
    void SetBackgroundImage (UIImage backgroundImage, UIToolbarPosition position, UIBarMetrics barMetrics);

    [Since (5,0)]
    [Export ("backgroundImageForToolbarPosition:barMetrics:")]
    [Appearance]
    UIImage GetBackgroundImage (UIToolbarPosition position, UIBarMetrics barMetrics);
}

Výše uvedený kód by vygeneroval následující kód v uiToolbaru:

public partial class UIToolbar {
    public partial class UIToolbarAppearance : UIView.UIViewAppearance {
        public virtual void SetBackgroundImage (UIImage backgroundImage, UIToolbarPosition position, UIBarMetrics barMetrics);
        public virtual UIImage GetBackgroundImage (UIToolbarPosition position, UIBarMetrics barMetrics)
    }
    public static new UIToolbarAppearance Appearance { get; }
    public static new UIToolbarAppearance AppearanceWhenContainedIn (params Type [] containers);
}

AutoReleaseAttribute (Xamarin.iOS 5.4)

[AutoReleaseAttribute] Pomocí metod a vlastností zabalte volání metody do metody v objektu NSAutoReleasePool.

Existují Objective-C některé metody, které vracejí hodnoty, které jsou přidány do výchozího NSAutoReleasePool. Ve výchozím nastavení by to přešlo do vašeho vlákna NSAutoReleasePool, ale vzhledem k tomu, že Xamarin.iOS také uchovává odkaz na vaše objekty, dokud se spravovaný objekt nachází, možná nebudete chtít zachovat další odkaz, který NSAutoReleasePool se vyprázdní pouze do doby, než vlákno vrátí řízení na další vlákno, nebo se vrátíte zpět do hlavní smyčky.

Tento atribut se použije například u těžkých vlastností (například UIImage.FromFile), které vrací objekty, které byly přidány do výchozího NSAutoReleasePool. Bez tohoto atributu by se image zachovaly, pokud vlákno nevrátilo řízení do hlavní smyčky. Uf vaše vlákno bylo nějaký druh stahování na pozadí, který je vždy naživu a čeká na práci, obrázky by nikdy nebyly vydány.

ForcedTypeAttribute

Slouží [ForcedTypeAttribute] k vynucení vytvoření spravovaného typu i v případě, že vrácený nespravovaný objekt neodpovídá typu popsanému v definici vazby.

To je užitečné, když typ popsaný v hlavičce neodpovídá vrácenému typu nativní metody, například použijte následující Objective-C definici z NSURLSession:

- (NSURLSessionDownloadTask *)downloadTaskWithRequest:(NSURLRequest *)request

Jasně uvádí, že vrátí NSURLSessionDownloadTask instanci, ale přesto vrátíNSURLSessionTask, což je supertřída, a proto se nepřevést na NSURLSessionDownloadTask. Vzhledem k tomu, že jsme v kontextu InvalidCastException bezpečném typu, stane se to.

Chcete-li dodržet popis záhlaví a vyhnout se InvalidCastException, použije se [ForcedTypeAttribute] .

[BaseType (typeof (NSObject), Name="NSURLSession")]
interface NSUrlSession {

    [Export ("downloadTaskWithRequest:")]
    [return: ForcedType]
    NSUrlSessionDownloadTask CreateDownloadTask (NSUrlRequest request);
}

Přijímá [ForcedTypeAttribute] také logickou hodnotu s názvem Owns , která je false ve výchozím nastavení [ForcedType (owns: true)]. Vlastní parametr se používá k sledování zásad vlastnictví pro objekty Core Foundation.

Hodnota [ForcedTypeAttribute] je platná pouze u parametrů, vlastností a návratové hodnoty.

BindAsAttribute

Umožňuje [BindAsAttribute] vazbu NSNumberNSValue a NSString(výčty) do přesnějších typů jazyka C#. Atribut lze použít k vytvoření lepšího, přesnějšího rozhraní .NET API přes nativní rozhraní API.

Metody můžete vyzdobit (při návratové hodnotě), parametry a vlastnosti pomocí BindAs. Jediným omezením je, že člen nesmí být uvnitř ani [Model] rozhraní[Protocol].

Příklad:

[return: BindAs (typeof (bool?))]
[Export ("shouldDrawAt:")]
NSNumber ShouldDraw ([BindAs (typeof (CGRect))] NSValue rect);

Výstup:

[Export ("shouldDrawAt:")]
bool? ShouldDraw (CGRect rect) { ... }

Interně provedeme bool?<>NSNumber -a<CGRect ->NSValue převody.

Aktuální podporované typy zapouzdření jsou:

  • NSValue
  • NSNumber
  • NSString

NSValue

Následující datové typy jazyka C# jsou podporovány pro zapouzdření z/do NSValue:

  • CGAffineTransform
  • NSRange
  • CGVector
  • SCNMatrix4
  • CLLocationCoordinate2D
  • SCNVector3
  • SCNVector4
  • CGPoint / PointF
  • CGRect / RectangleF
  • CGSize / SizeF
  • UIEdgeInsets
  • UIOffset
  • MKCoordinateSpan
  • CMTimeRange
  • CMTime
  • CMTimeMapping
  • CATransform3D

NSNumber

Následující datové typy jazyka C# jsou podporovány pro zapouzdření z/do NSNumber:

  • bool
  • byte
  • double
  • float (číslo s plovoucí řádovou čárkou)
  • short
  • int
  • long
  • sbyte
  • ushort
  • uint
  • ulong
  • nfloat
  • nint
  • nuint
  • Výčty

NSString

[BindAs] funguje v konjunkci s výčty, které jsou podporovány konstantou NSString, abyste mohli vytvořit lepší rozhraní .NET API, například:

[BindAs (typeof (CAScroll))]
[Export ("supportedScrollMode")]
NSString SupportedScrollMode { get; set; }

Výstup:

[Export ("supportedScrollMode")]
CAScroll SupportedScrollMode { get; set; }

Zacházíme s převodem enum<>NSString pouze v případě, že zadaný typ výčtu je [BindAs]podporován NSString konstantou.

Pole

[BindAs] podporuje také pole libovolného z podporovaných typů, jako příklad můžete mít následující definici rozhraní API:

[return: BindAs (typeof (CAScroll []))]
[Export ("getScrollModesAt:")]
NSString [] GetScrollModes ([BindAs (typeof (CGRect []))] NSValue [] rects);

Výstup:

[Export ("getScrollModesAt:")]
CAScroll? [] GetScrollModes (CGRect [] rects) { ... }

Parametr rects bude zapouzdřen do objektu NSArray , který obsahuje hodnotu NSValue pro každou z nich CGRect a ve vrácených hodnotách získáte pole, jehož CAScroll? pole bylo vytvořeno pomocí hodnot vrácených NSArray obsahujících NSStrings.

BindAttribute

Atribut [Bind] má dva použití jednoho při použití na metodu nebo deklaraci vlastnosti a druhý při použití na jednotlivý getter nebo setter ve vlastnosti.

Pokud se používá pro metodu nebo vlastnost, účinek [Bind] atributu je vygenerovat metodu, která vyvolá zadaný selektor. Výsledná vygenerovaná metoda však není zdobena atributem [Export] , což znamená, že se nemůže účastnit přepsání metody. Obvykle se používá v kombinaci s atributem [Target] pro implementaci Objective-C rozšiřujících metod.

Příklad:

public interface UIView {
    [Bind ("drawAtPoint:withFont:")]
    SizeF DrawString ([Target] string str, CGPoint point, UIFont font);
}

Pokud se používá v getter nebo setter, [Bind] atribut se používá ke změně výchozích hodnot odvozených generátorem kódu při generování názvů getter a setter setter Objective-C setter pro vlastnost. Ve výchozím nastavení při označení vlastnosti s názvem fooBargenerátor vygeneruje fooBar export pro getter a setFooBar: pro setter. V několika případech Objective-C se tato konvence nedodržuje, obvykle mění název getter na isFooBar. Tento atribut byste použili k informování generátoru.

Příklad:

// Default behavior
[Export ("active")]
bool Active { get; set; }

// Custom naming with the Bind attribute
[Export ("visible")]
bool Visible { [Bind ("isVisible")] get; set; }

AsyncAttribute

K dispozici pouze pro Xamarin.iOS 6.3 a novější.

Tento atribut lze použít u metod, které jako poslední argument přebírají obslužnou rutinu dokončení.

Atribut můžete použít [Async] u metod, jejichž posledním argumentem je zpětné volání. Pokud použijete tuto metodu, generátor vazeb vygeneruje verzi této metody s příponou Async. Pokud zpětné volání nepřijímá žádné parametry, návratová hodnota bude Taska , pokud zpětné volání převezme parametr, bude výsledkem Task<T>.

[Export ("upload:complete:")]
[Async]
void LoadFile (string file, NSAction complete)

Následující metoda vygeneruje tuto asynchronní metodu:

Task LoadFileAsync (string file);

Pokud zpětné volání přebírá více parametrů, měli byste nastavit ResultType nebo ResultTypeName zadat požadovaný název vygenerovaného typu, který bude obsahovat všechny vlastnosti.

delegate void OnComplete (string [] files, nint byteCount);

[Export ("upload:complete:")]
[Async (ResultTypeName="FileLoading")]
void LoadFiles (string file, OnComplete complete)

Následující příkaz vygeneruje tuto asynchronní metodu, kde FileLoading obsahuje vlastnosti pro přístup k oběma files a byteCount:

Task<FileLoading> LoadFile (string file);

Pokud poslední parametr zpětného volání je NSError, pak vygenerovaná Async metoda zkontroluje, zda hodnota není null, a pokud je to případ, vygenerovaná asynchronní metoda nastaví výjimku úkolu.

[Export ("upload:onComplete:")]
[Async]
void Upload (string file, Action<string,NSError> onComplete);

Výše uvedená metoda generuje následující asynchronní metodu:

Task<string> UploadAsync (string file);

A při chybě bude výsledná úloha mít nastavenou NSErrorException výjimku, která zabalí výsledný NSError.

AsyncAttribute.ResultType

Tato vlastnost slouží k určení hodnoty pro vrácený Task objekt. Tento parametr přebírá existující typ, takže je potřeba ho definovat v jedné z definic základního rozhraní API.

AsyncAttribute.ResultTypeName

Tato vlastnost slouží k určení hodnoty pro vrácený Task objekt. Tento parametr přebírá název požadovaného typu, generátor vytvoří řadu vlastností, jednu pro každý parametr, který přebírá zpětné volání.

AsyncAttribute.MethodName

Tato vlastnost slouží k přizpůsobení názvu vygenerovaných asynchronních metod. Výchozí hodnota je použít název metody a připojit text "Async", můžete to použít ke změně tohoto výchozího nastavení.

DesignatedInitializerAttribute

Pokud se tento atribut použije u konstruktoru, vygeneruje se stejné [DesignatedInitializer] v konečném sestavení platformy. To pomáhá integrovanému vývojovému prostředí indikovat, který konstruktor se má použít v podtřídách.

To by se mělo mapovat na Objective-C/clang použití __attribute__((objc_designated_initializer)).

Zakázat FunkciZeroCopyAttribute

Tento atribut se použije na parametry řetězce nebo vlastnosti řetězce a dává generátoru kódu pokyn, aby pro tento parametr nezařazoval řetězec zero-copy, a místo toho vytvoří novou instanci NSString z řetězce jazyka C#. Tento atribut je vyžadován pouze u řetězců, pokud dáváte generátoru pokyn, aby používal zařazování řetězců nulové kopie pomocí možnosti příkazového --zero-copy řádku nebo nastavení atributu ZeroCopyStringsAttributena úrovni sestavení .

To je nezbytné v případech, kdy je vlastnost deklarována Objective-C jako retain nebo assign vlastnost namísto copy vlastnosti. Obvykle k tomu dochází v knihovnách třetích stran, které vývojáři nesprávně optimalizovali. Obecně platí, že neboNSStringassignvlastnosti jsou nesprávné, retain protože NSMutableString nebo uživatelem odvozené třídy NSString mohou měnit obsah řetězců bez znalosti kódu knihovny, subtly rozbít aplikaci. Obvykle k tomu dochází kvůli předčasné optimalizaci.

V následujícím příkladu jsou uvedeny dvě takové vlastnosti Objective-C:

@property(nonatomic,retain) NSString *name;
@property(nonatomic,assign) NSString *name2;

DisposeAttribute

Když použijete u [DisposeAttribute] třídy, poskytnete fragment kódu, který se přidá do Dispose() implementace metody třídy.

Vzhledem k tomu, že metoda Dispose je automaticky generována bmac-native nástroji a btouch-native nástroje, musíte použít [Dispose] atribut k vložení kódu do vygenerované Dispose implementace metody.

Příklad:

[BaseType (typeof (NSObject))]
[Dispose ("if (OpenConnections > 0) CloseAllConnections ();")]
interface DatabaseConnection {
}

ExportAttribute

Atribut [Export] se používá k označení metody nebo vlastnosti, které mají být vystaveny modulu Objective-C runtime. Tento atribut se sdílí mezi nástrojem pro vytváření vazeb a skutečnými moduly runtime Xamarin.iOS a Xamarin.Mac. Pro metody se parametr předá doslovné kódu pro vlastnosti, getter a setter Export jsou generovány na základě základní deklarace (viz část informace o [BindAttribute] tom, jak změnit chování nástroje vazby).

Syntaxe:

public enum ArgumentSemantic {
    None, Assign, Copy, Retain.
}

[AttributeUsage (AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Property)]
public class ExportAttribute : Attribute {
    public ExportAttribute();
    public ExportAttribute (string selector);
    public ExportAttribute (string selector, ArgumentSemantic semantic);
    public string Selector { get; set; }
    public ArgumentSemantic ArgumentSemantic { get; set; }
}

Selektor představuje název podkladové Objective-C metody nebo vlastnosti, která je vázána.

ExportAttribute.ArgumentSemantic

FieldAttribute

Tento atribut slouží k zveřejnění globální proměnné jazyka C jako pole, které je načteno na vyžádání a vystaveno kódu jazyka C#. Obvykle se to vyžaduje k získání hodnot konstant, které jsou definovány v jazyce C nebo Objective-C které můžou být buď tokeny používané v některých rozhraních API, nebo jejichž hodnoty jsou neprůhlené a musí být použity stejně jako uživatelský kód.

Syntaxe:

public class FieldAttribute : Attribute {
    public FieldAttribute (string symbolName);
    public FieldAttribute (string symbolName, string libraryName);
    public string SymbolName { get; set; }
    public string LibraryName { get; set; }
}

Symbol symbolName jazyka C, se kterým chcete propojit. Ve výchozím nastavení se načte z knihovny, jejíž název je odvozen z oboru názvů, kde je typ definován. Pokud se nejedná o knihovnu, ve které se symbol vyhledá, měli byste předat libraryName parametr. Pokud propojíte statickou knihovnulibraryName, použijte __Internal ji jako parametr.

Vygenerované vlastnosti jsou vždy statické.

Vlastnosti označené atributem Pole můžou být následující typy:

  • NSString
  • NSArray
  • nint / int / long
  • nuint / uint / ulong
  • nfloat / float
  • double
  • CGSize
  • System.IntPtr
  • Výčty

Funkce Setter nejsou podporovány pro výčty zálohované konstantami NSString, ale v případě potřeby je lze ručně svázat.

Příklad:

[Static]
interface CameraEffects {
     [Field ("kCameraEffectsZoomFactorKey", "CameraLibrary")]
     NSString ZoomFactorKey { get; }
}

InternalAttribute

Atribut [Internal] lze použít u metod nebo vlastností a má vliv na označení generovaného kódu klíčovým slovem internal jazyka C#, které kód zpřístupní pouze kódu ve vygenerovaném sestavení. Obvykle se používá ke skrytí rozhraní API, která jsou příliš nízká nebo poskytují neoptimální veřejné rozhraní API, které chcete vylepšit nebo pro rozhraní API, která generátor nepodporuje, a vyžadují ruční kódování.

Při návrhu vazby byste obvykle skryli metodu nebo vlastnost pomocí tohoto atributu a zadali jiný název metody nebo vlastnosti a pak v doplňkovém souboru podpory jazyka C# byste přidali obálku se silnými typy, která zveřejňuje základní funkce.

Příklad:

[Internal]
[Export ("setValue:forKey:")]
void _SetValueForKey (NSObject value, NSObject key);

[Internal]
[Export ("getValueForKey:")]
NSObject _GetValueForKey (NSObject key);

V podpůrném souboru pak můžete mít nějaký kód podobný tomuto:

public NSObject this [NSObject idx] {
    get {
        return _GetValueForKey (idx);
    }
    set {
        _SetValueForKey (value, idx);
    }
}

IsThreadStaticAttribute

Tento atribut označí záložní pole pro vlastnost, která má být označena atributem .NET [ThreadStatic] . To je užitečné, pokud je pole statickou proměnnou vlákna.

MarshalNativeExceptions (Xamarin.iOS 6.0.6)

Tento atribut způsobí, že metoda podporuje nativní (Objective-C) výjimky. Místo přímého volání objc_msgSend projde volání vlastní trampoline, která zachytí výjimky ObjectiveC a zařadí je do spravovaných výjimek.

V současné době se podporuje jenom několik objc_msgSend podpisů (zjistíte, jestli se podpis nepodporuje při nativním propojení aplikace, která používá vazbu, selže s chybějícím symbolem monotouch__objc_msgSend ), ale na žádost je možné přidat další.

NewAttribute

Tento atribut se použije u metod a vlastností, aby generátor vygeneroval new klíčové slovo před deklarací.

Používá se k tomu, aby se zabránilo upozornění kompilátoru při zavedení stejné metody nebo názvu vlastnosti v podtřídě, která již existovala v základní třídě.

NotificationAttribute

Tento atribut můžete použít u polí, aby generátor vytvořil třídu oznámení silného typu.

Tento atribut lze použít bez argumentů pro oznámení, která neobsahují datovou část, nebo můžete zadat System.Type odkaz na jiné rozhraní v definici rozhraní API, obvykle s názvem končícím na "EventArgs". Generátor změní rozhraní na třídu, která podtřídy EventArgs a bude obsahovat všechny vlastnosti uvedené tam. Atribut [Export] by měl být použit ve EventArgs třídě k výpisu názvu klíče použitého k vyhledání Objective-C slovníku pro načtení hodnoty.

Příklad:

interface MyClass {
    [Notification]
    [Field ("MyClassDidStartNotification")]
    NSString DidStartNotification { get; }
}

Výše uvedený kód vygeneruje vnořenou třídu MyClass.Notifications s následujícími metodami:

public class MyClass {
   [..]
   public Notifications {
      public static NSObject ObserveDidStart (EventHandler<NSNotificationEventArgs> handler)
      public static NSObject ObserveDidStart (NSObject objectToObserve, EventHandler<NSNotificationEventArgs> handler)
   }
}

Uživatelé vašeho kódu se pak můžou snadno přihlásit k odběru oznámení odesílaných do NSDefaultCenter pomocí následujícího kódu:

var token = MyClass.Notifications.ObserverDidStart ((notification) => {
    Console.WriteLine ("Observed the 'DidStart' event!");
});

Nebo nastavit konkrétní objekt, který chcete sledovat. Pokud tuto metodu objectToObserve předátenull, bude se chovat stejně jako její druhý partner.

var token = MyClass.Notifications.ObserverDidStart (objectToObserve, (notification) => {
    Console.WriteLine ("Observed the 'DidStart' event on objectToObserve!");
});

Vrácenou hodnotu lze ObserveDidStart použít k snadnému zastavení přijímání oznámení, například takto:

token.Dispose ();

Nebo můžete volat NSNotification.DefaultCenter.RemoveObserver a předat token. Pokud oznámení obsahuje parametry, měli byste zadat pomocné EventArgs rozhraní, například takto:

interface MyClass {
    [Notification (typeof (MyScreenChangedEventArgs)]
    [Field ("MyClassScreenChangedNotification")]
    NSString ScreenChangedNotification { get; }
}

// The helper EventArgs declaration
interface MyScreenChangedEventArgs {
    [Export ("ScreenXKey")]
    nint ScreenX { get; set; }

    [Export ("ScreenYKey")]
    nint ScreenY { get; set; }

    [Export ("DidGoOffKey")]
    [ProbePresence]
    bool DidGoOff { get; }
}

Výše uvedená funkce vygeneruje MyScreenChangedEventArgs třídu s vlastnostmi ScreenX , ScreenY které načítají data ze slovníku NSNotification.UserInfo pomocí klíčů ScreenXKey a ScreenYKey v uvedeném pořadí použijí správné převody. Atribut [ProbePresence] se používá pro generátor pro sondu, pokud je klíč nastaven v UserInfo, místo pokusu o extrakci hodnoty. Používá se v případech, kdy je přítomnost klíče hodnotou (obvykle pro logické hodnoty).

To vám umožní psát kód takto:

var token = MyClass.NotificationsObserveScreenChanged ((notification) => {
    Console.WriteLine ("The new screen dimensions are {0},{1}", notification.ScreenX, notification.ScreenY);
});

V některých případech není žádná konstanta přidružená k hodnotě předané ve slovníku. Apple někdy používá konstanty veřejných symbolů a někdy používá řetězcové konstanty. Ve výchozím nastavení [Export] atribut ve vaší zadané EventArgs třídě použije zadaný název jako veřejný symbol, který se má vyhledat za běhu. Pokud tomu tak není, a místo toho se má vyhledat jako řetězcová konstanta, předejte ArgumentSemantic.Assign hodnotu atributu Export.

Novinka v Xamarin.iOS 8.4

V některých případech budou oznámení začínat životností bez argumentů, takže použití [Notification] bez argumentů je přijatelné. Někdy se ale do oznámení zavedou parametry. Pro podporu tohoto scénáře lze atribut použít více než jednou.

Pokud vyvíjíte vazbu a chcete se vyhnout přerušení existujícího uživatelského kódu, změníte existující oznámení z:

interface MyClass {
    [Notification]
    [Field ("MyClassScreenChangedNotification")]
    NSString ScreenChangedNotification { get; }
}

Do verze, která vypíše atribut oznámení dvakrát, například takto:

interface MyClass {
    [Notification]
    [Notification (typeof (MyScreenChangedEventArgs)]
    [Field ("MyClassScreenChangedNotification")]
    NSString ScreenChangedNotification { get; }
}

NullAllowedAttribute

Pokud se tato vlastnost použije na vlastnost, označí ji příznakem, že umožňuje, aby k ní byla přiřazena hodnota null . To platí jenom pro odkazové typy.

Pokud se tento parametr použije u parametru v podpisu metody, znamená to, že zadaný parametr může mít hodnotu null a že by neměla být provedena žádná kontrola pro předávání null hodnot.

Pokud typ odkazu nemá tento atribut, nástroj vazby vygeneruje kontrolu přiřazené hodnoty před jeho Objective-C předáním a vygeneruje kontrolu, která vyvolá ArgumentNullException , pokud je nullpřiřazena hodnota .

Příklad:

// In properties

[NullAllowed]
UIImage IconFile { get; set; }

// In methods
void SetImage ([NullAllowed] UIImage image, State forState);

OverrideAttribute

Tento atribut použijte k pokyn generátoru vazeb, že vazba pro tuto konkrétní metodu by měla být označena klíčovým slovem override .

PreSnippetAttribute

Tento atribut můžete použít k vložení kódu, který se má vložit po ověření vstupních parametrů, ale před voláním kódu do Objective-C.

Příklad:

[Export ("demo")]
[PreSnippet ("var old = ViewController;")]
void Demo ();

PrologueSnippetAttribute

Tento atribut můžete použít k vložení kódu před ověřením některého z parametrů ve vygenerované metodě.

Příklad:

[Export ("demo")]
[Prologue ("Trace.Entry ();")]
void Demo ();

PostGetAttribute

Dává generátoru vazeb pokyn, aby vyvolal zadanou vlastnost z této třídy, aby z ní načte hodnotu.

Tato vlastnost se obvykle používá k aktualizaci mezipaměti, která odkazuje na odkazované objekty, které udržují odkazovaný na graf objektu. Obvykle se zobrazuje v kódu, který obsahuje operace, jako je Přidání nebo odebrání. Tato metoda se používá, aby se po přidání nebo odebrání prvků aktualizovala interní mezipaměť, abychom zajistili, že uchováváme spravované odkazy na objekty, které se skutečně používají. To je možné, protože nástroj vazby vygeneruje záložní pole pro všechny referenční objekty v dané vazbě.

Příklad:

[BaseType (typeof (NSObject))]
[Since (4,0)]
public interface NSOperation {
    [Export ("addDependency:")][PostGet ("Dependencies")]
    void AddDependency (NSOperation op);

    [Export ("removeDependency:")][PostGet ("Dependencies")]
    void RemoveDependency (NSOperation op);

    [Export ("dependencies")]
    NSOperation [] Dependencies { get; }
}

V tomto případě Dependencies bude vlastnost vyvolána po přidání nebo odebrání závislostí z objektu NSOperation , abychom zajistili, že máme graf, který představuje skutečné načtené objekty, což brání nevrácené paměti i poškození paměti.

PostSnippetAttribute

Tento atribut můžete použít k vložení některého zdrojového kódu jazyka C#, který se má vložit po vyvolání základní Objective-C metody.

Příklad:

[Export ("demo")]
[PostSnippet ("if (old != null) old.DemoComplete ();")]
void Demo ();

ProxyAttribute

Tento atribut se použije k vrácení hodnot, které je označí příznakem jako proxy objekty. Některá Objective-C rozhraní API vrací objekty proxy, které nelze odlišit od uživatelských vazeb. Výsledkem tohoto atributu je označení objektu DirectBinding jako objektu. Pro scénář v Xamarin.Mac se můžete podívat na diskuzi o této chybě.

Zachovat AtributListAttribute

Dává generátoru pokyn, aby zachoval spravovaný odkaz na parametr nebo odebral interní odkaz na parametr. Slouží k zachování odkazů na objekty.

Syntaxe:

public class RetainListAttribute: Attribute {
     public RetainListAttribute (bool doAdd, string listName);
}

Pokud je hodnota doAdd true, pak se parametr přidá do __mt_{0}_var List<NSObject>;. Kde {0} se nahrazuje daným listNameznakem . Toto pomocné pole musíte deklarovat v doplňkové částečné třídě do rozhraní API.

Příklad najdete v tématu foundation.cs a NSNotificationCenter.cs

ReleaseAttribute (Xamarin.iOS 6.0)

To lze použít pro návratové typy označující, že generátor by měl před vrácením objektu volat Release objekt. To je potřeba jenom v případě, že metoda poskytuje uchováný objekt (na rozdíl od autoreleasovaného objektu, což je nejběžnější scénář).

Příklad:

[Export ("getAndRetainObject")]
[return: Release ()]
NSObject GetAndRetainObject ();

Kromě toho se tento atribut rozšíří do vygenerovaného kódu, aby modul runtime Xamarin.iOS věděl, že musí zachovat objekt při návratu z Objective-C takové funkce.

SealedAttribute

Dá generátoru pokyn, aby označil vygenerovanou metodu jako zapečetěnou. Pokud tento atribut není zadaný, výchozí hodnota je vygenerovat virtuální metodu (buď virtuální metodu, abstraktní metodu nebo přepsání v závislosti na tom, jak se používají jiné atributy).

StaticAttribute

[Static] Pokud je atribut použit pro metodu nebo vlastnost, vygeneruje statickou metodu nebo vlastnost. Pokud tento atribut není zadán, generátor vytvoří metodu instance nebo vlastnost.

TransientAttribute

Tento atribut použijte k označení vlastností, jejichž hodnoty jsou přechodné, tj. objekty vytvořené dočasně v iOSu, ale nejsou dlouhodobé. Pokud se tento atribut použije na vlastnost, generátor nevytvoří záložní pole pro tuto vlastnost, což znamená, že spravovaná třída neuchovává odkaz na objekt.

WrapAttribute

V návrhu vazeb [Wrap] Xamarin.iOS/Xamarin.Mac se atribut používá k zabalení slabě zadaného objektu se silným objektem. Jedná se většinou o Objective-C delegované objekty, které jsou obvykle deklarovány jako typ id nebo NSObject. Konvence, kterou používá Xamarin.iOS a Xamarin.Mac, je zveřejnit tyto delegáty nebo zdroje dat jako typ NSObject a jsou pojmenovány pomocí konvence "Slabá" + název, který se zveřejňuje. Vlastnost id delegate z Objective-C by byla vystavena jako NSObject WeakDelegate { get; set; } vlastnost v souboru kontraktu rozhraní API.

Obvykle je ale hodnota přiřazená tomuto delegátovi silného typu, takže se podíváme na silný typ a použijeme [Wrap] atribut, to znamená, že uživatelé se můžou rozhodnout použít slabé typy, pokud potřebují nějaké jemné řízení nebo pokud se potřebují uchylovat k trikům nízké úrovně, nebo mohou použít vlastnost silného typu pro většinu své práce.

Příklad:

[BaseType (typeof (NSObject))]
interface Demo {
     [Export ("delegate"), NullAllowed]
     NSObject WeakDelegate { get; set; }

     [Wrap ("WeakDelegate")]
     DemoDelegate Delegate { get; set; }
}

[BaseType (typeof (NSObject))]
[Model][Protocol]
interface DemoDelegate {
    [Export ("doDemo")]
    void DoDemo ();
}

Takto by uživatel používal slabě napsanou verzi delegáta:

// The weak case, user has to roll his own
class SomeObject : NSObject {
    [Export ("doDemo")]
    void CallbackForDoDemo () {}

}

var demo = new Demo ();
demo.WeakDelegate = new SomeObject ();

A takto by uživatel používal verzi silného typu, všimněte si, že uživatel využívá systém typů jazyka C# a používá klíčové slovo přepsání k deklaraci svého záměru a že nemusí ručně vyzdobovat metodu [Export]pomocí , protože jsme to udělali ve vazbě pro uživatele:

// This is the strong case,
class MyDelegate : DemoDelegate {
   override void Demo DoDemo () {}
}

var strongDemo = new Demo ();
demo.Delegate = new MyDelegate ();

Dalším použitím atributu [Wrap] je podpora verzí metod silného typu. Příklad:

[BaseType (typeof (NSObject))]
interface XyzPanel {
    [Export ("playback:withOptions:")]
    void Playback (string fileName, [NullAllowed] NSDictionary options);

    [Wrap ("Playback (fileName, options == null ? null : options.Dictionary")]
    void Playback (string fileName, XyzOptions options);
}

[Wrap] Pokud je atribut použit pro metodu uvnitř typu zdobeného atributem[Category], musíte zahrnout This jako první argument, protože se generuje rozšiřující metoda. Příklad:

[Wrap ("Write (This, image, options?.Dictionary, out error)")]
bool Write (CIImage image, CIImageRepresentationOptions options, out NSError error);

Členové vygenerované [Wrap] ve výchozím nastavení nejsou virtual , pokud potřebujete virtual člena, který můžete nastavit na true volitelný isVirtual parametr.

[BaseType (typeof (NSObject))]
interface FooExplorer {
    [Export ("fooWithContentsOfURL:")]
    void FromUrl (NSUrl url);

    [Wrap ("FromUrl (NSUrl.FromString (url))", isVirtual: true)]
    void FromUrl (string url);
}

[Wrap] lze také použít přímo v objektech getter a setter. To umožňuje mít na nich úplnou kontrolu a podle potřeby upravit kód. Představte si například následující definici rozhraní API, která používá inteligentní výčty:

// Smart enum.
enum PersonRelationship {
        [Field (null)]
        None,

        [Field ("FMFather", "__Internal")]
        Father,

        [Field ("FMMother", "__Internal")]
        Mother
}

Definice rozhraní:

// Property definition.

[Export ("presenceType")]
NSString _PresenceType { get; set; }

PersonRelationship PresenceType {
    [Wrap ("PersonRelationshipExtensions.GetValue (_PresenceType)")]
    get;
    [Wrap ("_PresenceType = value.GetConstant ()")]
    set;
}

Atributy parametru

Tato část popisuje atributy, které můžete použít na parametry v definici metody a [NullAttribute] také na vlastnosti jako celek.

BlockCallback

Tento atribut se použije u typů parametrů v deklalarací delegátů jazyka C#, aby upozorňují na to, že daný parametr odpovídá Objective-C konvenci volání bloku a měl by ho tímto způsobem zařazovat.

Obvykle se používá pro zpětná volání, která jsou definována takto:Objective-C

typedef returnType (^SomeTypeDefinition) (int parameter1, NSString *parameter2);

Viz také: CCallback.

CCallback

Tento atribut se použije u typů parametrů v deklalarací delegátů jazyka C# a upozorní ho, že daný parametr odpovídá konvenci volání ukazatele funkce C ABI a měl by ho tímto způsobem zařazovat.

Obvykle se používá pro zpětná volání, která jsou definována takto:Objective-C

typedef returnType (*SomeTypeDefinition) (int parameter1, NSString *parameter2);

Viz také: BlockCallback.

Params

Atribut u posledního parametru [Params] pole definice metody můžete použít k tomu, aby generátor v definici vkládal parametr "params". To umožňuje vazbu snadno povolit volitelné parametry.

Například následující definice:

[Export ("loadFiles:")]
void LoadFiles ([Params]NSUrl [] files);

Umožňuje zápis následujícího kódu:

foo.LoadFiles (new NSUrl (url));
foo.LoadFiles (new NSUrl (url1), new NSUrl (url2), new NSUrl (url3));

To má přidanou výhodu, že nevyžaduje, aby uživatelé vytvořili pole čistě pro předávání prvků.

Prostý řetězec

Atribut před řetězcovými parametry můžete použít [PlainString] k pokynu generátoru vazby, aby předal řetězec jako řetězec jazyka C, a nikoli předání parametru jako parametru NSString.

Většina Objective-C rozhraní API využívá NSString parametry, ale několik rozhraní API zveřejňuje char * rozhraní API pro předávání řetězců místo NSString varianty. Používejte [PlainString] v těchto případech.

Například následující Objective-C deklarace:

- (void) setText: (NSString *) theText;
- (void) logMessage: (char *) message;

Měla by být vázána takto:

[Export ("setText:")]
void SetText (string theText);

[Export ("logMessage:")]
void LogMessage ([PlainString] string theText);

RetainAttribute

Dává generátoru pokyn, aby odkazoval na zadaný parametr. Generátor poskytne záložní úložiště pro toto pole nebo můžete zadat název (the WrapName) pro uložení hodnoty na. To je užitečné pro uložení odkazu na spravovaný objekt, který je předán jako parametr Objective-C , a když víte, že Objective-C bude uchovávat pouze tuto kopii objektu. Například rozhraní API jako SetDisplay (SomeObject) by použilo tento atribut, protože je pravděpodobné, že SetDisplay může zobrazit pouze jeden objekt najednou. Pokud potřebujete sledovat více než jeden objekt (například pro rozhraní API podobné zásobníku [RetainList] ), použili byste atribut.

Syntaxe:

public class RetainAttribute {
    public RetainAttribute ();
    public RetainAttribute (string wrapName);
    public string WrapName { get; }
}

Zachovat AtributListAttribute

Dává generátoru pokyn, aby zachoval spravovaný odkaz na parametr nebo odebral interní odkaz na parametr. Slouží k zachování odkazů na objekty.

Syntaxe:

public class RetainListAttribute: Attribute {
     public RetainListAttribute (bool doAdd, string listName);
}

Pokud je hodnota doAdd true, pak se parametr přidá do __mt_{0}_var List<NSObject>. Kde {0} se nahrazuje daným listNameznakem . Toto pomocné pole musíte deklarovat v doplňkové částečné třídě do rozhraní API.

Příklad najdete v tématu foundation.cs a NSNotificationCenter.cs

TransientAttribute

Tento atribut se použije na parametry a používá se pouze při přechodu z Objective-C jazyka C#. Během těchto přechodů jsou různé Objective-CNSObject parametry zabaleny do spravované reprezentace objektu.

Modul runtime vezme odkaz na nativní objekt a ponechá odkaz do posledního spravovaného odkazu na objekt a GC má šanci spustit.

V několika případech je důležité, aby modul runtime jazyka C# neuchovávat odkaz na nativní objekt. K tomu někdy dochází v případě, že základní nativní kód připojil speciální chování k životnímu cyklu parametru. Příklad: Destruktor parametru provede nějakou akci vyčištění nebo odstraní nějaký drahocenný prostředek.

Tento atribut informuje modul runtime, že chcete objekt odstranit, pokud je to možné při návratu zpět Objective-C z přepsáné metody.

Pravidlo je jednoduché: Pokud modul runtime musel vytvořit novou spravovanou reprezentaci z nativního objektu, na konci funkce se zachovají počet zachování nativního objektu a vlastnost Handle spravovaného objektu se vymaže. To znamená, že pokud jste zachovali odkaz na spravovaný objekt, tento odkaz se stane zbytečným (vyvolání metod v něm vyvolá výjimku).

Pokud předaný objekt nebyl vytvořen nebo pokud již existuje nevyřízených spravovaných reprezentací objektu, vynucené vyřazení neproběhne.

Atributy vlastností

NotImplementedAttribute

Tento atribut se používá k podpoře Objective-C idiomu, kde vlastnost s getter je zavedena v základní třídě a proměnlivá podtřída představuje setter.

Vzhledem k tomu, že jazyk C# tento model nepodporuje, musí mít základní třída metodu setter i getter a podtřídu může použít OverrideAttribute.

Tento atribut se používá pouze v setter vlastnosti a slouží k podpoře mutable idiom v Objective-C.

Příklad:

[BaseType (typeof (NSObject))]
interface MyString {
    [Export ("initWithValue:")]
    IntPtr Constructor (string value);

    [Export ("value")]
    string Value {
        get;

    [NotImplemented ("Not available on MyString, use MyMutableString to set")]
        set;
    }
}

[BaseType (typeof (MyString))]
interface MyMutableString {
    [Export ("value")]
    [Override]
    string Value { get; set; }
}

Atributy výčtu

Mapování NSString konstant na výčtové hodnoty je snadný způsob, jak vytvořit lepší rozhraní .NET API. Je to:

  • umožňuje, aby dokončování kódu bylo užitečnější zobrazením pouze správných hodnot pro rozhraní API;
  • přidává bezpečnost typů, nelze použít jinou NSString konstantu v nesprávném kontextu;
  • umožňuje skrýt některé konstanty, aby dokončování kódu zobrazoval kratší seznam rozhraní API bez ztráty funkčnosti.

Příklad:

enum NSRunLoopMode {

    [DefaultEnumValue]
    [Field ("NSDefaultRunLoopMode")]
    Default,

    [Field ("NSRunLoopCommonModes")]
    Common,

    [Field (null)]
    Other = 1000
}

Z výše uvedené definice vazby generátor vytvoří sám sebe enum a také vytvoří *Extensions statický typ, který obsahuje dva způsoby metody převodu mezi hodnotami výčtu NSString a konstanty. To znamená, že konstanty zůstanou dostupné vývojářům i v případě, že nejsou součástí rozhraní API.

Příklady:

// using the NSString constant in a different API / framework / 3rd party code
CallApiRequiringAnNSString (NSRunLoopMode.Default.GetConstant ());
// converting the constants from a different API / framework / 3rd party code
var constant = CallApiReturningAnNSString ();
// back into an enum value
CallApiWithEnum (NSRunLoopModeExtensions.GetValue (constant));

DefaultEnumValueAttribute

Pomocí tohoto atributu můžete ozdobit jednu hodnotu výčtu. To se stane konstantou, která se vrátí, pokud není známa hodnota výčtu.

Z výše uvedeného příkladu:

var x = (NSRunLoopMode) 99;
Call (x.GetConstant ()); // NSDefaultRunLoopMode will be used

Pokud není hodnota výčtu zdobena, NotSupportedException bude vyvolán.

ErrorDomainAttribute

Kódy chyb jsou vázané jako hodnoty výčtu. Doména chyb pro ně obecně existuje a není vždy snadné zjistit, která doména se týká (nebo pokud existuje).

Tento atribut můžete použít k přidružení domény chyby k samotnému výčtu.

Příklad:

[Native]
[ErrorDomain ("AVKitErrorDomain")]
public enum AVKitError : nint {
    None = 0,
    Unknown = -1000,
    PictureInPictureStartFailed = -1001
}

Pak můžete volat metodu GetDomain rozšíření, která získá konstantu domény jakékoli chyby.

FieldAttribute

Jedná se o stejný atribut, který [Field] se používá pro konstanty uvnitř typu. Dá se také použít uvnitř výčtů k mapování hodnoty s konkrétní konstantou.

Hodnotu null lze použít k určení, která hodnota výčtu má být vrácena, pokud je zadána konstanta nullNSString .

Z výše uvedeného příkladu:

var constant = NSRunLoopMode.NewInWatchOS3; // will be null in watchOS 2.x
Call (NSRunLoopModeExtensions.GetValue (constant)); // will return 1000

Pokud není k dispozici žádná null hodnota, vyvolá se chyba ArgumentNullException .

Globální atributy

Globální atributy se použijí buď pomocí modifikátoru atributu [assembly:] , jako je například atribut [LinkWithAttribute] , nebo se dají použít kdekoli, jako jsou atributy [Lion] a [Since] atributy.

LinkWithAttribute

Jedná se o atribut na úrovni sestavení, který vývojářům umožňuje zadat příznaky propojení vyžadované k opakovanému použití vázané knihovny bez vynucení příjemce knihovny k ruční konfiguraci gcc_flags a dalších argumentů mtouch předaných knihovně.

Syntaxe:

// In properties
[Flags]
public enum LinkTarget {
    Simulator    = 1,
    ArmV6    = 2,
    ArmV7    = 4,
    Thumb    = 8,
}

[AttributeUsage(AttributeTargets.Assembly, AllowMultiple=true)]
public class LinkWithAttribute : Attribute {
    public LinkWithAttribute ();
    public LinkWithAttribute (string libraryName);
    public LinkWithAttribute (string libraryName, LinkTarget target);
    public LinkWithAttribute (string libraryName, LinkTarget target, string linkerFlags);
    public bool ForceLoad { get; set; }
    public string Frameworks { get; set; }
    public bool IsCxx { get; set;  }
    public string LibraryName { get; }
    public string LinkerFlags { get; set; }
    public LinkTarget LinkTarget { get; set; }
    public bool NeedsGccExceptionHandling { get; set; }
    public bool SmartLink { get; set; }
    public string WeakFrameworks { get; set; }
}

Tento atribut se používá například na úrovni sestavení, které používají vazby CorePlot:

[assembly: LinkWith ("libCorePlot-CocoaTouch.a", LinkTarget.ArmV7 | LinkTarget.ArmV7s | LinkTarget.Simulator, Frameworks = "CoreGraphics QuartzCore", ForceLoad = true)]

Při použití atributu [LinkWith] je zadaný libraryName vložen do výsledného sestavení, což uživatelům umožňuje odeslat jednu knihovnu DLL, která obsahuje nespravované závislosti i příznaky příkazového řádku potřebné k správnému využívání knihovny z Xamarin.iOS.

Není také možné zadat libraryName, v takovém případě LinkWith lze atribut použít pouze k určení dalších příznaků linkeru:

[assembly: LinkWith (LinkerFlags = "-lsqlite3")]

Konstruktory LinkWithAttribute

Tyto konstruktory umožňují určit knihovnu pro propojení a vložení do výsledného sestavení, podporované cíle, které knihovna podporuje, a všechny volitelné příznaky knihovny, které jsou nezbytné pro propojení s knihovnou.

Všimněte si, že LinkTarget argument je odvozen xamarin.iOS a není nutné ho nastavit.

Příklady:

// Specify additional linker:
[assembly: LinkWith (LinkerFlags = "-sqlite3")]

// Specify library name for the constructor:
[assembly: LinkWith ("libDemo.a");

// Specify library name, and link target for the constructor:
[assembly: LinkWith ("libDemo.a", LinkTarget.Thumb | LinkTarget.Simulator);

// Specify only the library name, link target and linker flags for the constructor:
[assembly: LinkWith ("libDemo.a", LinkTarget.Thumb | LinkTarget.Simulator, SmartLink = true, ForceLoad = true, IsCxx = true);

LinkWithAttribute.ForceLoad

Vlastnost ForceLoad se používá k rozhodnutí, zda -force_load se příznak odkazu používá pro propojení nativní knihovny. Prozatím by to mělo být vždy pravdivé.

LinkWithAttribute.Frameworks

Pokud vázání knihovny má pevný požadavek na jakékoli architektury (jiné než Foundation a UIKit), měli byste nastavit Frameworks vlastnost na řetězec obsahující seznam s oddělovači mezerami požadovaných architektur platformy. Například pokud vytváříte vazbu knihovny, která vyžaduje CoreGraphics , a CoreText, byste vlastnost nastavili Frameworks na "CoreGraphics CoreText".

LinkWithAttribute.IsCxx

Nastavte tuto vlastnost na hodnotu true, pokud je nutné výsledný spustitelný soubor zkompilovat pomocí kompilátoru jazyka C++ namísto výchozího kompilátoru jazyka C, což je kompilátor jazyka C. Tuto možnost použijte, pokud byla knihovna, kterou vytváříte vazbu, zapsána v jazyce C++.

LinkWithAttribute.LibraryName

Název nespravované knihovny, která se má seskupit. Jedná se o soubor s příponou ".a" a může obsahovat kód objektu pro více platforem (například ARM a x86 pro simulátor).

Starší verze Xamarin.iOS zkontrolovaly LinkTarget vlastnost, aby určila platformu, která je podporovaná, ale tato možnost je nyní automaticky zjištěna a LinkTarget vlastnost se ignoruje.

LinkWithAttribute.LinkerFlags

Řetězec LinkerFlags poskytuje autorům vazby způsob, jak určit všechny další příznaky linkeru potřebné při propojení nativní knihovny s aplikací.

Pokud například nativní knihovna vyžaduje knihovnu LinkerFlags libxml2 a zlib, nastavíte řetězec na "-lxml2 -lz"hodnotu .

LinkWithAttribute.LinkTarget

Starší verze Xamarin.iOS zkontrolovaly LinkTarget vlastnost, aby určila platformu, která je podporovaná, ale tato možnost je nyní automaticky zjištěna a LinkTarget vlastnost se ignoruje.

LinkWithAttribute.NeedsGccExceptionHandling

Nastavte tuto vlastnost na true, pokud knihovna, kterou propojíte, vyžaduje knihovnu GCC Exception Handling (gcc_eh).

Vlastnost SmartLink by měla být nastavena na hodnotu true, aby Xamarin.iOS určila, zda ForceLoad je požadována, nebo ne.

LinkWithAttribute.WeakFrameworks

Vlastnost WeakFrameworks funguje stejně jako Frameworks vlastnost, s tím rozdílem, že v době propojení je -weak_framework specifikátor předán gcc pro každou z uvedených architektur.

WeakFrameworks umožňuje, aby knihovny a aplikace slabě odkazovaly na architektury platforem, aby je mohly volitelně používat, pokud jsou dostupné, ale nezabírají na nich pevnou závislost, což je užitečné, pokud je vaše knihovna určená k přidání dalších funkcí v novějších verzích iOSu. Další informace o slabém propojení najdete v dokumentaci společnosti Apple ke slabému propojení.

Dobrými kandidáty pro slabé propojení by byly Frameworks účty, CoreBluetooth, CoreImage, NewsstandKitGLKita Twitter protože jsou k dispozici pouze v iOS 5.

SinceAttribute (iOS) a LionAttribute (macOS)

Tento atribut použijete [Since] k označení rozhraní API tak, aby se v určitém okamžiku zavedla. Atribut by se měl použít pouze k označení typů a metod, které by mohly způsobit problém za běhu, pokud podkladová třída, metoda nebo vlastnost není k dispozici.

Syntaxe:

public SinceAttribute : Attribute {
     public SinceAttribute (byte major, byte minor);
     public byte Major, Minor;
}

Obecně by se nemělo používat na výčty, omezení nebo nové struktury, protože ty by nezpůsobily chybu za běhu, pokud se spustí na zařízení se starší verzí operačního systému.

Příklad použití u typu:

// Type introduced with iOS 4.2
[Since (4,2)]
[BaseType (typeof (UIPrintFormatter))]
interface UIViewPrintFormatter {
    [Export ("view")]
    UIView View { get; }
}

Příklad při použití u nového člena:

[BaseType (typeof (UIViewController))]
public interface UITableViewController {
    [Export ("tableView", ArgumentSemantic.Retain)]
    UITableView TableView { get; set; }

    [Since (3,2)]
    [Export ("clearsSelectionOnViewWillAppear")]
    bool ClearsSelectionOnViewWillAppear { get; set; }

Atribut [Lion] se použije stejným způsobem, ale u typů zavedených s Lionem. Důvodem použití [Lion] oproti konkrétnějšímu počtu verzí, které se používá v iOSu, je, že se iOS velmi často reviduje, zatímco hlavní verze OS X se vyskytují zřídka a operační systém je jednodušší zapamatovat podle názvu kódu než podle čísla jejich verze.

AdviceAttribute

Tento atribut použijte k tomu, abyste vývojářům poskytli nápovědu k dalším rozhraním API, která by mohla být pro jejich použití pohodlnější. Pokud například zadáte verzi rozhraní API silného typu, můžete tento atribut použít u slabě napsaného atributu k nasměrování vývojáře na lepší rozhraní API.

Informace z tohoto atributu jsou uvedeny v dokumentaci a nástrojích lze vyvinout, aby uživatelům poskytly návrhy na zlepšení.

VyžadujeSuperAttribute

Jedná se o specializovanou podtřídu atributu [Advice] , kterou lze použít k nápovědě pro vývojáře, že přepsání metody vyžaduje volání základní (přepisované) metody.

To odpovídá clang__attribute__((objc_requires_super))

ZeroCopyStringsAttribute

K dispozici pouze v Xamarin.iOS 5.4 a novějším.

Tento atribut dává generátoru pokyn, aby vazba pro tuto konkrétní knihovnu (pokud je použita [assembly:]s) nebo typ by měla používat rychlé zařazování řetězců nulové kopie. Tento atribut je ekvivalentní předání možnosti --zero-copy příkazového řádku generátoru.

Při použití nulové kopie pro řetězce generátor efektivně používá stejný řetězec C# jako řetězec, který Objective-C spotřebovává, aniž by došlo k vytvoření nového NSString objektu a vyhnout se kopírování dat z řetězců jazyka C#do Objective-C řetězce. Jedinou nevýhodou použití řetězců nulové kopie je, že musíte zajistit, aby všechny řetězcové vlastnosti, které zalamujete, které se stane označeny příznakem nebo retaincopy[DisableZeroCopy] nastaven atribut. To je vyžadováno, protože popisovač řetězců nulové kopie je přidělen v zásobníku a při vrácení funkce je neplatný.

Příklad:

[ZeroCopyStrings]
[BaseType (typeof (NSObject))]
interface MyBinding {
    [Export ("name")]
    string Name { get; set; }

    [Export ("domain"), NullAllowed]
    string Domain { get; set; }

    [DisablZeroCopy]
    [Export ("someRetainedNSString")]
    string RetainedProperty { get; set; }
}

Můžete také použít atribut na úrovni sestavení a bude platit pro všechny typy sestavení:

[assembly:ZeroCopyStrings]

Slovníky se silnými typy

S Xamarin.iOS 8.0 jsme zavedli podporu pro snadné vytváření tříd silného typu, které zabalí NSDictionaries.

I když bylo vždy možné použít datový typ DictionaryContainer společně s ručním rozhraním API, je teď mnohem jednodušší to udělat. Další informace naleznete v tématu Surfacing Strong Types.

StrongDictionary

Pokud se tento atribut použije na rozhraní, generátor vytvoří třídu se stejným názvem jako rozhraní, které je odvozeno z DictionaryContainer a změní každou vlastnost definovanou v rozhraní na výraz getter a setter pro slovník.

Tím se automaticky vygeneruje třída, která může být vytvořena z existujícího NSDictionary nebo vytvořeného nového.

Tento atribut přebírá jeden parametr, název třídy obsahující klíče, které se používají pro přístup k prvkům ve slovníku. Ve výchozím nastavení každá vlastnost v rozhraní s atributem vyhledá člen v zadaném typu pro název s příponou "Klíč".

Příklad:

[StrongDictionary ("MyOptionKeys")]
interface MyOption {
    string Name { get; set; }
    nint    Age  { get; set; }
}

[Static]
interface MyOptionKeys {
    // In Objective-C this is "NSString *MYOptionNameKey;"
    [Field ("MYOptionNameKey")]
    NSString NameKey { get; }

    // In Objective-C this is "NSString *MYOptionAgeKey;"
    [Field ("MYOptionAgeKey")]
    NSString AgeKey { get; }
}

V předchozím případě třída vytvoří řetězcovou vlastnost, MyOptionName která použije MyOptionKeys.NameKey jako klíč do slovníku k načtení řetězce. A použije MyOptionKeys.AgeKey jako klíč do slovníku k načtení NSNumber int.

Pokud chcete použít jiný klíč, můžete pro vlastnost použít atribut exportu, například:

[StrongDictionary ("MyColoringKeys")]
interface MyColoringOptions {
    [Export ("TheName")]  // Override the default which would be NameKey
    string Name { get; set; }

    [Export ("TheAge")] // Override the default which would be AgeKey
    nint    Age  { get; set; }
}

[Static]
interface MyColoringKeys {
    // In Objective-C this is "NSString *MYColoringNameKey"
    [Field ("MYColoringNameKey")]
    NSString TheName { get; }

    // In Objective-C this is "NSString *MYColoringAgeKey"
    [Field ("MYColoringAgeKey")]
    NSString TheAge { get; }
}

Silné typy slovníků

Definice podporuje StrongDictionary následující datové typy:

Typ rozhraní jazyka C# NSDictionary Typ úložiště
bool Boolean uložená v NSNumber
Hodnoty výčtu celé číslo uložené v NSNumber
int 32bitové celé číslo uložené v NSNumber
uint 32bitové celé číslo bez znaménka uložené v NSNumber
nint NSInteger uložená v NSNumber
nuint NSUInteger uložená v NSNumber
long 64bitové celé číslo uložené v NSNumber
float 32bitové celé číslo uložené jako NSNumber
double 64bitové celé číslo uložené jako NSNumber
NSObject a podtřídy NSObject
NSDictionary NSDictionary
string NSString
NSString NSString
C# Array z NSObject NSArray
C# Array výčtů NSArray obsahující NSNumber hodnoty