Udostępnij za pośrednictwem


Przewodnik referencyjny dotyczący typów powiązań

W tym dokumencie opisano listę atrybutów, których można użyć do dodawania adnotacji do plików kontraktów interfejsu API w celu napędzania powiązania i wygenerowanego kodu

Kontrakty interfejsów API platform Xamarin.iOS i Xamarin.Mac są zapisywane w języku C# głównie jako definicje interfejsu definiujące sposób, w jaki Objective-C kod jest wyświetlany w języku C#. Proces obejmuje kombinację deklaracji interfejsu oraz niektóre podstawowe definicje typów, których może wymagać kontrakt interfejsu API. Aby zapoznać się z wprowadzeniem do typów powiązań, zobacz nasz przewodnik Objective-C po wiązaniach bibliotek.

Definicje typów

Składnia:

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

Każdy interfejs w definicji kontraktu [BaseType] , który ma atrybut deklaruje typ podstawowy dla wygenerowanego obiektu. W powyższej deklaracji zostanie wygenerowany MyType typ klasy C#, który wiąże się z typem Objective-C o nazwie MyType.

Jeśli określisz jakiekolwiek typy po nazwie typename (w przykładzie powyżej Protocol1 i Protocol2) przy użyciu składni dziedziczenia interfejsu zawartość tych interfejsów zostanie wciśnięta tak, jakby były częścią kontraktu dla MyTypeelementu . Sposób, w jaki platforma Xamarin.iOS powierzchnie typu przyjmują protokół, polega na podkreśliniu wszystkich metod i właściwości, które zostały zadeklarowane w protokole w samym typie.

Poniżej przedstawiono sposób Objective-C definiowania deklaracji w UITextField kontrakcie platformy Xamarin.iOS:

@interface UITextField : UIControl <UITextInput> {

}

Zostanie napisany w ten sposób jako kontrakt interfejsu API języka C#:

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

Możesz kontrolować wiele innych aspektów generowania kodu, stosując inne atrybuty do interfejsu [BaseType] , a także konfigurując atrybut.

Generowanie zdarzeń

Jedną z funkcji projektowania interfejsu API Xamarin.iOS.i Xamarin.Mac jest mapowanie Objective-C klas delegatów jako zdarzeń języka C# i wywołań zwrotnych. Użytkownicy mogą wybrać w poszczególnych wystąpieniach, czy chcą przyjąć Objective-C wzorzec programowania, przypisując do właściwości, takich jak Delegate wystąpienie klasy, które implementuje różne metody Objective-C wywoływane przez środowisko uruchomieniowe, lub wybierając zdarzenia i właściwości w stylu C#.

Zobaczmy jeden przykład użycia 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 ();
    }
}

W powyższym przykładzie widać, że wybraliśmy zastąpienie dwóch metod: jedno powiadomienie o tym, że miało miejsce zdarzenie przewijania, a drugi jest wywołaniem zwrotnym, które powinno zwrócić wartość logiczną, określającą scrollView , czy powinna zostać przewinięta do góry, czy nie.

Model języka C# umożliwia użytkownikowi biblioteki nasłuchiwanie powiadomień przy użyciu składni zdarzeń języka C# lub składni właściwości w celu podłączenia wywołań zwrotnych, które mają zwracać wartości.

W ten sposób kod języka C# dla tej samej funkcji wygląda następująco:

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

Ponieważ zdarzenia nie zwracają wartości (mają zwracany typ void), można połączyć wiele kopii. Nie ShouldScrollToTop jest to zdarzenie, zamiast tego jest to właściwość o typie UIScrollViewCondition , który ma ten podpis:

public delegate bool UIScrollViewCondition (UIScrollView scrollView);

bool Zwraca wartość, w tym przypadku składnia lambda pozwala nam po prostu zwrócić wartość z MakeDecision funkcji.

Generator powiązań obsługuje generowanie zdarzeń i właściwości, które łączą klasę podobną UIScrollView do jej UIScrollViewDelegate (dobrze wywołaj tę klasę modelu), jest to wykonywane przez dodawanie adnotacji [BaseType] do definicji za pomocą Events parametrów i Delegates (opisanych poniżej). Oprócz dodawania adnotacji [BaseType] do tych parametrów konieczne jest informowanie generatora o kilku kolejnych składnikach.

W przypadku zdarzeń, które przyjmują więcej niż jeden parametr (w Objective-C konwencji jest to, że pierwszy parametr w klasie delegata jest wystąpieniem obiektu nadawcy) należy podać nazwę, którą chcesz, aby wygenerowana EventArgs klasa miała być. Jest to wykonywane z atrybutem [EventArgs] w deklaracji metody w klasie Model. Na przykład:

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

Powyższa deklaracja wygeneruje klasę UIImagePickerImagePickedEventArgs , która pochodzi z EventArgs parametrów i pakuje zarówno parametry , jak UIImage i NSDictionary. Generator generuje następujące dane:

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

Następnie uwidacznia następujące elementy w UIImagePickerController klasie:

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

Metody modelu zwracające wartość są powiązane inaczej. Wymagają one zarówno nazwy wygenerowanego delegata języka C# (podpisu metody), jak i wartości domyślnej zwracanej w przypadku, gdy użytkownik nie udostępnia implementacji. Na przykład ShouldScrollToTop definicja to:

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

Powyższe polecenie spowoduje utworzenie delegata UIScrollViewCondition z podpisem, który został przedstawiony powyżej, a jeśli użytkownik nie dostarczy implementacji, wartość zwracana będzie true.

Oprócz atrybutu [DefaultValue] można również użyć atrybutu [DefaultValueFromArgument] , który kieruje generator do zwrócenia wartości określonego parametru w wywołaniu lub parametru [NoDefaultValue] , który instruuje generator, że nie ma wartości domyślnej.

BaseTypeAttribute

Składnia:

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

Właściwość służy do kontrolowania Name nazwy, z którą ten typ będzie wiązany na Objective-C świecie. Jest to zwykle używane do nadania typowi C# nazwy zgodnej z wytycznymi projektowymi programu .NET Framework, ale które mapuje na nazwę, Objective-C która nie jest zgodna z tą konwencją.

Na przykład w poniższym przypadku zamapujemy Objective-CNSURLConnection typ na NSUrlConnection, ponieważ wytyczne dotyczące projektowania programu .NET Framework używają adresu URL zamiast "URL":

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

Określona nazwa jest używana jako wartość wygenerowanego [Register] atrybutu w powiązaniu. Jeśli Name nie zostanie określona, krótka nazwa typu jest używana jako wartość atrybutu [Register] w wygenerowanych danych wyjściowych.

BaseType.Events i BaseType.Delegates

Te właściwości są używane do generowania zdarzeń w stylu C#w wygenerowanych klasach. Są one używane do łączenia danej klasy z jej Objective-C klasą delegata. Napotkasz wiele przypadków, w których klasa używa klasy delegata do wysyłania powiadomień i zdarzeń. Na przykład klasa BarcodeScanner towarzysza będzie miała klasę towarzyszącą BardodeScannerDelegate . Klasa BarcodeScanner zazwyczaj ma Delegate właściwość, do której można przypisać wystąpienie BarcodeScannerDelegate klasy , chociaż działa to, możesz chcieć uwidocznić użytkownikom interfejs zdarzenia w stylu C#, a w takich przypadkach należy użyć Events właściwości i Delegates atrybutu [BaseType] .

Te właściwości są zawsze ustawiane razem i muszą mieć taką samą liczbę elementów i być zsynchronizowane. Tablica Delegates zawiera jeden ciąg dla każdego słabo wpisanego delegata, który ma zostać zawijany, a Events tablica zawiera jeden typ dla każdego typu, który chcesz skojarzyć z nim.

[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

Jeśli zastosujesz ten atrybut po utworzeniu nowych wystąpień tej klasy, wystąpienie tego obiektu będzie przechowywane do momentu wywołania metody przywoływanej KeepRefUntil przez klasę . Jest to przydatne, aby zwiększyć użyteczność interfejsów API, gdy nie chcesz, aby użytkownik używał odwołania do obiektu w celu korzystania z kodu. Wartość tej właściwości jest nazwą metody w Delegate klasie, więc należy jej użyć w połączeniu z właściwościami Events i Delegates .

W poniższym przykładzie pokazano, jak jest to używane w UIActionSheet środowisku 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

Gdy ten atrybut zostanie zastosowany do definicji interfejsu, wygeneruje [DesignatedInitializer] atrybut w domyślnym (wygenerowanym) konstruktorze init , który jest mapowany na selektor.

DisableDefaultCtorAttribute

Zastosowanie tego atrybutu do definicji interfejsu uniemożliwi generatorowi tworzenie konstruktora domyślnego.

Użyj tego atrybutu, jeśli potrzebujesz obiektu, aby został zainicjowany przy użyciu jednego z innych konstruktorów w klasie.

PrivateDefaultCtorAttribute

Po zastosowaniu tego atrybutu do definicji interfejsu będzie on flagą konstruktora domyślnego jako prywatny. Oznacza to, że nadal można utworzyć wystąpienie obiektu tej klasy wewnętrznie z pliku rozszerzenia, ale po prostu nie będzie dostępny dla użytkowników klasy.

Categoryattribute

Użyj tego atrybutu w definicji typu, aby powiązać Objective-C kategorie i uwidocznić te jako metody rozszerzenia języka C#, aby zdublować sposób Objective-C uwidacznia funkcje.

Kategorie to Objective-C mechanizm służący do rozszerzania zestawu metod i właściwości dostępnych w klasie. W praktyce są one używane do rozszerzania funkcjonalności klasy bazowej (na przykład NSObject), gdy określona struktura jest połączona (na przykład UIKit), udostępniając ich metody, ale tylko wtedy, gdy nowa struktura jest połączona. W niektórych innych przypadkach są one używane do organizowania funkcji w klasie według funkcji. Są one podobne do metod rozszerzeń języka C#.

Oto, jak wygląda kategoria w pliku Objective-C:

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

Powyższy przykład znajduje się w bibliotece, która rozszerza wystąpienia UIView klasy za pomocą metody makeBackgroundRed.

Aby je powiązać, możesz użyć atrybutu [Category] w definicji interfejsu. W przypadku używania atrybutu [Category] znaczenie atrybutu [BaseType] zmienia się z używanego do określania klasy bazowej do rozszerzenia, do bycia typem do rozszerzenia.

Poniżej pokazano, jak UIView rozszerzenia są powiązane i przekształcone w metody rozszerzeń języka C#:

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

Powyższe spowoduje MyUIViewExtension utworzenie klasy zawierającej metodę MakeBackgroundRed rozszerzenia. Oznacza to, że teraz możesz wywołać dowolną MakeBackgroundRedUIView podklasę, zapewniając taką samą funkcjonalność, jaką można uzyskać w systemie Objective-C.

W niektórych przypadkach znajdziesz statyczne elementy członkowskie wewnątrz kategorii, jak w poniższym przykładzie:

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

Spowoduje to niepoprawną definicję interfejsu Kategorii C#:

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

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

Jest to nieprawidłowe, ponieważ do korzystania z BoolMethod rozszerzenia potrzebne jest wystąpienieFooObject, ale wiążesz rozszerzenie statyczne ObjC, jest to efekt uboczny ze względu na fakt implementacji metod rozszerzeń języka C#.

Jedynym sposobem użycia powyższych definicji jest następujący brzydki kod:

(null as FooObject).BoolMethod (range);

Zaleceniem, aby tego uniknąć, jest śródliniowa BoolMethod definicja wewnątrz samej definicji interfejsu FooObject , co umożliwi wywołanie tego rozszerzenia, tak jak ma to na celu FooObject.BoolMethod (range).

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

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

Podczas znajdowania [Static] elementu członkowskiego w [Category] definicji zostanie wyświetlone ostrzeżenie (BI1117). Jeśli naprawdę chcesz mieć [Static] członków wewnątrz definicji [Category] , możesz wyciszyć ostrzeżenie za pomocą [Category (allowStaticMembers: true)] funkcji lub dekorując definicję elementu członkowskiego lub [Category] interfejsu za [Internal]pomocą polecenia .

StaticAttribute

Gdy ten atrybut zostanie zastosowany do klasy, po prostu wygeneruje klasę statyczną, która nie pochodzi z NSObjectklasy , więc [BaseType] atrybut jest ignorowany. Klasy statyczne są używane do hostowania zmiennych publicznych języka C, które chcesz uwidocznić.

Na przykład:

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

Wygeneruje klasę języka C# przy użyciu następującego interfejsu API:

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

Definicje protokołu/modelu

Modele są zwykle używane przez implementację protokołu. Różnią się one tym, że środowisko uruchomieniowe będzie rejestrować się tylko przy użyciu Objective-C metod, które faktycznie zostały zastąpione. W przeciwnym razie metoda nie zostanie zarejestrowana.

Ogólnie rzecz biorąc, oznacza to, że w przypadku podklasy klasy, która została oflagowana za pomocą ModelAttributeklasy , nie należy wywoływać metody podstawowej. Wywołanie tej metody spowoduje zgłoszenie następującego wyjątku: Foundation.You_Should_Not_Call_base_In_This_Method. Należy zaimplementować całe zachowanie w podklasie dla wszystkich metod, które zastąpisz.

AbstractAttribute

Domyślnie elementy członkowskie będące częścią protokołu nie są obowiązkowe. Dzięki temu użytkownicy mogą utworzyć podklasę Model obiektu jedynie wyprowadzając ją z klasy w języku C# i zastępując tylko metody, o których dbają. Czasami Objective-C kontrakt wymaga, aby użytkownik zapewnia implementację dla tej metody (te zostały oflagowane z dyrektywą @required w pliku Objective-C). W takich przypadkach należy oznaczyć te metody atrybutem [Abstract] .

Atrybut [Abstract] można zastosować do metod lub właściwości i powoduje, że generator flaguje wygenerowany element członkowski jako abstrakcyjny i klasę jako klasę abstrakcyjną.

Z platformy Xamarin.iOS pochodzą następujące elementy:

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

Defaultvalueattribute

Określa wartość domyślną, która ma być zwracana przez metodę modelu, jeśli użytkownik nie udostępnia metody dla tej konkretnej metody w obiekcie Modelu

Składnia:

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

Na przykład w następującej wyimaginowanej klasie delegata dla Camera klasy udostępniamy element ShouldUploadToServer , który będzie uwidoczniony jako właściwość klasy Camera . Jeśli użytkownik Camera klasy nie ustawi jawnie wartości lambda, która może odpowiedzieć na wartość true lub false, wartość domyślna zwracana w tym przypadku będzie false, wartość określona w atrybucie DefaultValue :

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

Jeśli użytkownik ustawia procedurę obsługi w klasie wyimaginowanej, ta wartość zostanie zignorowana:

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

Zobacz również: [NoDefaultValue], [DefaultValueFromArgument].

DefaultValueFromArgumentAttribute

Składnia:

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

Ten atrybut podany w metodzie zwracającej wartość w klasie modelu spowoduje, że generator zwróci wartość określonego parametru, jeśli użytkownik nie podał własnej metody lub lambda.

Przykład:

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

W powyższym przypadku, jeśli użytkownik NSAnimation klasy zdecydował się użyć dowolnego z zdarzeń/właściwości języka C# i nie ustawił NSAnimation.ComputeAnimationCurve metody lub lambdy, wartość zwracana będzie wartością przekazaną w parametrze progress.

Zobacz również: [NoDefaultValue], [DefaultValue]

IgnoredInDelegateAttribute

Czasami nie ma sensu uwidaczniać zdarzenia lub delegować właściwości z klasy modelu do klasy hosta, dlatego dodanie tego atrybutu spowoduje, że generator będzie nakazał generatorowi uniknięcie generowania dowolnej metody ozdobionej nią.

[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

Ten atrybut jest używany w metodach modelu, które zwracają wartości, aby ustawić nazwę podpisu delegowanego do użycia.

Przykład:

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

Po powyższej definicji generator utworzy następującą deklarację publiczną:

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

DelegateApiNameAttribute

Ten atrybut umożliwia generatorowi zmianę nazwy właściwości wygenerowanej w klasie hosta. Czasami jest to przydatne, gdy nazwa metody klasy FooDelegate ma sens dla klasy Delegate, ale wygląda dziwnie w klasie hosta jako właściwości.

Jest to również naprawdę przydatne (i potrzebne), jeśli masz co najmniej dwie metody przeciążenia, które mają sens, aby zachować je nazwane jako w klasie FooDelegate, ale chcesz uwidocznić je w klasie hosta o lepszej nazwie.

Przykład:

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

Po powyższej definicji generator utworzy następującą deklarację publiczną w klasie hosta:

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

EventArgsAttribute

W przypadku zdarzeń, które przyjmują więcej niż jeden parametr (w Objective-C konwencji jest to, że pierwszy parametr w klasie delegata jest wystąpieniem obiektu nadawcy) należy podać nazwę, którą chcesz, aby wygenerowana klasa EventArgs miała być. Jest to wykonywane z atrybutem [EventArgs] w deklaracji metody w Model klasie.

Na przykład:

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

Powyższa deklaracja wygeneruje klasę pochodzącą UIImagePickerImagePickedEventArgs z klasy EventArgs i pakuje zarówno parametry , jak i UIImageNSDictionary. Generator generuje następujące dane:

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

Następnie uwidacznia następujące elementy w UIImagePickerController klasie:

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

EventNameAttribute

Ten atrybut umożliwia generatorowi zmianę nazwy zdarzenia lub właściwości wygenerowanej w klasie. Czasami jest to przydatne, gdy nazwa metody klasy modelu ma sens dla klasy modelu, ale wygląda dziwnie w klasie źródłowej jako zdarzenie lub właściwość.

Na przykład parametr UIWebView używa następującego bitu z elementu UIWebViewDelegate:

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

Powyższe dane uwidacznia LoadingFinished jako metodę w elemecie UIWebViewDelegate, ale LoadFinished jako zdarzenie, do których należy podłączyć element w elemecie UIWebView:

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

ModelAttribute

Po zastosowaniu atrybutu [Model] do definicji typu w interfejsie API kontraktu środowisko uruchomieniowe wygeneruje specjalny kod, który będzie wyświetlać wywołania tylko do metod w klasie, jeśli użytkownik nadpisał metodę w klasie. Ten atrybut jest zwykle stosowany do wszystkich interfejsów API, które opakowuje klasę delegata Objective-C .

Środowisko uruchomieniowe wygeneruje również klasę zgodną Objective-C z nazwą odpowiedniego protokołu.

Można dostosować nazwę Objective-C klasy na dwa sposoby:

  1. Ustawienie AutoGeneratedName = true:

    [Model (AutoGeneratedName = true)]
    

    Spowoduje to wygenerowanie przez środowisko uruchomieniowe unikatowej nazwy dla Objective-C typu. Nazwa jest obecnie oparta na nazwie zestawu i pełnej nazwie typu modelu (może to ulec zmianie w przyszłości).

  2. Jawne określanie nazwy:

    [Model (Name = "CustomName")]
    

Zaleca się użycie polecenia AutoGeneratedName = true. Na platformie .NET nazwa jest zawsze generowana (chyba że jest jawnie określona jako w 2. powyżej), a AutoGeneratedName właściwość już nie istnieje.

NoDefaultValueAttribute

Określa, że metoda w modelu nie udostępnia domyślnej wartości zwracanej.

Działa to z Objective-C środowiskiem uruchomieniowym, odpowiadając na falseObjective-C żądanie środowiska uruchomieniowego w celu określenia, czy określony selektor jest zaimplementowany w tej klasie.

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

Zobacz również: [DefaultValue], [DefaultValueFromArgument]

Protokoły

Koncepcja Objective-C protokołu nie istnieje w języku C#. Protokoły są podobne do interfejsów języka C#, ale różnią się, że nie wszystkie metody i właściwości zadeklarowane w protokole muszą być implementowane przez klasę, która ją przyjmuje. Zamiast niektórych metod i właściwości są opcjonalne.

Niektóre protokoły są zwykle używane jako klasy modelu. Należy je powiązać przy użyciu atrybutu [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 ();
}

Począwszy od platformy Xamarin.iOS 7.0 została włączona nowa i ulepszona funkcja powiązania protokołu. Każda definicja zawierająca [Protocol] atrybut faktycznie wygeneruje trzy klasy pomocnicze, które znacznie poprawią sposób korzystania z protokołów:

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

Implementacja klasy zapewnia kompletną abstrakcyjną klasę, którą można zastąpić poszczególnymi metodami i uzyskać bezpieczeństwo pełnego typu. Jednak ze względu na to, że język C# nie obsługuje wielu dziedziczenia, istnieją scenariusze, w których może być wymagana inna klasa bazowa, ale nadal chcesz zaimplementować interfejs.

W tym miejscu znajduje się definicja wygenerowanego interfejsu . Jest to interfejs, który ma wszystkie wymagane metody z protokołu. Dzięki temu deweloperzy, którzy chcą zaimplementować protokół tylko zaimplementować interfejs. Środowisko uruchomieniowe automatycznie zarejestruje typ jako przyjmujący protokół.

Zwróć uwagę, że interfejs wyświetla tylko wymagane metody i udostępnia opcjonalne metody. Oznacza to, że klasy, które przyjmują protokół, uzyskają pełne sprawdzanie typów dla wymaganych metod, ale będą musiały uciekać się do słabego wpisywania (ręcznie przy użyciu atrybutów Eksportuj i dopasowywania podpisu) dla opcjonalnych metod protokołu.

Aby ułatwić korzystanie z interfejsu API korzystającego z protokołów, narzędzie powiązania utworzy również klasę metody rozszerzeń, która uwidacznia wszystkie metody opcjonalne. Oznacza to, że o ile korzystasz z interfejsu API, będziesz w stanie traktować protokoły jako wszystkie metody.

Jeśli chcesz użyć definicji protokołu w interfejsie API, musisz napisać szkieletowe puste interfejsy w definicji interfejsu API. Jeśli chcesz użyć aplikacji MyProtocol w interfejsie API, musisz wykonać następujące czynności:

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

Powyższe elementy są potrzebne, ponieważ w momencie IMyProtocol powiązania obiekt nie istnieje, dlatego należy podać pusty interfejs.

Wdrażanie interfejsów generowanych przez protokół

Za każdym razem, gdy implementujesz jeden z interfejsów generowanych dla protokołów, w następujący sposób:

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

Implementacja wymaganych metod interfejsu jest eksportowana z odpowiednią nazwą, więc jest ona równoważna następującemu:

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

Będzie to działać dla wszystkich wymaganych elementów członkowskich protokołu, ale istnieje szczególny przypadek z opcjonalnymi selektorami, o których należy pamiętać.

Opcjonalne elementy członkowskie protokołu są traktowane identycznie podczas korzystania z klasy bazowej:

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

ale w przypadku korzystania z interfejsu protokołu jest wymagany do dodania [Eksportuj]. Środowisko IDE doda je za pośrednictwem autouzupełniania po dodaniu, rozpoczynając od zastąpienia.

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

Istnieje niewielka różnica między zachowaniem dwóch w czasie wykonywania:

  • Użytkownicy klasy bazowej (NSUrlSessionDownloadDelegate w przykładzie) udostępniają wszystkie wymagane i opcjonalne selektory, zwracając rozsądne wartości domyślne.
  • Użytkownicy interfejsu (INSUrlSessionDownloadDelegate w przykładzie) reagują tylko na podane selektory.

Niektóre rzadkie klasy mogą zachowywać się inaczej tutaj. W prawie wszystkich przypadkach można jednak bezpiecznie użyć.

Inlining protokołu

Po powiązaniu istniejących Objective-C typów, które zostały zadeklarowane jako przyjmując protokół, należy bezpośrednio umieścić protokół w tekście. W tym celu należy jedynie zadeklarować protokół jako interfejs bez żadnego [BaseType] atrybutu i wyświetlić protokół na liście interfejsów podstawowych.

Przykład:

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

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

Definicje składowych

Atrybuty w tej sekcji są stosowane do poszczególnych elementów członkowskich typu: właściwości i deklaracje metody.

AlignAttribute

Służy do określania wartości wyrównania dla typów zwracanych właściwości. Niektóre właściwości przyjmują wskaźniki do adresów, które muszą być wyrównane do określonych granic (w środowisku Xamarin.iOS dzieje się tak na przykład z niektórymi GLKBaseEffect właściwościami, które muszą być wyrównane 16 bajtów). Za pomocą tej właściwości można ozdobić getter i użyć wartości wyrównania. Jest to zwykle używane z typami OpenTK.Vector4 i OpenTK.Matrix4 w przypadku integracji z Objective-C interfejsami API.

Przykład:

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

WyglądAttribute

Atrybut [Appearance] jest ograniczony do systemu iOS 5, gdzie wprowadzono menedżera wyglądu.

Atrybut [Appearance] można zastosować do dowolnej metody lub właściwości, która uczestniczy w strukturze UIAppearance . Gdy ten atrybut jest stosowany do metody lub właściwości w klasie, będzie kierować generator powiązań do utworzenia silnie typizowanej klasy wyglądu używanej do stylu wszystkich wystąpień tej klasy lub wystąpień, które spełniają określone kryteria.

Przykład:

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

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

Powyższe polecenie wygeneruje następujący kod w narzędziu UIToolbar:

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] Użyj metod i właściwości w celu opakowywania wywołania metody do metody w elemecie NSAutoReleasePool.

W Objective-C niektórych metodach zwracane są wartości, które są dodawane do wartości domyślnej NSAutoReleasePool. Domyślnie będą one przechodzić do wątku NSAutoReleasePool, ale ponieważ Xamarin.iOS przechowuje również odwołanie do obiektów, o ile istnieje obiekt zarządzany, możesz nie chcieć zachować dodatkowe odwołanie w NSAutoReleasePool elemencie, w którym zostanie opróżnione tylko wtedy, gdy wątek zwróci kontrolę do następnego wątku lub wrócisz do pętli głównej.

Ten atrybut jest stosowany na przykład w przypadku dużych właściwości (na przykład UIImage.FromFile), które zwracają obiekty, które zostały dodane do domyślnej wartości NSAutoReleasePool. Bez tego atrybutu obrazy będą zachowywane tak długo, jak wątek nie zwrócił kontroli do pętli main. Uf twój wątek był pewnego rodzaju downloader tła, który jest zawsze żywy i czeka na pracę, obrazy nigdy nie zostaną opublikowane.

ForcedTypeAttribute

Element [ForcedTypeAttribute] służy do wymuszania tworzenia typu zarządzanego, nawet jeśli zwrócony obiekt niezarządzany nie jest zgodny z typem opisanym w definicji powiązania.

Jest to przydatne, gdy typ opisany w nagłówku nie jest zgodny z zwracanym typem metody natywnej, na przykład weź następującą Objective-C definicję z NSURLSession:

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

Wyraźnie stwierdza, że zwróci NSURLSessionDownloadTask wystąpienie, ale jednak zwraca wartość , która jest superklasą NSURLSessionTask, a tym samym nie będzie konwertowana na NSURLSessionDownloadTask. Ponieważ jesteśmy w bezpiecznym kontekście InvalidCastException typu, nastąpi.

Aby zachować zgodność z opisem nagłówka i uniknąć parametru InvalidCastException, [ForcedTypeAttribute] parametr jest używany.

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

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

Element [ForcedTypeAttribute] akceptuje również wartość logiczną o nazwie Owns , która jest false domyślnie [ForcedType (owns: true)]. Parametr owns służy do przestrzegania zasad własności dla obiektów Core Foundation .

Parametr [ForcedTypeAttribute] jest prawidłowy tylko dla parametrów, właściwości i wartości zwracanej.

BindAsAttribute

Element [BindAsAttribute] umożliwia powiązanie NSNumber, NSValue i NSString(wyliczenia) do bardziej dokładnych typów języka C#. Atrybut może służyć do tworzenia lepszego, dokładniejszego interfejsu API platformy .NET za pośrednictwem natywnego interfejsu API.

Metody (przy wartości zwracanej) można dekorować za pomocą parametrów i właściwości za pomocą polecenia BindAs. Jedynym ograniczeniem jest to, że element członkowski nie może znajdować się wewnątrz interfejsu [Protocol] lub [Model] .

Na przykład:

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

Czy dane wyjściowe:

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

Wewnętrznie wykonamy konwersje i CGRect.>NSValue<NSNumber>bool?<

Bieżące obsługiwane typy hermetyzacji to:

  • NSValue
  • NSNumber
  • NSString

NSValue

Następujące typy danych języka C# są obsługiwane do hermetyzacji z/do NSValue:

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

NSNumber

Następujące typy danych języka C# są obsługiwane do hermetyzacji z/do NSNumber:

  • bool
  • byte
  • double
  • liczba zmiennoprzecinkowa
  • short
  • int
  • długi
  • sbyte
  • ushort
  • uint
  • ulong
  • nfloat
  • nint
  • nuint
  • Wyliczenia

NSString

[BindAs] działa w połączeniu z wyliczeniami wspieranymi przez stałą NSString, aby można było utworzyć lepszy interfejs API platformy .NET, na przykład:

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

Czy dane wyjściowe:

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

Obsłużymy konwersję enum<—>NSString tylko wtedy, gdy podany typ wyliczenia do [BindAs] jest wspierany przez stałą NSString.

Tablice

[BindAs] Obsługuje również tablice dowolnego z obsługiwanych typów, możesz mieć następującą definicję interfejsu API jako przykład:

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

Czy dane wyjściowe:

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

Parametr rects zostanie hermetyzowany do elementu NSArray zawierającego NSValue element dla każdego CGRect elementu i w zamian otrzymasz tablicę, której CAScroll? utworzono przy użyciu wartości zwróconych NSArray zawierających NSStringswartość .

BindAttribute

Atrybut [Bind] ma dwa zastosowania po zastosowaniu do deklaracji metody lub właściwości, a drugi w przypadku zastosowania do pojedynczego elementu getter lub setter we właściwości.

W przypadku użycia dla metody lub właściwości efektem atrybutu [Bind] jest wygenerowanie metody, która wywołuje określony selektor. Jednak wynikowa metoda wygenerowana nie jest ozdobiona atrybutem [Export] , co oznacza, że nie może uczestniczyć w zastępowaniu metody. Jest to zwykle używane w połączeniu z atrybutem [Target] do implementowania Objective-C metod rozszerzeń.

Na przykład:

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

W przypadku użycia w metodzie getter lub setter [Bind] atrybut jest używany do zmiany wartości domyślnych wywnioskowanych przez generator kodu podczas generowania metody getter i nazwy selektora ustawiającego Objective-C dla właściwości. Domyślnie, gdy flagujesz właściwość o nazwie fooBar, generator wygeneruje fooBar eksport dla elementu getter i setFooBar: dla ustawiania. W kilku przypadkach Objective-C nie jest zgodne z tą konwencją, zwykle zmieniają nazwę getter na isFooBar. Ten atrybut służy do informowania generatora o tym.

Na przykład:

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

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

AsyncAttribute

Dostępne tylko na platformie Xamarin.iOS 6.3 i nowszych.

Ten atrybut można zastosować do metod, które przyjmują procedurę obsługi uzupełniania jako ostatni argument.

Można użyć atrybutu [Async] w metodach, których ostatni argument jest wywołaniem zwrotnym. Po zastosowaniu tej metody do metody generator powiązań wygeneruje wersję tej metody z sufiksem Async. Jeśli wywołanie zwrotne nie przyjmuje żadnych parametrów, zwracana wartość będzie wartością Task, jeśli wywołanie zwrotne przyjmuje parametr, wynik będzie wartością Task<T>.

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

Następujące elementy wygenerują tę metodę asynchroniczną:

Task LoadFileAsync (string file);

Jeśli wywołanie zwrotne przyjmuje wiele parametrów, należy ustawić ResultType wartość lub ResultTypeName , aby określić żądaną nazwę wygenerowanego typu, który będzie przechowywać wszystkie właściwości.

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

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

Następujące polecenie wygeneruje tę metodę asynchroniczną, gdzie FileLoading zawiera właściwości umożliwiające dostęp do metody files i byteCount:

Task<FileLoading> LoadFile (string file);

Jeśli ostatnim parametrem NSErrorwywołania zwrotnego jest metoda , metoda wygenerowana Async sprawdzi, czy wartość nie ma wartości null, a jeśli tak jest, wygenerowana metoda asynchroniczna ustawi wyjątek zadania.

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

Powyższe polecenie generuje następującą metodę asynchroniową:

Task<string> UploadAsync (string file);

W przypadku błędu wynikowe zadanie będzie zawierać wyjątek ustawiony na NSErrorException element, który opakowuje wynikowy NSErrorelement .

AsyncAttribute.ResultType

Użyj tej właściwości, aby określić wartość zwracanego Task obiektu. Ten parametr przyjmuje istniejący typ, dlatego należy go zdefiniować w jednej z podstawowych definicji interfejsu API.

AsyncAttribute.ResultTypeName

Użyj tej właściwości, aby określić wartość zwracanego Task obiektu. Ten parametr przyjmuje nazwę żądanego typu, generator utworzy serię właściwości, po jednym dla każdego parametru, który przyjmuje wywołanie zwrotne.

AsyncAttribute.MethodName

Użyj tej właściwości, aby dostosować nazwę wygenerowanych metod asynchronicznych. Wartością domyślną jest użycie nazwy metody i dołączenie tekstu "Async", aby zmienić to ustawienie domyślne.

DesignatedInitializerAttribute

Zastosowanie tego atrybutu do konstruktora spowoduje wygenerowanie tego samego [DesignatedInitializer] atrybutu w ostatnim zestawie platformy. Pomaga to środowisku IDE wskazać, który konstruktor powinien być używany w podklasach.

Powinno to być mapowanie na Objective-C/clang użycia .__attribute__((objc_designated_initializer))

DisableZeroCopyAttribute

Ten atrybut jest stosowany do parametrów ciągu lub właściwości ciągu i instruuje generator kodu, aby nie używał marshalingu ciągu zerowego dla tego parametru, a zamiast tego utworzyć nowe wystąpienie NSString z ciągu języka C#. Ten atrybut jest wymagany tylko w przypadku ciągów, jeśli poinstruujesz generatora, aby używał marshalingu ciągu zerowego przy użyciu --zero-copy opcji wiersza polecenia lub ustawiania atrybutu ZeroCopyStringsAttributena poziomie zestawu .

Jest to konieczne w przypadkach, gdy właściwość jest zadeklarowana jako Objective-Cretain właściwość lub assign zamiast copy właściwości. Zazwyczaj występują one w bibliotekach innych firm, które zostały nieprawidłowo "zoptymalizowane" przez deweloperów. Ogólnie rzecz biorąc, lub assignNSString właściwości są niepoprawne, retain ponieważ NSMutableString lub klasy NSString pochodne użytkownika mogą zmieniać zawartość ciągów bez znajomości kodu biblioteki, co powoduje subtelne przerwanie aplikacji. Zazwyczaj dzieje się tak z powodu przedwczesnej optymalizacji.

Poniżej przedstawiono dwie takie właściwości w pliku Objective-C:

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

DisposeAttribute

Po zastosowaniu [DisposeAttribute] elementu do klasy należy podać fragment kodu, który zostanie dodany do Dispose() implementacji metody klasy.

Dispose Ponieważ metoda jest generowana automatycznie przez bgen narzędzie, należy użyć atrybutu [Dispose] w celu wstrzyknięcia kodu w implementacji wygenerowanej Dispose metody.

Na przykład:

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

Exportattribute

Atrybut [Export] służy do flagowania metody lub właściwości, która ma być uwidoczniona w środowisku uruchomieniowym Objective-C . Ten atrybut jest współużytkowany między narzędziem powiązania a rzeczywistymi środowiskami uruchomieniowymi platform Xamarin.iOS i Xamarin.Mac. W przypadku metod parametr jest przekazywany dosłownie do wygenerowanego kodu, w przypadku właściwości metoda getter i moduł ustawiająca Eksporty są generowane na podstawie deklaracji bazowej (zobacz sekcję na [BindAttribute] temat sposobu zmiany zachowania narzędzia powiązania).

Składnia:

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 reprezentuje nazwę podstawowej Objective-C metody lub właściwości, która jest powiązana.

ExportAttribute.ArgumentSemantic

PoleAttribute

Ten atrybut służy do uwidaczniania zmiennej globalnej języka C jako pola załadowanego na żądanie i uwidocznionego w kodzie C#. Zazwyczaj jest to wymagane, aby uzyskać wartości stałych zdefiniowanych w języku C lub Objective-C , które mogą być tokenami używanymi w niektórych interfejsach API lub których wartości są nieprzezroczyste i muszą być używane zgodnie z kodem użytkownika.

Składnia:

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

Jest symbolName to symbol języka C, z który ma być łączony. Domyślnie zostanie to załadowane z biblioteki, której nazwa jest wywnioskowana z przestrzeni nazw, w której jest zdefiniowany typ. Jeśli nie jest to biblioteka, w której wyszukany jest symbol, należy przekazać libraryName parametr . Jeśli łączysz bibliotekę statyczną, użyj parametru __InternallibraryName .

Wygenerowane właściwości są zawsze statyczne.

Właściwości oflagowane za pomocą atrybutu Field mogą mieć następujące typy:

  • NSString
  • NSArray
  • nint / int / long
  • nuint / uint / ulong
  • nfloat / float
  • double
  • CGSize
  • System.IntPtr
  • Wyliczenia

Zestawy nie są obsługiwane w przypadku wyliczenia wspieranych przez stałe NSString, ale w razie potrzeby można je powiązać ręcznie.

Przykład:

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

InternalAttribute

Atrybut [Internal] można zastosować do metod lub właściwości i ma wpływ na flagowanie wygenerowanego kodu za internal pomocą słowa kluczowego C#, dzięki czemu kod jest dostępny tylko dla kodu w wygenerowanych zestawach. Jest to zwykle używane do ukrywania interfejsów API, które są zbyt niskie lub zapewniają nieoptymalny publiczny interfejs API, który chcesz ulepszyć lub dla interfejsów API, które nie są obsługiwane przez generator i wymagają ręcznego kodowania.

Podczas projektowania powiązania zwykle ukrywa się metodę lub właściwość przy użyciu tego atrybutu i podaj inną nazwę metody lub właściwości, a następnie w pliku obsługi uzupełniającej języka C#, należy dodać silnie typizowana otoka, która uwidacznia podstawowe funkcje.

Na przykład:

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

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

Następnie w pliku pomocniczym możesz mieć kod podobny do następującego:

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

IsThreadStaticAttribute

Ten atrybut flaguje pole tworzenia kopii zapasowej dla właściwości, która ma być oznaczona za pomocą atrybutu .NET [ThreadStatic] . Jest to przydatne, jeśli pole jest zmienną statyczną wątku.

MarshalNativeExceptions (Xamarin.iOS 6.0.6)

Ten atrybut spowoduje, że metoda będzie obsługiwać wyjątki natywne (Objective-C). Zamiast wywoływać objc_msgSend bezpośrednio, wywołanie przejdzie przez niestandardową trampolinę, która przechwytuje wyjątki ObjectiveC i marshaluje je do zarządzanych wyjątków.

Obecnie obsługiwane są tylko kilka objc_msgSend podpisów (można dowiedzieć się, czy podpis nie jest obsługiwany w przypadku natywnego łączenia aplikacji korzystającej z powiązania kończy się niepowodzeniem z brakującym symbolem xamarin__objc_msgSend ale więcej można dodać na żądanie.

NewAttribute

Ten atrybut jest stosowany do metod i właściwości, aby generator wygenerował new słowo kluczowe przed deklaracją.

Służy do unikania ostrzeżeń kompilatora, gdy ta sama nazwa metody lub właściwości jest wprowadzana w podklasie, która już istniała w klasie bazowej.

PowiadomienieAttribute

Ten atrybut można zastosować do pól, aby generator wygenerował silnie typizowany klasę Powiadomień pomocnika.

Ten atrybut może być używany bez argumentów dla powiadomień, które nie mają ładunku, lub można określić, że odwołuje się do System.Type innego interfejsu w definicji interfejsu API, zazwyczaj z nazwą kończącą się ciągiem "EventArgs". Generator przekształci interfejs w klasę, która podklasy EventArgs i będzie zawierać wszystkie wymienione tam właściwości. Atrybut [Export] powinien być używany w EventArgs klasie, aby wyświetlić nazwę klucza używanego do wyszukania Objective-C słownika w celu pobrania wartości.

Na przykład:

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

Powyższy kod spowoduje wygenerowanie zagnieżdżonej klasy MyClass.Notifications przy użyciu następujących metod:

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

Użytkownicy kodu mogą następnie łatwo subskrybować powiadomienia publikowane w NSDefaultCenter przy użyciu kodu w następujący sposób:

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

Lub ustawić określony obiekt do obserwowania. Jeśli przekażesz nullobjectToObserve metodę, zachowasz się podobnie jak w przypadku innego elementu równorzędnego.

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

Zwrócona wartość z ObserveDidStart może służyć do łatwego zatrzymywania odbierania powiadomień, w następujący sposób:

token.Dispose ();

Możesz też wywołać serwer NSNotification.DefaultCenter.RemoveObserver i przekazać token. Jeśli powiadomienie zawiera parametry, należy określić interfejs pomocnika EventArgs , w następujący sposób:

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

Powyższe polecenie wygeneruje klasę MyScreenChangedEventArgs z właściwościami ScreenX i ScreenY , które pobierają dane ze słownika NSNotification.UserInfo przy użyciu kluczy ScreenXKey i ScreenYKey odpowiednio i zastosują odpowiednie konwersje. Atrybut [ProbePresence] jest używany do sondowania generatora, jeśli klucz jest ustawiony w elemecie UserInfo, zamiast próbować wyodrębnić wartość. Jest to używane w przypadkach, gdy obecność klucza jest wartością (zazwyczaj dla wartości logicznych).

Umożliwia to pisanie kodu w następujący sposób:

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

W niektórych przypadkach nie ma stałej skojarzonej z wartością przekazaną w słowniku. Firma Apple czasami używa stałych symboli publicznych, a czasami używa stałych ciągów. Domyślnie [Export] atrybut w podanej EventArgs klasie będzie używać określonej nazwy jako symbolu publicznego do wyszukiwania w czasie wykonywania. Jeśli tak nie jest, a zamiast tego powinno być wyszukane jako stała ciągu, następnie przekaż ArgumentSemantic.Assign wartość do atrybutu Eksportuj.

Nowość w środowisku Xamarin.iOS 8.4

Czasami powiadomienia rozpoczną się bez żadnych argumentów, więc użycie [Notification] bez argumentów jest dopuszczalne. Ale czasami zostaną wprowadzone parametry powiadomienia. Aby obsłużyć ten scenariusz, atrybut można zastosować więcej niż raz.

Jeśli tworzysz powiązanie i chcesz uniknąć przerywania istniejącego kodu użytkownika, możesz włączyć istniejące powiadomienie:

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

W wersji, która wyświetla dwa razy atrybut powiadomienia, w następujący sposób:

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

NullAllowedAttribute

Po zastosowaniu tej właściwości flaguje właściwość jako zezwalającą na przypisanie do niej wartości null . Jest to prawidłowe tylko dla typów referencyjnych.

Po zastosowaniu tego parametru do parametru w podpisie metody wskazuje, że określony parametr może mieć wartość null i że nie należy wykonywać sprawdzania pod kątem przekazywania null wartości.

Jeśli typ odwołania nie ma tego atrybutu, narzędzie powiązania wygeneruje sprawdzenie przypisanej wartości przed przekazaniem jej i Objective-C wygeneruje sprawdzenie, które ArgumentNullException zgłosi, jeśli przypisana wartość to null.

Na przykład:

// In properties

[NullAllowed]
UIImage IconFile { get; set; }

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

ZastąpićAttribute

Użyj tego atrybutu, aby poinstruować generator powiązań, że powiązanie dla tej konkretnej metody powinno być oflagowane za pomocą słowa kluczowego override .

PreSnippetAttribute

Za pomocą tego atrybutu można wstawić kod do wstawienia po zweryfikowaniu parametrów wejściowych, ale przed wywołaniami kodu do Objective-Celementu .

Przykład:

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

PrologueSnippetAttribute

Tego atrybutu można użyć do wstawienia kodu, zanim którykolwiek z parametrów zostanie zweryfikowany w wygenerowanej metodzie.

Przykład:

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

PostGetAttribute

Instruuje generator powiązań, aby wywołał określoną właściwość z tej klasy, aby pobrać z niej wartość.

Ta właściwość jest zwykle używana do odświeżania pamięci podręcznej wskazującej obiekty odwołujące się do obiektów, do których odwołuje się graf obiektu. Zwykle jest on wyświetlany w kodzie zawierającym operacje takie jak Dodawanie/usuwanie. Ta metoda jest używana tak, aby po dodaniu lub usunięciu elementów wewnętrzna pamięć podręczna została zaktualizowana w celu zapewnienia, że przechowujemy zarządzane odwołania do obiektów, które są rzeczywiście używane. Jest to możliwe, ponieważ narzędzie powiązania generuje pole zapasowe dla wszystkich obiektów referencyjnych w danym powiązaniu.

Przykład:

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

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

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

W takim przypadku Dependencies właściwość zostanie wywołana po dodaniu lub usunięciu NSOperation zależności z obiektu, zapewniając, że mamy wykres reprezentujący rzeczywiste załadowane obiekty, zapobiegając wyciekom pamięci, a także uszkodzeniu pamięci.

PostSnippetAttribute

Możesz użyć tego atrybutu, aby wstawić kod źródłowy języka C#, który ma zostać wstawiony po wywołaniu metody bazowej Objective-C

Przykład:

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

ProxyAttribute

Ten atrybut jest stosowany do zwracania wartości, aby oznaczyć je jako obiekty serwera proxy. Niektóre Objective-C interfejsy API zwracają obiekty serwera proxy, których nie można odróżnić od powiązań użytkowników. Efektem tego atrybutu jest flaga obiektu jako DirectBinding obiektu. W przypadku scenariusza w środowisku Xamarin.Mac można zobaczyć dyskusję na temat tej usterki.

ReleaseAttribute (Xamarin.iOS 6.0)

Można to zastosować do zwracanych typów, aby wskazać, że generator powinien wywołać Release obiekt przed zwróceniem go. Jest to konieczne tylko wtedy, gdy metoda daje zachowany obiekt (w przeciwieństwie do obiektu z automatycznym wydaniem, który jest najbardziej typowym scenariuszem)

Przykład:

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

Ponadto ten atrybut jest propagowany do wygenerowanego kodu, dzięki czemu środowisko uruchomieniowe Xamarin.iOS wie, że musi zachować obiekt po powrocie do Objective-C z takiej funkcji.

SealedAttribute

Nakazuje generatorowi flagowanie wygenerowanej metody jako zapieczętowanej. Jeśli ten atrybut nie zostanie określony, wartością domyślną jest wygenerowanie metody wirtualnej (metody wirtualnej, metody abstrakcyjnej lub przesłonięcia w zależności od sposobu użycia innych atrybutów).

StaticAttribute

[Static] Gdy atrybut jest stosowany do metody lub właściwości, generuje to metodę statyczną lub właściwość. Jeśli ten atrybut nie zostanie określony, generator generuje metodę wystąpienia lub właściwość.

TransientAttribute

Ten atrybut służy do flagowania właściwości, których wartości są przejściowe, czyli obiektów tworzonych tymczasowo przez system iOS, ale nie są długotrwałe. Po zastosowaniu tego atrybutu do właściwości generator nie tworzy pola zapasowego dla tej właściwości, co oznacza, że klasa zarządzana nie przechowuje odwołania do obiektu.

WrapAttribute

W projekcie powiązań platformy [Wrap] Xamarin.iOS/Xamarin.Mac atrybut jest używany do opakowania słabo typizowanego obiektu za pomocą silnie typizowanego obiektu. Dzieje się tak głównie w Objective-C przypadku obiektów delegowanych, które są zwykle deklarowane jako typ id lub NSObject. Konwencją używaną przez platformy Xamarin.iOS i Xamarin.Mac jest uwidocznienie tych delegatów lub źródeł danych jako typu NSObject i nazwa jest nazywana konwencją "Weak" + uwidoczniona nazwa. Właściwość id delegate z Objective-C elementu zostanie uwidoczniona jako NSObject WeakDelegate { get; set; } właściwość w pliku kontraktu interfejsu API.

Jednak zazwyczaj wartość przypisana do tego delegata jest silną typem, dlatego udostępniamy silny typ i stosujemy [Wrap] atrybut, co oznacza, że użytkownicy mogą używać słabych typów, jeśli potrzebują pewnej precyzyjnej kontroli lub jeśli muszą uciekać się do sztuczki niskiego poziomu lub mogą używać silnie typizowanej właściwości w większości pracy.

Przykład:

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

W ten sposób użytkownik będzie używać słabo typizowanej wersji delegata:

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

}

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

W ten sposób użytkownik będzie używać silnie typizowanej wersji, zwróć uwagę, że użytkownik korzysta z systemu typów języka C#i używa słowa kluczowego zastąpienia, aby zadeklarować jego intencję i nie musi ręcznie dekorować metody za [Export]pomocą polecenia , ponieważ działało to w powiązaniu dla użytkownika:

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

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

Innym zastosowaniem atrybutu [Wrap] jest obsługa silnie typizowanej wersji metod. Na przykład:

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

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

Po zastosowaniu atrybutu [Wrap] w metodzie wewnątrz typu ozdobionego atrybutem [Category] należy dołączyć This jako pierwszy argument, ponieważ jest generowana metoda rozszerzenia. Na przykład:

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

Elementy członkowskie generowane przez [Wrap] usługę nie virtual są domyślnie, jeśli potrzebujesz virtual elementu członkowskiego, możesz ustawić trueisVirtual opcjonalny parametr.

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

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

[Wrap] można również używać bezpośrednio w programach pobierających i ustawiających właściwości. Dzięki temu można mieć pełną kontrolę nad nimi i dostosować kod zgodnie z potrzebami. Rozważmy na przykład następującą definicję interfejsu API, która używa wyliczenia inteligentnego:

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

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

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

Definicja interfejsu:

// Property definition.

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

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

Atrybuty parametru

W tej sekcji opisano atrybuty, które można zastosować do parametrów w definicji metody, a także [NullAttribute] atrybuty, które mają zastosowanie do właściwości jako całości.

BlockCallback

Ten atrybut jest stosowany do typów parametrów w deklaracjach delegatów języka C#, aby powiadomić binder, że parametr, którego dotyczy problem, jest zgodny z konwencją Objective-C wywoływania bloków i powinien być marshaling w ten sposób.

Jest to zwykle używane w przypadku wywołań zwrotnych, które są zdefiniowane w następujący sposób w pliku Objective-C:

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

Zobacz również: CCallback.

CCallback

Ten atrybut jest stosowany do typów parametrów w deklaracjach delegatów języka C#, aby powiadomić binder, że parametr, którego dotyczy problem, jest zgodny z konwencją wywoływania wskaźnika funkcji ABI i powinien przeprowadzić marshaling w ten sposób.

Jest to zwykle używane w przypadku wywołań zwrotnych, które są zdefiniowane w następujący sposób w pliku Objective-C:

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

Zobacz również: BlockCallback.

Parametry

Możesz użyć atrybutu [Params] w ostatnim parametrze tablicy definicji metody, aby generator wstrzyknął "params" w definicji. Dzięki temu powiązanie może łatwo zezwalać na parametry opcjonalne.

Na przykład następująca definicja:

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

Umożliwia napisanie następującego kodu:

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

Ma to dodatkową zaletę, że nie wymaga od użytkowników tworzenia tablicy wyłącznie do przekazywania elementów.

PlainString

Możesz użyć atrybutu [PlainString] przed parametrami ciągu, aby poinstruować generator powiązań, aby przekazać ciąg jako ciąg języka C, zamiast przekazywać parametr jako NSString.

Większość Objective-C interfejsów API korzysta NSString z parametrów, ale kilka interfejsów API uwidacznia char * interfejs API do przekazywania ciągów zamiast NSString odmiany. W takich przypadkach należy użyć [PlainString] polecenia .

Na przykład następujące Objective-C deklaracje:

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

Powinna być powiązana w następujący sposób:

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

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

RetainAttribute

Nakazuje generatorowi zachowanie odwołania do określonego parametru. Generator udostępni magazyn zapasowy dla tego pola lub możesz określić nazwę () WrapNamedo przechowywania wartości na stronie. Jest to przydatne do przechowywania odwołania do zarządzanego obiektu, który jest przekazywany jako parametr do Objective-C i gdy wiadomo, że Objective-C będzie przechowywać tylko tę kopię obiektu. Na przykład interfejs API, który SetDisplay (SomeObject) chciałby użyć tego atrybutu, ponieważ prawdopodobnie zestawDisplay może wyświetlić tylko jeden obiekt naraz. Jeśli musisz śledzić więcej niż jeden obiekt (na przykład dla interfejsu API przypominającego stos), użyj atrybutu [RetainList] .

Składnia:

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

TransientAttribute

Ten atrybut jest stosowany do parametrów i jest używany tylko podczas przechodzenia z Objective-C do języka C#. Podczas tych przejść różne Objective-CNSObject parametry są opakowane w zarządzaną reprezentację obiektu.

Środowisko uruchomieniowe będzie odwoływać się do obiektu natywnego i zachować odwołanie do ostatniego zarządzanego odwołania do obiektu, a GC ma szansę uruchomić.

W kilku przypadkach ważne jest, aby środowisko uruchomieniowe języka C# nie przechowywało odwołania do obiektu natywnego. Czasami dzieje się tak, gdy podstawowy kod natywny dołączył specjalne zachowanie do cyklu życia parametru. Na przykład: destruktor parametru wykona jakąś akcję oczyszczania lub usunie cenny zasób.

Ten atrybut informuje środowisko uruchomieniowe, że chcesz, aby obiekt został usunięty, jeśli jest to możliwe podczas powrotu z powrotem do Objective-C metody nadpisanej.

Reguła jest prosta: jeśli środowisko uruchomieniowe musiało utworzyć nową reprezentację zarządzaną z obiektu natywnego, na końcu funkcji zostanie usunięta liczba zachowywań dla obiektu natywnego, a właściwość Handle obiektu zarządzanego zostanie wyczyszczone. Oznacza to, że jeśli odwołanie do obiektu zarządzanego zostanie zachowane, odwołanie stanie się bezużyteczne (wywołanie metod na nim zgłosi wyjątek).

Jeśli przekazany obiekt nie został utworzony lub jeśli istnieje już zaległa zarządzana reprezentacja obiektu, wymuszone usunięcie nie odbywa się.

Atrybuty właściwości

NotImplementedAttribute

Ten atrybut jest używany do obsługi Objective-C idiomu, w którym właściwość z getter jest wprowadzana w klasie bazowej, a podklasa modyfikowalna wprowadza metodę ustawiającą.

Ponieważ język C# nie obsługuje tego modelu, klasa bazowa musi mieć zarówno klasę ustawiającą, jak i metodę getter, a podklasę może używać atrybutu OverrideAttribute.

Ten atrybut jest używany tylko w zestawach właściwości i jest używany do obsługi mutable idiom w systemie Objective-C.

Przykład:

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

Atrybuty wyliczenia

Mapowanie NSString stałych na wartości wyliczeniowe to prosty sposób tworzenia lepszego interfejsu API platformy .NET. To:

  • umożliwia bardziej użyteczne uzupełnianie kodu, wyświetlając tylko poprawne wartości interfejsu API;
  • dodaje bezpieczeństwo typu, nie można użyć innej NSString stałej w nieprawidłowym kontekście; i
  • umożliwia ukrycie niektórych stałych, dzięki czemu uzupełnianie kodu pokazuje krótszą listę interfejsów API bez utraty funkcjonalności.

Przykład:

enum NSRunLoopMode {

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

    [Field ("NSRunLoopCommonModes")]
    Common,

    [Field (null)]
    Other = 1000
}

Z powyższej definicji powiązania generator utworzy enum sam siebie, a także utworzy *Extensions typ statyczny, który zawiera metody konwersji na dwa sposoby między wartościami wyliczeniowymi i NSString stałymi. Oznacza to, że stałe pozostają dostępne dla deweloperów, nawet jeśli nie są częścią interfejsu API.

Przykłady:

// 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

Możesz ozdobić jedną wartość wyliczenia za pomocą tego atrybutu. Stanie się to stałą zwracaną, jeśli wartość wyliczenia nie jest znana.

W powyższym przykładzie:

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

Jeśli żadna wartość wyliczenia nie zostanie ozdobiona, zostanie ona wyrzucona NotSupportedException .

ErrorDomainAttribute

Kody błędów są powiązane jako wartości wyliczeniowe. Ogólnie jest dla nich domena błędów i nie zawsze łatwo jest znaleźć, która z nich ma zastosowanie (lub nawet istnieje).

Możesz użyć tego atrybutu, aby skojarzyć domenę błędów z samym wyliczeniami.

Przykład:

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

Następnie można wywołać metodę GetDomain rozszerzenia, aby uzyskać stałą domeny dowolnego błędu.

PoleAttribute

Jest to ten sam [Field] atrybut używany dla stałych wewnątrz typu. Można go również używać wewnątrz wyliczenia do mapowania wartości z określoną stałą.

Wartość null może służyć do określenia, która wartość wyliczenia ma być zwracana, jeśli określono stałą nullNSString .

W powyższym przykładzie:

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

Jeśli żadna wartość nie null jest obecna, zostanie zgłoszony element ArgumentNullException .

Atrybuty globalne

Atrybuty globalne są stosowane przy użyciu modyfikatora atrybutów [assembly:] , takiego jak [LinkWithAttribute] lub mogą być używane w dowolnym miejscu, na przykład atrybuty dostępności.

LinkWithAttribute

Jest to atrybut na poziomie zestawu, który umożliwia deweloperom określenie flag łączenia wymaganych do ponownego użycia powiązanej biblioteki bez wymuszania ręcznego skonfigurowania gcc_flags i dodatkowych argumentów mtouch przekazanych do biblioteki.

Składnia:

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

Ten atrybut jest stosowany na poziomie zestawu, na przykład jest to używane powiązania CorePlot:

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

Jeśli używasz atrybutu [LinkWith] , określony libraryName jest osadzony w wynikowym zestawie, co umożliwia użytkownikom dostarczanie pojedynczej biblioteki DLL zawierającej zarówno niezarządzane zależności, jak i flagi wiersza polecenia niezbędne do prawidłowego korzystania z biblioteki z platformy Xamarin.iOS.

Można również nie podać libraryNameelementu , w którym przypadku LinkWith atrybut może służyć tylko do określania dodatkowych flag konsolidatora:

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

Konstruktory LinkWithAttribute

Te konstruktory umożliwiają określenie biblioteki do łączenia z zestawem wynikowym i osadzania ich w wynikowym zestawie, obsługiwanych obiektów docelowych obsługiwanych przez bibliotekę oraz wszelkich opcjonalnych flag bibliotek, które są niezbędne do połączenia z biblioteką.

Należy pamiętać, że LinkTarget argument jest wnioskowany przez platformę Xamarin.iOS i nie musi być ustawiony.

Przykłady:

// 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

Właściwość ForceLoad służy do określania, czy flaga -force_load łącza jest używana do łączenia biblioteki natywnej. Na razie powinno to być zawsze prawdziwe.

LinkWithAttribute.Frameworks

Jeśli powiązana biblioteka ma twarde wymaganie dotyczące dowolnych struktur (innych niż Foundation i UIKit), należy ustawić Frameworks właściwość na ciąg zawierający rozdzielaną spacją listę wymaganych platform. Jeśli na przykład wiążesz bibliotekę, która wymaga CoreGraphics i CoreText, należy ustawić Frameworks właściwość na "CoreGraphics CoreText".

LinkWithAttribute.IsCxx

Ustaw tę właściwość na wartość true, jeśli wynikowy plik wykonywalny musi zostać skompilowany przy użyciu kompilatora języka C++ zamiast domyślnego, który jest kompilatorem języka C. Użyj tej opcji, jeśli biblioteka, którą wiążesz, została napisana w języku C++.

LinkWithAttribute.LibraryName

Nazwa niezarządzanej biblioteki do pakietu. Jest to plik z rozszerzeniem ".a" i może zawierać kod obiektu dla wielu platform (na przykład ARM i x86 dla symulatora).

Wcześniejsze wersje platformy Xamarin.iOS sprawdziły LinkTarget właściwość, aby określić platformę obsługiwaną przez bibliotekę, ale jest to teraz wykrywane automatycznie, a LinkTarget właściwość jest ignorowana.

LinkWithAttribute.LinkerFlags

Ciąg LinkerFlags umożliwia autorom powiązań określenie wszelkich dodatkowych flag konsolidatora wymaganych podczas łączenia biblioteki natywnej z aplikacją.

Jeśli na przykład biblioteka natywna wymaga biblioteki libxml2 i zlib, należy ustawić LinkerFlags ciąg na "-lxml2 -lz"wartość .

LinkWithAttribute.LinkTarget

Wcześniejsze wersje platformy Xamarin.iOS sprawdziły LinkTarget właściwość, aby określić platformę obsługiwaną przez bibliotekę, ale jest to teraz wykrywane automatycznie, a LinkTarget właściwość jest ignorowana.

LinkWithAttribute.NeedsGccExceptionHandling

Ustaw tę właściwość na wartość true, jeśli biblioteka, którą łączysz, wymaga biblioteki obsługi wyjątków GCC (gcc_eh)

Właściwość powinna być ustawiona SmartLink na wartość true, aby umożliwić platformie Xamarin.iOS określenie, czy ForceLoad jest wymagane, czy nie.

LinkWithAttribute.WeakFrameworks

Właściwość WeakFrameworks działa tak samo jak Frameworks właściwość, z tą różnicą, -weak_framework że w czasie połączenia specyfikator jest przekazywany do biblioteki gcc dla każdej z wymienionych struktur.

WeakFrameworks umożliwia bibliotekom i aplikacjom słabe łączenie się ze strukturami platform, dzięki czemu mogą opcjonalnie ich używać, jeśli są dostępne, ale nie mają na nich twardej zależności, co jest przydatne, jeśli biblioteka ma dodawać dodatkowe funkcje w nowszych wersjach systemu iOS. Aby uzyskać więcej informacji na temat słabych linków, zobacz dokumentację firmy Apple dotyczącą weak linking.

Dobrymi kandydatami do słabego łączenia będą Frameworks konta, CoreBluetooth, CoreImage, NewsstandKitGLKiti Twitter ponieważ są dostępne tylko w systemie iOS 5.

PoradaAttribute

Użyj tego atrybutu, aby dać deweloperom wskazówkę dotyczącą innych interfejsów API, które mogą być dla nich wygodniejsze. Na przykład w przypadku podania silnie typizowanej wersji interfejsu API można użyć tego atrybutu w słabym typie atrybutu, aby przekierować dewelopera do lepszego interfejsu API.

Informacje z tego atrybutu są wyświetlane w dokumentacji i narzędziach, które można opracowywać, aby przekazać sugestie użytkowników dotyczące sposobu ulepszania

WymagaSuperAttribute

Jest to wyspecjalizowana podklasa atrybutu [Advice] , który może służyć do podpowiedzi deweloperowi, który przesłania metodę wymaga wywołania metody podstawowej (przesłoniętej).

Odpowiada to clang__attribute__((objc_requires_super))

ZeroCopyStringsAttribute

Dostępne tylko w środowiskach Xamarin.iOS 5.4 i nowszych.

Ten atrybut instruuje generator, że powiązanie dla tej konkretnej biblioteki (jeśli jest stosowane w [assembly:]programie ) lub typ powinien używać szybkiego marshalingu ciągów bez kopiowania. Ten atrybut jest odpowiednikiem przekazywania opcji --zero-copy wiersza polecenia do generatora.

W przypadku używania zero-copy dla ciągów generator skutecznie używa tego samego ciągu języka C#, co ciąg, który Objective-C używa bez ponoszenia tworzenia nowego NSString obiektu i unikając kopiowania danych z ciągów języka C# do Objective-C ciągu. Jedyną wadą używania ciągów zero copy jest to, że należy upewnić się, że każda właściwość ciągu, która zostanie opakowana, która ma być oflagowana jako retain lub copy ma zestaw atrybutów [DisableZeroCopy] . Jest to wymagane, ponieważ uchwyt dla ciągów bez kopiowania jest przydzielany na stosie i jest nieprawidłowy po powrocie funkcji.

Przykład:

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

Można również zastosować atrybut na poziomie zestawu i będzie on stosowany do wszystkich typów zestawu:

[assembly:ZeroCopyStrings]

Słowniki silnie typizowane

W przypadku platformy Xamarin.iOS 8.0 wprowadziliśmy obsługę łatwego tworzenia silnie typiowanych klas, które opakowujące NSDictionariesfunkcję .

Chociaż zawsze było możliwe użycie typu danych DictionaryContainer wraz z ręcznym interfejsem API, teraz jest to znacznie prostsze. Aby uzyskać więcej informacji, zobacz Surfacing Strong Types (Wyświetlanie silnych typów).

StrongDictionary

Po zastosowaniu tego atrybutu do interfejsu generator utworzy klasę o takiej samej nazwie jak interfejs, który pochodzi z DictionaryContainer i zamienia każdą właściwość zdefiniowaną w interfejsie w silnie typizowane getter i ustawiający dla słownika.

Spowoduje to automatyczne wygenerowanie klasy, która może zostać utworzona na podstawie istniejącej NSDictionary lub utworzonej nowej klasy.

Ten atrybut przyjmuje jeden parametr, nazwę klasy zawierającej klucze używane do uzyskiwania dostępu do elementów w słowniku. Domyślnie każda właściwość w interfejsie z atrybutem będzie wyszukiwać element członkowski w określonym typie dla nazwy z sufiksem "Klucz".

Na przykład:

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

W powyższym przypadku klasa utworzy właściwość Name string, MyOption która będzie używać MyOptionKeys.NameKey jako klucza do słownika w celu pobrania ciągu. Parametr będzie MyOptionKeys.AgeKey używany jako klucz do słownika, aby pobrać element NSNumber , który zawiera int.

Jeśli chcesz użyć innego klucza, możesz użyć atrybutu eksportu we właściwości, na przykład:

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

Silne typy słowników

Następujące typy danych są obsługiwane w StrongDictionary definicji:

Typ interfejsu języka C# NSDictionary Typ magazynu
bool Boolean przechowywane w obiekcie NSNumber
Wartości wyliczenia liczba całkowita przechowywana w obiekcie NSNumber
int 32-bitowa liczba całkowita przechowywana w obiekcie NSNumber
uint 32-bitowa liczba całkowita bez znaku przechowywana w obiekcie NSNumber
nint NSInteger przechowywane w obiekcie NSNumber
nuint NSUInteger przechowywane w obiekcie NSNumber
long 64-bitowa liczba całkowita przechowywana w obiekcie NSNumber
float 32-bitowa liczba całkowita przechowywana jako NSNumber
double 64-bitowa liczba całkowita przechowywana jako NSNumber
NSObject i podklasy NSObject
NSDictionary NSDictionary
string NSString
NSString NSString
C# Array z NSObject NSArray
C# Array wyliczenia NSArrayNSNumber zawierające wartości