Partager via


Guide de référence des types de liaisons

Ce document décrit la liste des attributs que vous pouvez utiliser pour annoter vos fichiers de contrat d’API pour piloter la liaison et le code généré

Les contrats d’API Xamarin.iOS et Xamarin.Mac sont écrits en C# principalement en tant que définitions d’interface qui définissent la façon dont le Objective-C code est exposé à C#. Le processus implique une combinaison de déclarations d’interface ainsi que certaines définitions de type de base que le contrat d’API peut nécessiter. Pour une présentation des types de liaisons, consultez notre guide complémentaire Bibliothèques de liaisonsObjective-C.

Définitions de type

Syntaxe :

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

Chaque interface de votre définition de contrat qui a l’attribut [BaseType] déclare le type de base de l’objet généré. Dans la déclaration ci-dessus, un MyType type C# de classe est généré qui lie à un Objective-C type appelé MyType.

Si vous spécifiez des types après le nom de type (dans l’exemple ci-dessus Protocol1 et Protocol2) à l’aide de la syntaxe d’héritage de l’interface, le contenu de ces interfaces sera inline comme s’il faisait partie du contrat pour MyType. La façon dont Xamarin.iOS surface qu’un type adopte un protocole consiste à inliner toutes les méthodes et propriétés déclarées dans le protocole dans le type lui-même.

L’exemple suivant montre comment la Objective-C déclaration serait UITextField définie dans un contrat Xamarin.iOS :

@interface UITextField : UIControl <UITextInput> {

}

Serait écrit comme suit sous la forme d’un contrat d’API C# :

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

Vous pouvez contrôler de nombreux autres aspects de la génération de code en appliquant d’autres attributs à l’interface et en configurant l’attribut [BaseType] .

Génération d’événements

L’une des fonctionnalités de la conception de l’API Xamarin.iOS et Xamarin.Mac est que nous mappons Objective-C les classes de délégué en tant qu’événements C# et rappels. Les utilisateurs peuvent choisir dans une base par instance s’ils souhaitent adopter le Objective-C modèle de programmation, en affectant des propriétés comme Delegate une instance d’une classe qui implémente les différentes méthodes que le Objective-C runtime appelle, ou en choisissant les événements et propriétés de style C#.

Voyons un exemple d’utilisation du Objective-C modèle :

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

Dans l’exemple ci-dessus, vous pouvez voir que nous avons choisi de remplacer deux méthodes, une notification indiquant qu’un événement de défilement a eu lieu et le second qui est un rappel qui doit retourner une valeur booléenne indiquant s’il scrollView doit faire défiler vers le haut ou non.

Le modèle C# permet à l’utilisateur de votre bibliothèque d’écouter les notifications à l’aide de la syntaxe d’événement C# ou de la syntaxe de propriété pour raccorder des rappels censés retourner des valeurs.

Voici comment le code C# pour la même fonctionnalité ressemble à l’utilisation de lambdas :

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

Étant donné que les événements ne retournent pas de valeurs (ils ont un type de retour void) vous pouvez connecter plusieurs copies. Ce ShouldScrollToTop n’est pas un événement, il s’agit plutôt d’une propriété avec le type UIScrollViewCondition qui a cette signature :

public delegate bool UIScrollViewCondition (UIScrollView scrollView);

Elle retourne une bool valeur, dans ce cas la syntaxe lambda nous permet de renvoyer simplement la valeur de la MakeDecision fonction.

Le générateur de liaisons prend en charge la génération d’événements et de propriétés qui lient une classe comme UIScrollView avec son UIScrollViewDelegate (appelez-les correctement à la classe Model), cela est effectué en annotant votre [BaseType] définition avec les paramètres et Delegates les Events paramètres (décrits ci-dessous). En plus d’annoter les [BaseType] paramètres, il est nécessaire d’informer le générateur de quelques composants supplémentaires.

Pour les événements qui prennent plusieurs paramètres (dans Objective-C la convention, c’est que le premier paramètre d’une classe déléguée est l’instance de l’objet expéditeur), vous devez indiquer le nom que vous souhaitez pour que la classe générée EventArgs soit. Pour ce faire, utilisez l’attribut sur la [EventArgs] déclaration de méthode dans votre classe Model. Par exemple :

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

La déclaration ci-dessus génère une UIImagePickerImagePickedEventArgs classe qui dérive des EventArgs paramètres et les packs, le UIImage et le NSDictionary. Le générateur produit ceci :

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

Il expose ensuite les éléments suivants dans la UIImagePickerController classe :

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

Les méthodes de modèle qui retournent une valeur sont liées différemment. Ceux-ci nécessitent à la fois un nom pour le délégué C# généré (la signature de la méthode) et une valeur par défaut à retourner si l’utilisateur ne fournit pas d’implémentation. Par exemple, la ShouldScrollToTop définition est la suivante :

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

Le code ci-dessus crée un UIScrollViewCondition délégué avec la signature indiquée ci-dessus et, si l’utilisateur ne fournit pas d’implémentation, la valeur de retour est vraie.

En plus de l’attribut [DefaultValue] , vous pouvez également utiliser l’attribut [DefaultValueFromArgument] qui dirige le générateur pour retourner la valeur du paramètre spécifié dans l’appel ou le [NoDefaultValue] paramètre qui indique au générateur qu’il n’existe aucune valeur par défaut.

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

Vous utilisez la Name propriété pour contrôler le nom auquel ce type sera lié dans le Objective-C monde. Il est généralement utilisé pour donner au type C# un nom conforme aux instructions de conception .NET Framework, mais qui est mappé à un nom dans Objective-C ce qui ne suit pas cette convention.

Par exemple, dans le cas suivant, nous mappons le Objective-CNSURLConnection type à NSUrlConnection, car les instructions de conception .NET Framework utilisent « URL » au lieu de « URL » :

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

Le nom spécifié est utilisé comme valeur pour l’attribut généré [Register] dans la liaison. S’il Name n’est pas spécifié, le nom court du type est utilisé comme valeur de l’attribut [Register] dans la sortie générée.

BaseType.Events et BaseType.Delegates

Ces propriétés sont utilisées pour piloter la génération d’événements de style C#dans les classes générées. Ils sont utilisés pour lier une classe donnée à sa Objective-C classe déléguée. Vous rencontrerez de nombreux cas où une classe utilise une classe déléguée pour envoyer des notifications et des événements. Par exemple, une BarcodeScanner classe complémentaire aurait une classe complémentaire BardodeScannerDelegate . La BarcodeScanner classe aurait généralement une Delegate propriété à laquelle vous attribuez une instanceBarcodeScannerDelegate, alors que cela fonctionne, vous pouvez exposer à vos utilisateurs une interface d’événement de style C#, et dans ces cas, vous utiliseriez les propriétés et Delegates les Events propriétés de l’attribut[BaseType].

Ces propriétés sont toujours définies ensemble et doivent avoir le même nombre d’éléments et être synchronisées. Le Delegates tableau contient une chaîne pour chaque délégué faiblement typé que vous souhaitez encapsuler, et le Events tableau contient un type pour chaque type que vous souhaitez associer à celui-ci.

[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

Si vous appliquez cet attribut lorsque de nouvelles instances de cette classe sont créées, l’instance de cet objet sera conservée jusqu’à ce que la méthode référencée par l’objet KeepRefUntil ait été appelée. Cela est utile pour améliorer la facilité d’utilisation de vos API, lorsque vous ne souhaitez pas que votre utilisateur conserve une référence à un objet autour de lui pour utiliser votre code. La valeur de cette propriété est le nom d’une méthode dans la Delegate classe. Vous devez donc l’utiliser en combinaison avec les propriétés et Delegates les Events propriétés.

L’exemple suivant montre comment cela est utilisé dans UIActionSheet 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

Lorsque cet attribut est appliqué à la définition d’interface, il génère un [DesignatedInitializer] attribut sur le constructeur par défaut (généré), qui est mappé au init sélecteur.

DisableDefaultCtorAttribute

Lorsque cet attribut est appliqué à la définition d’interface, il empêche le générateur de produire le constructeur par défaut.

Utilisez cet attribut lorsque vous avez besoin que l’objet soit initialisé avec l’un des autres constructeurs de la classe.

PrivateDefaultCtorAttribute

Lorsque cet attribut est appliqué à la définition d’interface, il signale le constructeur par défaut comme privé. Cela signifie que vous pouvez toujours instancier l’objet de cette classe en interne à partir de votre fichier d’extension, mais il n’est pas accessible aux utilisateurs de votre classe.

CategoryAttribute

Utilisez cet attribut sur une définition de type pour lier Objective-C des catégories et les exposer en tant que méthodes d’extension C# pour miroir la façon d’exposer Objective-C les fonctionnalités.

Les catégories sont un Objective-C mécanisme utilisé pour étendre l’ensemble de méthodes et de propriétés disponibles dans une classe. Dans la pratique, ils sont utilisés pour étendre les fonctionnalités d’une classe de base (par exemple NSObject) lorsqu’un framework spécifique est lié (par exemple UIKit), rendant leurs méthodes disponibles, mais uniquement si le nouveau framework est lié. Dans d’autres cas, ils sont utilisés pour organiser les fonctionnalités d’une classe par fonctionnalité. Ils sont similaires dans l’esprit aux méthodes d’extension C#.

Voici à quoi ressemble une catégorie dans Objective-C:

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

L’exemple ci-dessus se trouve sur une bibliothèque qui étendrait les instances de UIView la méthode makeBackgroundRed.

Pour les lier, vous pouvez utiliser l’attribut [Category] sur une définition d’interface. Lorsque vous utilisez l’attribut [Category] , la signification de l’attribut [BaseType] change d’être utilisé pour spécifier la classe de base à étendre, pour être le type à étendre.

L’exemple suivant montre comment les UIView extensions sont liées et transformées en méthodes d’extension C# :

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

La classe ci-dessus crée une MyUIViewExtension classe qui contient la méthode d’extension MakeBackgroundRed . Cela signifie que vous pouvez maintenant appeler MakeBackgroundRed n’importe quelle UIView sous-classe, ce qui vous donne les mêmes fonctionnalités que celles que Objective-Cvous obtiendriez .

Dans certains cas, vous trouverez des membres statiques dans des catégories comme dans l’exemple suivant :

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

Cela entraîne une définition d’interface C# de catégorie incorrecte :

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

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

Cela est incorrect, car pour utiliser l’extension BoolMethod dont vous avez besoin d’une instance, FooObject mais que vous liez une extension statique ObjC, il s’agit d’un effet secondaire en raison de la façon dont les méthodes d’extension C# sont implémentées.

La seule façon d’utiliser les définitions ci-dessus est le code laid suivant :

(null as FooObject).BoolMethod (range);

La recommandation d’éviter cela consiste à inliner la BoolMethod définition à l’intérieur de la FooObject définition d’interface elle-même, ce qui vous permettra d’appeler cette extension comme elle est prévue FooObject.BoolMethod (range).

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

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

Nous émettrons un avertissement (BI1117) chaque fois que nous trouvons un [Static] membre dans une [Category] définition. Si vous souhaitez vraiment avoir [Static] des membres à l’intérieur de vos [Category] définitions, vous pouvez réduire l’avertissement en utilisant [Category (allowStaticMembers: true)] ou en décorant votre définition de membre ou [Category] d’interface avec [Internal].

StaticAttribute

Lorsque cet attribut est appliqué à une classe, il génère simplement une classe statique, une classe qui ne dérive NSObjectpas , de sorte que l’attribut [BaseType] est ignoré. Les classes statiques sont utilisées pour héberger des variables publiques C que vous souhaitez exposer.

Par exemple :

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

Génère une classe C# avec l’API suivante :

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

Définitions de protocole/modèle

Les modèles sont généralement utilisés par l’implémentation de protocole. Ils diffèrent dans le fait que le runtime s’inscrit uniquement auprès Objective-C des méthodes qui ont réellement été remplacées. Sinon, la méthode n’est pas inscrite.

Cela signifie généralement que lorsque vous sous-classez une classe qui a été marquée avec le ModelAttribute, vous ne devez pas appeler la méthode de base. L’appel de cette méthode lève l’exception suivante : Foundation.You_Should_Not_Call_base_In_This_Method. Vous êtes censé implémenter l’intégralité du comportement sur votre sous-classe pour toutes les méthodes que vous remplacez.

AbstractAttribute

Par défaut, les membres qui font partie d’un protocole ne sont pas obligatoires. Cela permet aux utilisateurs de créer une sous-classe de l’objet Model en dérivant simplement de la classe en C# et en substituant uniquement les méthodes dont ils se soucient. Parfois, le Objective-C contrat exige que l’utilisateur fournisse une implémentation pour cette méthode (celles-ci sont marquées avec la @required directive dans Objective-C). Dans ces cas, vous devez marquer ces méthodes avec l’attribut [Abstract] .

L’attribut [Abstract] peut être appliqué à des méthodes ou des propriétés et entraîne l’indicateur du membre généré comme abstrait et la classe comme classe abstraite.

Les éléments suivants sont extraits de Xamarin.iOS :

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

DefaultValueAttribute

Spécifie la valeur par défaut à renvoyer par une méthode de modèle si l’utilisateur ne fournit pas de méthode pour cette méthode particulière dans l’objet Model

Syntaxe :

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

Par exemple, dans la classe de délégué imaginaire suivante pour une Camera classe, nous fournissons un ShouldUploadToServer élément qui serait exposé en tant que propriété sur la Camera classe. Si l’utilisateur de la Camera classe ne définit pas explicitement la valeur sur une valeur lambda pouvant répondre à true ou false, la valeur par défaut retournée dans ce cas est false, la valeur que nous avons spécifiée dans l’attribut DefaultValue :

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

Si l’utilisateur définit un gestionnaire dans la classe imaginaire, cette valeur est ignorée :

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

Voir aussi : [NoDefaultValue], [DefaultValueFromArgument].

DefaultValueFromArgumentAttribute

Syntaxe :

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

Cet attribut lorsqu’il est fourni sur une méthode qui retourne une valeur sur une classe de modèle indique au générateur de retourner la valeur du paramètre spécifié si l’utilisateur n’a pas fourni sa propre méthode ou son propre lambda.

Exemple :

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

Dans le cas ci-dessus si l’utilisateur de la NSAnimation classe a choisi d’utiliser l’un des événements/propriétés C# et n’a pas défini NSAnimation.ComputeAnimationCurve sur une méthode ou un lambda, la valeur de retour serait la valeur passée dans le paramètre de progression.

Voir aussi : [NoDefaultValue], [DefaultValue]

IgnoredInDelegateAttribute

Il est parfois judicieux de ne pas exposer d’événement ou de déléguer une propriété d’une classe Model dans la classe hôte, de sorte que l’ajout de cet attribut indique au générateur d’éviter la génération d’une méthode décorée avec elle.

[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

Cet attribut est utilisé dans les méthodes Model qui retournent des valeurs pour définir le nom de la signature de délégué à utiliser.

Exemple :

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

Avec la définition ci-dessus, le générateur produit la déclaration publique suivante :

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

DelegateApiNameAttribute

Cet attribut permet au générateur de modifier le nom de la propriété générée dans la classe hôte. Parfois, il est utile lorsque le nom de la méthode de classe FooDelegate est logique pour la classe Delegate, mais semble étrange dans la classe hôte en tant que propriété.

Cela est également très utile (et nécessaire) lorsque vous avez deux méthodes de surcharge ou plus qui sont logiques pour les garder nommées comme c’est le cas dans la classe FooDelegate, mais vous souhaitez les exposer dans la classe hôte avec un nom mieux donné.

Exemple :

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

Avec la définition ci-dessus, le générateur produit la déclaration publique suivante dans la classe hôte :

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

EventArgsAttribute

Pour les événements qui prennent plusieurs paramètres (dans Objective-C la convention est que le premier paramètre d’une classe de délégué est l’instance de l’objet expéditeur), vous devez fournir le nom que vous souhaitez pour que la classe EventArgs générée soit. Pour ce faire, utilisez l’attribut [EventArgs] sur la déclaration de méthode dans votre Model classe.

Par exemple :

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

La déclaration ci-dessus génère une UIImagePickerImagePickedEventArgs classe qui dérive d’EventArgs et packe les deux paramètres, le UIImage et le NSDictionary. Le générateur produit ceci :

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

Il expose ensuite les éléments suivants dans la UIImagePickerController classe :

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

EventNameAttribute

Cet attribut permet au générateur de modifier le nom d’un événement ou d’une propriété généré dans la classe. Parfois, il est utile lorsque le nom de la méthode de classe Model est judicieux pour la classe de modèle, mais semble étrange dans la classe d’origine comme un événement ou une propriété.

Par exemple, il UIWebView utilise le bit suivant à partir des UIWebViewDelegateéléments suivants :

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

Le code ci-dessus s’expose LoadingFinished en tant que méthode dans le UIWebViewDelegate, mais LoadFinished en tant qu’événement à connecter dans un UIWebView:

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

ModelAttribute

Lorsque vous appliquez l’attribut [Model] à une définition de type dans votre API de contrat, le runtime génère du code spécial qui ne fait apparaître que des appels aux méthodes de la classe si l’utilisateur a remplacé une méthode dans la classe. Cet attribut est généralement appliqué à toutes les API qui encapsulent une Objective-C classe de délégué.

Le runtime génère également une Objective-C classe qui correspond au nom du protocole correspondant.

Il est possible de personnaliser le nom de la Objective-C classe de deux façons :

  1. Paramètre AutoGeneratedName = true:

    [Model (AutoGeneratedName = true)]
    

    Cela permet au runtime de générer un nom unique pour le Objective-C type. Le nom est actuellement basé sur le nom de l’assembly et le nom complet du type du modèle (cela peut changer à l’avenir).

  2. Spécification explicite du nom :

    [Model (Name = "CustomName")]
    

Il est recommandé d’utiliser AutoGeneratedName = true. Dans .NET, le nom est toujours généré (sauf s’il est spécifié explicitement comme dans 2. ci-dessus), et la AutoGeneratedName propriété n’existe plus.

NoDefaultValueAttribute

Spécifie que la méthode sur le modèle ne fournit pas de valeur de retour par défaut.

Cela fonctionne avec le Objective-C runtime en répondant false à la Objective-C demande d’exécution pour déterminer si le sélecteur spécifié est implémenté dans cette classe.

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

Voir aussi : [DefaultValue], [DefaultValueFromArgument]

Protocoles

Le Objective-C concept de protocole n’existe pas vraiment en C#. Les protocoles sont similaires aux interfaces C#, mais ils diffèrent selon que toutes les méthodes et propriétés déclarées dans un protocole doivent être implémentées par la classe qui l’adopte. Au lieu de certaines méthodes et propriétés sont facultatives.

Certains protocoles sont généralement utilisés comme classes model, ceux-ci doivent être liés à l’aide de l’attribut [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 ();
}

À compter de Xamarin.iOS 7.0, une nouvelle fonctionnalité de liaison de protocole améliorée a été incorporée. Toute définition qui contient l’attribut [Protocol] génère en fait trois classes de prise en charge qui améliorent considérablement la façon dont vous consommez des protocoles :

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

L’implémentation de classe fournit une classe abstraite complète que vous pouvez remplacer des méthodes individuelles et obtenir une sécurité de type complète. Toutefois, en raison de C# qui ne prend pas en charge plusieurs héritages, il existe des scénarios dans lesquels vous pouvez nécessiter une autre classe de base, mais que vous souhaitez toujours implémenter une interface.

C’est là que se trouve la définition d’interface générée. Il s’agit d’une interface qui a toutes les méthodes requises à partir du protocole. Cela permet aux développeurs qui souhaitent implémenter votre protocole pour simplement implémenter l’interface. Le runtime inscrit automatiquement le type lors de l’adoption du protocole.

Notez que l’interface répertorie uniquement les méthodes requises et expose les méthodes facultatives. Cela signifie que les classes qui adoptent le protocole obtiennent un type complet case activée ing pour les méthodes requises, mais doivent recourir à un type faible (manuellement à l’aide d’attributs d’exportation et correspondant à la signature) pour les méthodes de protocole facultatives.

Pour qu’il soit pratique de consommer une API qui utilise des protocoles, l’outil de liaison produit également une classe de méthode d’extensions qui expose toutes les méthodes facultatives. Cela signifie que tant que vous consommez une API, vous pourrez traiter les protocoles comme ayant toutes les méthodes.

Si vous souhaitez utiliser les définitions de protocole dans votre API, vous devez écrire des interfaces vides squelettes dans votre définition d’API. Si vous souhaitez utiliser myProtocol dans une API, vous devez procéder comme suit :

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

L’élément ci-dessus est nécessaire, car au moment de la liaison, il IMyProtocol n’existe pas, c’est pourquoi vous devez fournir une interface vide.

Adoption d’interfaces générées par le protocole

Chaque fois que vous implémentez l’une des interfaces générées pour les protocoles, comme suit :

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

L’implémentation des méthodes d’interface requises est exportée avec le nom approprié. Il est donc équivalent à ceci :

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

Cela fonctionnera pour tous les membres de protocole requis, mais il existe un cas particulier avec des sélecteurs facultatifs à connaître.

Les membres de protocole facultatifs sont traités de façon identique lors de l’utilisation de la classe de base :

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

mais lors de l’utilisation de l’interface de protocole, il est nécessaire d’ajouter le [Export]. L’IDE l’ajoute via la saisie semi-automatique lorsque vous l’ajoutez à partir d’un remplacement.

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

Il existe une légère différence de comportement entre les deux lors de l’exécution :

  • Les utilisateurs de la classe de base (NSUrlSessionDownloadDelegate, par exemple) fournissent tous les sélecteurs obligatoires et facultatifs, retournant des valeurs par défaut raisonnables.
  • Les utilisateurs de l’interface (INSUrlSessionDownloadDelegate dans l’exemple) répondent uniquement aux sélecteurs exacts fournis.

Certaines classes rares peuvent se comporter différemment ici. Dans presque tous les cas cependant, il est sûr d’utiliser l’un ou l’autre.

Inlining de protocole

Pendant que vous liez des types existants Objective-C qui ont été déclarés comme adoptant un protocole, vous souhaiterez inliner le protocole directement. Pour ce faire, déclarez simplement votre protocole en tant qu’interface sans [BaseType] attribut et listez le protocole dans la liste des interfaces de base pour votre interface.

Exemple :

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

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

Définitions de membres

Les attributs de cette section sont appliqués aux membres individuels d’un type : propriétés et déclarations de méthode.

AlignAttribute

Permet de spécifier la valeur d’alignement pour les types de retour de propriété. Certaines propriétés prennent des pointeurs vers des adresses qui doivent être alignées à certaines limites (dans Xamarin.iOS, cela se produit par exemple avec certaines GLKBaseEffect propriétés qui doivent être alignées sur 16 octets). Vous pouvez utiliser cette propriété pour décorer le getter et utiliser la valeur d’alignement. Cela est généralement utilisé avec les types et OpenTK.Matrix4 les OpenTK.Vector4 types lorsqu’ils sont intégrés aux Objective-C API.

Exemple :

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

AppearanceAttribute

L’attribut [Appearance] est limité à iOS 5, où le gestionnaire d’apparence a été introduit.

L’attribut [Appearance] peut être appliqué à n’importe quelle méthode ou propriété qui participe à l’infrastructure UIAppearance . Lorsque cet attribut est appliqué à une méthode ou à une propriété dans une classe, il dirige le générateur de liaison pour créer une classe d’apparence fortement typée utilisée pour mettre en forme toutes les instances de cette classe, ou les instances qui correspondent à certains critères.

Exemple :

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

Le code ci-dessus génère le code suivant dans 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)

Utilisez les [AutoReleaseAttribute] méthodes et les propriétés pour encapsuler l’appel de méthode à la méthode dans un NSAutoReleasePool.

Il Objective-C existe certaines méthodes qui retournent des valeurs ajoutées à la valeur par défaut NSAutoReleasePool. Par défaut, ceux-ci vont à votre thread NSAutoReleasePool, mais étant donné que Xamarin.iOS conserve également une référence à vos objets tant que l’objet managé vit, vous ne souhaiterez peut-être pas conserver une référence supplémentaire dans celle-ci NSAutoReleasePool uniquement jusqu’à ce que votre thread retourne le contrôle au thread suivant, ou que vous revenez à la boucle principale.

Cet attribut est appliqué par exemple sur les propriétés lourdes (par exemple UIImage.FromFile) qui retourne des objets qui ont été ajoutés à la valeur par défaut NSAutoReleasePool. Sans cet attribut, les images sont conservées tant que votre thread n’a pas retourné le contrôle à la boucle principale. Uf votre thread était une sorte de téléchargeur d’arrière-plan qui est toujours vivant et en attente de travail, les images ne seraient jamais publiées.

ForcedTypeAttribute

Il [ForcedTypeAttribute] est utilisé pour appliquer la création d’un type managé même si l’objet non managé retourné ne correspond pas au type décrit dans la définition de liaison.

Cela est utile lorsque le type décrit dans un en-tête ne correspond pas au type retourné de la méthode native, par exemple prendre la définition suivante Objective-C à partir de NSURLSession:

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

Il indique clairement qu’il retournera une NSURLSessionDownloadTask instance, mais pourtant il retourne un NSURLSessionTask, qui est une superclasse et donc pas convertible en NSURLSessionDownloadTask. Étant donné que nous sommes dans un contexte de type sécurisé, un InvalidCastException événement se produit.

Pour vous conformer à la description de l’en-tête et éviter le InvalidCastException, il [ForcedTypeAttribute] est utilisé.

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

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

Il [ForcedTypeAttribute] accepte également une valeur booléenne nommée Owns par false défaut [ForcedType (owns: true)]. Le paramètre propriétaire est utilisé pour suivre la stratégie de propriété pour les objets Core Foundation .

La [ForcedTypeAttribute] valeur est valide uniquement sur les paramètres, les propriétés et la valeur de retour.

BindAsAttribute

Permet la [BindAsAttribute] liaison NSNumberNSValue et NSString(enums) en types C# plus précis. L’attribut peut être utilisé pour créer une API .NET plus précise et plus précise sur l’API native.

Vous pouvez décorer des méthodes (sur valeur de retour), des paramètres et des propriétés avec BindAs. La seule restriction est que votre membre ne doit pas se trouver à l’intérieur d’une interface ou [Model] d’une [Protocol] interface.

Par exemple :

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

Sortie :

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

En interne, nous allons effectuer les bool?conversions ->NSNumber et CGRect<->NSValue .<

Les types d’encapsulation pris en charge sont les suivants :

  • NSValue
  • NSNumber
  • NSString

NSValue

Les types de données C# suivants sont pris en charge pour être encapsulés depuis/vers NSValue:

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

NSNumber

Les types de données C# suivants sont pris en charge pour être encapsulés depuis/vers NSNumber:

  • bool
  • byte
  • double
  • virgule flottante
  • short
  • int
  • long
  • sbyte
  • ushort
  • uint
  • ulong
  • nfloat
  • nint
  • nuint
  • Énumérations

NSString

[BindAs] fonctionne en conjontion avec des énumérations soutenues par une constante NSString afin de pouvoir créer une meilleure API .NET, par exemple :

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

Sortie :

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

Nous allons gérer la enum<conversion :NSString> uniquement si le type d’énumération fourni en [BindAs] est soutenu par une constante NSString.

Tableaux

[BindAs] prend également en charge les tableaux de tous les types pris en charge, vous pouvez avoir la définition d’API suivante comme exemple :

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

Sortie :

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

Le rects paramètre est encapsulé dans un NSArray qui contient un NSValue pour chaque CGRect et en retour, vous obtiendrez un tableau dont CAScroll? vous avez créé à l’aide des valeurs du conteneur NSStringsretournéNSArray.

BindAttribute

L’attribut [Bind] a deux utilisations lorsqu’il est appliqué à une méthode ou à une déclaration de propriété, et un autre lorsqu’il est appliqué à l’élément getter ou setter individuel dans une propriété.

Lorsqu’il est utilisé pour une méthode ou une propriété, l’effet de l’attribut [Bind] est de générer une méthode qui appelle le sélecteur spécifié. Mais la méthode générée résultante n’est pas décorée avec l’attribut [Export] , ce qui signifie qu’elle ne peut pas participer à la substitution de méthode. Cela est généralement utilisé en combinaison avec l’attribut [Target] pour l’implémentation Objective-C de méthodes d’extension.

Par exemple :

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

Lorsqu’il est utilisé dans un getter ou un setter, l’attribut [Bind] est utilisé pour modifier les valeurs par défaut déduites par le générateur de code lors de la génération des noms de sélecteur getter et setter Objective-C pour une propriété. Par défaut, lorsque vous signalez une propriété portant le nom fooBar, le générateur génère une fooBar exportation pour le getter et setFooBar: pour le setter. Dans quelques cas, Objective-C ne suit pas cette convention, généralement ils changent le nom de getter pour être isFooBar. Vous utiliserez cet attribut pour informer le générateur de ce problème.

Par exemple :

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

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

AsyncAttribute

Disponible uniquement sur Xamarin.iOS 6.3 et versions ultérieures.

Cet attribut peut être appliqué aux méthodes qui prennent un gestionnaire d’achèvement comme dernier argument.

Vous pouvez utiliser l’attribut sur les méthodes dont le [Async] dernier argument est un rappel. Lorsque vous appliquez cela à une méthode, le générateur de liaison génère une version de cette méthode avec le suffixe Async. Si le rappel ne prend aucun paramètre, la valeur de retour est un Task, si le rappel prend un paramètre, le résultat est un Task<T>.

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

Les éléments suivants génèrent cette méthode asynchrone :

Task LoadFileAsync (string file);

Si le rappel prend plusieurs paramètres, vous devez définir ou ResultTypeResultTypeName spécifier le nom souhaité du type généré qui contiendra toutes les propriétés.

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

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

Les éléments suivants génèrent cette méthode asynchrone, où FileLoading contient des propriétés pour accéder à la fois files et byteCount:

Task<FileLoading> LoadFile (string file);

Si le dernier paramètre du rappel est un NSError, la méthode générée Async case activée si la valeur n’est pas null et si c’est le cas, la méthode asynchrone générée définit l’exception de tâche.

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

La méthode asynchrone ci-dessus génère la méthode asynchrone suivante :

Task<string> UploadAsync (string file);

En cas d’erreur, la tâche résultante aura l’exception définie sur une NSErrorException exception qui encapsule le résultat NSError.

AsyncAttribute.ResultType

Utilisez cette propriété pour spécifier la valeur de l’objet de retour Task . Ce paramètre prend un type existant, il doit donc être défini dans l’une de vos définitions d’API principales.

AsyncAttribute.ResultTypeName

Utilisez cette propriété pour spécifier la valeur de l’objet de retour Task . Ce paramètre prend le nom de votre nom de type souhaité, le générateur produit une série de propriétés, une pour chaque paramètre que prend le rappel.

AsyncAttribute.MethodName

Utilisez cette propriété pour personnaliser le nom des méthodes asynchrones générées. La valeur par défaut consiste à utiliser le nom de la méthode et à ajouter le texte « Async », vous pouvez l’utiliser pour modifier cette valeur par défaut.

DesignatedInitializerAttribute

Lorsque cet attribut est appliqué à un constructeur, il génère la même [DesignatedInitializer] chose dans l’assembly de plateforme final. Cela permet d’aider l’IDE à indiquer quel constructeur doit être utilisé dans les sous-classes.

Cela doit être mappé à Objective-Cl’utilisation de /clang de __attribute__((objc_designated_initializer)).

DisableZeroCopyAttribute

Cet attribut est appliqué aux paramètres de chaîne ou aux propriétés de chaîne et indique au générateur de code de ne pas utiliser le marshaling de chaîne de copie zéro pour ce paramètre, et crée plutôt une instance NSString à partir de la chaîne C#. Cet attribut est obligatoire uniquement sur les chaînes si vous demandez au générateur d’utiliser le marshaling de chaînes de copie zéro à l’aide de l’option --zero-copy de ligne de commande ou de la définition de l’attribut ZeroCopyStringsAttributeau niveau de l’assembly.

Cela est nécessaire dans les cas où la propriété est déclarée comme Objective-C étant une retain ou assign une propriété au lieu d’une copy propriété. Celles-ci se produisent généralement dans des bibliothèques tierces qui ont été mal « optimisées » par les développeurs. En général, ou assignNSString les propriétés sont incorrectes, retain car NSMutableString ou les classes dérivées par l’utilisateur peuvent NSString modifier le contenu des chaînes sans connaître le code de la bibliothèque, subtisant l’application. En règle générale, cela se produit en raison d’une optimisation prématurée.

L’exemple suivant montre deux propriétés de ce type dans Objective-C:

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

DisposeAttribute

Lorsque vous appliquez la [DisposeAttribute] classe à une classe, vous fournissez un extrait de code qui sera ajouté à l’implémentation de méthode Dispose() de la classe.

Étant donné que la Dispose méthode est générée automatiquement par l’outil bgen , vous devez utiliser l’attribut [Dispose] pour injecter du code dans l’implémentation de la méthode générée Dispose .

Par exemple :

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

ExportAttribute

L’attribut [Export] est utilisé pour marquer une méthode ou une propriété à exposer au Objective-C runtime. Cet attribut est partagé entre l’outil de liaison et les runtimes Xamarin.iOS et Xamarin.Mac réels. Pour les méthodes, le paramètre est transmis en détail au code généré, pour les propriétés, un getter et un setter Export sont générés en fonction de la déclaration de base (voir la section sur les informations sur la [BindAttribute] modification du comportement de l’outil de liaison).

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

Le sélecteur représente le nom de la méthode ou de la propriété sous-jacente Objective-C qui est liée.

ExportAttribute.ArgumentSemantic

FieldAttribute

Cet attribut est utilisé pour exposer une variable globale C en tant que champ chargé à la demande et exposé au code C#. En règle générale, il est nécessaire d’obtenir les valeurs des constantes définies en C ou Objective-C qui peuvent être des jetons utilisés dans certaines API, ou dont les valeurs sont opaques et doivent être utilisées en tant que code utilisateur.

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

Il symbolName s’agit du symbole C à lier. Par défaut, cela sera chargé à partir d’une bibliothèque dont le nom est déduit à partir de l’espace de noms où le type est défini. Si ce n’est pas la bibliothèque où le symbole est recherché, vous devez passer le libraryName paramètre. Si vous liez une bibliothèque statique, utilisez-la __InternallibraryName comme paramètre.

Les propriétés générées sont toujours statiques.

Les propriétés marquées avec l’attribut Field peuvent être des types suivants :

  • NSString
  • NSArray
  • nint / int / long
  • nuint / uint / ulong
  • nfloat / float
  • double
  • CGSize
  • System.IntPtr
  • Énumérations

Les setters ne sont pas pris en charge pour les énumérations sauvegardées par les constantes NSString, mais elles peuvent être liées manuellement si nécessaire.

Exemple :

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

InternalAttribute

L’attribut [Internal] peut être appliqué aux méthodes ou aux propriétés et a l’effet d’marquer le code généré avec le internal code C# mot clé rendre le code accessible uniquement au code dans l’assembly généré. Il est généralement utilisé pour masquer les API qui sont trop basses ou fournir une API publique non optimale que vous souhaitez améliorer ou pour les API qui ne sont pas prises en charge par le générateur et nécessitent un codage manuel.

Lorsque vous concevez la liaison, vous masquez généralement la méthode ou la propriété à l’aide de cet attribut et fournissez un nom différent pour la méthode ou la propriété, puis, sur votre fichier de support complémentaire C#, vous ajoutez un wrapper fortement typé qui expose les fonctionnalités sous-jacentes.

Par exemple :

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

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

Ensuite, dans votre fichier de prise en charge, vous pouvez avoir du code comme suit :

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

IsThreadStaticAttribute

Cet attribut signale le champ de stockage d’une propriété à annoter avec l’attribut .NET [ThreadStatic] . Cela est utile si le champ est une variable statique de thread.

MarshalNativeExceptions (Xamarin.iOS 6.0.6)

Cet attribut rend une méthode qui prend en charge les exceptions natives (Objective-C). Au lieu d’appeler objc_msgSend directement, l’appel passe par un trampoline personnalisé qui intercepte les exceptions ObjectiveC et les marshale en exceptions gérées.

Actuellement, seules quelques objc_msgSend signatures sont prises en charge (vous trouverez si une signature n’est pas prise en charge lors de la liaison native d’une application qui utilise la liaison échoue avec un symbole de xamarin_ manquant_objc_msgSend ), mais plus encore peut être ajouté à la demande.

NewAttribute

Cet attribut est appliqué aux méthodes et aux propriétés pour que le générateur génère l’mot clé new devant la déclaration.

Il est utilisé pour éviter les avertissements du compilateur lorsque la même méthode ou le même nom de propriété est introduit dans une sous-classe qui existait déjà dans une classe de base.

NotificationAttribute

Vous pouvez appliquer cet attribut aux champs pour que le générateur produise une classe Notifications d’assistance fortement typée.

Cet attribut peut être utilisé sans arguments pour les notifications qui ne comportent aucune charge utile, ou vous pouvez spécifier une System.Type autre interface dans la définition de l’API, généralement avec le nom se terminant par « EventArgs ». Le générateur transforme l’interface en classe qui sous-classe EventArgs et inclut toutes les propriétés répertoriées ici. L’attribut [Export] doit être utilisé dans la EventArgs classe pour répertorier le nom de la clé utilisée pour rechercher le Objective-C dictionnaire pour extraire la valeur.

Par exemple :

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

Le code ci-dessus génère une classe MyClass.Notifications imbriquée avec les méthodes suivantes :

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

Les utilisateurs de votre code peuvent alors facilement s’abonner aux notifications publiées dans NSDefaultCenter à l’aide de code comme suit :

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

Ou pour définir un objet spécifique à observer. Si vous passez null à objectToObserve cette méthode, vous vous comporterez comme son autre homologue.

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

La valeur retournée à partir de ObserveDidStart laquelle vous pouvez être utilisée pour arrêter facilement la réception de notifications, comme suit :

token.Dispose ();

Vous pouvez également appeler NSNotification.DefaultCenter.RemoveObserver et transmettre le jeton. Si votre notification contient des paramètres, vous devez spécifier une interface d’assistance EventArgs , comme suit :

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

La classe ci-dessus génère une MyScreenChangedEventArgs classe avec les ScreenYScreenX propriétés qui extraient les données du dictionnaire NSNotification.UserInfo à l’aide des clés ScreenXKey et ScreenYKey appliquent respectivement les conversions appropriées. L’attribut [ProbePresence] est utilisé pour que le générateur sonde si la clé est définie dans le UserInfo, au lieu d’essayer d’extraire la valeur. Cela est utilisé pour les cas où la présence de la clé est la valeur (généralement pour les valeurs booléennes).

Cela vous permet d’écrire du code comme suit :

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

Dans certains cas, il n’existe aucune constante associée à la valeur transmise au dictionnaire. Apple utilise parfois des constantes de symboles publics et utilise parfois des constantes de chaîne. Par défaut, l’attribut [Export] de votre classe fournie EventArgs utilise le nom spécifié comme symbole public à rechercher au moment de l’exécution. Si ce n’est pas le cas, et qu’il est censé être recherché comme une constante de chaîne, transmettez la ArgumentSemantic.Assign valeur à l’attribut Export.

Nouveautés de Xamarin.iOS 8.4

Parfois, les notifications commencent la vie sans arguments, de sorte que l’utilisation de [Notification] sans arguments est acceptable. Mais parfois, les paramètres de la notification seront introduits. Pour prendre en charge ce scénario, l’attribut peut être appliqué plusieurs fois.

Si vous développez une liaison et que vous souhaitez éviter d’interrompre le code utilisateur existant, vous devez activer une notification existante à partir de :

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

Dans une version qui répertorie deux fois l’attribut de notification, comme suit :

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

NullAllowedAttribute

Lorsqu’elle est appliquée à une propriété, elle signale la propriété comme autorisant l’affectation de la valeur null à celle-ci. Cela n’est valide que pour les types de référence.

Lorsqu’il est appliqué à un paramètre dans une signature de méthode, il indique que le paramètre spécifié peut être null et qu’aucune case activée ne doit être effectuée pour transmettre null des valeurs.

Si le type de référence n’a pas cet attribut, l’outil de liaison génère une case activée pour la valeur affectée avant de la transmettre Objective-C et génère un case activée qui lève une ArgumentNullException valeur si la valeur affectée est null.

Par exemple :

// In properties

[NullAllowed]
UIImage IconFile { get; set; }

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

OverrideAttribute

Utilisez cet attribut pour indiquer au générateur de liaison que la liaison pour cette méthode particulière doit être marquée avec un override mot clé.

PreSnippetAttribute

Vous pouvez utiliser cet attribut pour injecter du code à insérer une fois les paramètres d’entrée validés, mais avant que le code n’appelle Objective-C.

Exemple :

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

PrologueSnippetAttribute

Vous pouvez utiliser cet attribut pour injecter du code à insérer avant que l’un des paramètres ne soit validé dans la méthode générée.

Exemple :

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

PostGetAttribute

Indique au générateur de liaison d’appeler la propriété spécifiée de cette classe pour extraire une valeur.

Cette propriété est généralement utilisée pour actualiser le cache qui pointe vers des objets de référence qui conservent le graphique d’objet référencé. Il apparaît généralement dans le code qui a des opérations telles que Add/Remove. Cette méthode est utilisée afin qu’une fois les éléments ajoutés ou supprimés, le cache interne soit mis à jour pour garantir que nous conservons des références managées aux objets en cours d’utilisation. Cela est possible, car l’outil de liaison génère un champ de stockage pour tous les objets de référence dans une liaison donnée.

Exemple :

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

Dans ce cas, la Dependencies propriété est appelée après l’ajout ou la suppression de dépendances de l’objet NSOperation , ce qui garantit que nous disposons d’un graphique qui représente les objets chargés réels, ce qui empêche les fuites de mémoire ainsi que la corruption de la mémoire.

PostSnippetAttribute

Vous pouvez utiliser cet attribut pour injecter du code source C# à insérer une fois que le code a appelé la méthode sous-jacente Objective-C

Exemple :

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

ProxyAttribute

Cet attribut est appliqué pour retourner des valeurs pour les marquer comme étant des objets proxy. Certaines Objective-C API retournent des objets proxy qui ne peuvent pas être différenciés des liaisons utilisateur. L’effet de cet attribut consiste à marquer l’objet comme étant un DirectBinding objet. Pour un scénario dans Xamarin.Mac, vous pouvez voir la discussion sur ce bogue.

ReleaseAttribute (Xamarin.iOS 6.0)

Cela peut être appliqué aux types de retour pour indiquer que le générateur doit appeler Release l’objet avant de le renvoyer. Cela est nécessaire uniquement lorsqu’une méthode vous donne un objet conservé (par opposition à un objet autoreleased, qui est le scénario le plus courant)

Exemple :

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

En outre, cet attribut est propagé au code généré, afin que le runtime Xamarin.iOS sache qu’il doit conserver l’objet lors du retour à Objective-C partir d’une telle fonction.

SealedAttribute

Indique au générateur de marquer la méthode générée comme scellée. Si cet attribut n’est pas spécifié, la valeur par défaut consiste à générer une méthode virtuelle (une méthode virtuelle, une méthode abstraite ou un remplacement selon la façon dont d’autres attributs sont utilisés).

StaticAttribute

Lorsque l’attribut [Static] est appliqué à une méthode ou à une propriété, cela génère une méthode ou une propriété statique. Si cet attribut n’est pas spécifié, le générateur produit une méthode ou une propriété d’instance.

TransientAttribute

Utilisez cet attribut pour marquer les propriétés dont les valeurs sont temporaires, c’est-à-dire les objets créés temporairement par iOS, mais qui ne sont pas de longue durée. Lorsque cet attribut est appliqué à une propriété, le générateur ne crée pas de champ de stockage pour cette propriété, ce qui signifie que la classe managée ne conserve pas de référence à l’objet.

WrapAttribute

Dans la conception des liaisons Xamarin.iOS/Xamarin.Mac, l’attribut [Wrap] est utilisé pour encapsuler un objet faiblement typé avec un objet fortement typé. Cela entre en jeu principalement avec Objective-C des objets délégués qui sont généralement déclarés comme étant de type id ou NSObject. La convention utilisée par Xamarin.iOS et Xamarin.Mac consiste à exposer ces délégués ou sources de données comme étant de type NSObject et sont nommées à l’aide de la convention « Faible » + le nom exposé. Une id delegate propriété provenant de Objective-C serait exposée en tant que NSObject WeakDelegate { get; set; } propriété dans le fichier de contrat d’API.

Toutefois, en règle générale, la valeur affectée à ce délégué est d’un type fort. Par conséquent, nous mettons en évidence le type fort et appliquons l’attribut [Wrap] , cela signifie que les utilisateurs peuvent choisir d’utiliser des types faibles s’ils ont besoin d’un contrôle précis ou s’ils doivent recourir à des astuces de bas niveau, ou ils peuvent utiliser la propriété fortement typée pour la plupart de leur travail.

Exemple :

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

Voici comment l’utilisateur utiliserait la version faiblement typée du délégué :

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

}

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

Et c’est ainsi que l’utilisateur utilise la version fortement typée, notez que l’utilisateur tire parti du système de type C#et utilise le remplacement mot clé pour déclarer son intention et n’a pas à décorer manuellement la méthode, [Export]car nous avons effectué ce travail dans la liaison pour l’utilisateur :

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

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

Une autre utilisation de l’attribut [Wrap] consiste à prendre en charge la version fortement typée des méthodes. Par exemple :

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

Lorsque l’attribut [Wrap] est appliqué à une méthode à l’intérieur d’un type décoré d’un [Category] attribut, vous devez inclure This comme premier argument, car une méthode d’extension est générée. Par exemple :

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

Les membres générés par [Wrap] ne sont pas virtual par défaut, si vous avez besoin d’un virtual membre, vous pouvez définir true le paramètre facultatif isVirtual .

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

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

[Wrap] peut également être utilisé directement dans les getters de propriétés et les setters. Cela permet d’avoir un contrôle total sur eux et d’ajuster le code selon les besoins. Par exemple, considérez la définition d’API suivante qui utilise des énumérations intelligentes :

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

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

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

Définition de l’interface :

// Property definition.

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

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

Attributs de paramètres

Cette section décrit les attributs que vous pouvez appliquer aux paramètres d’une définition de méthode, ainsi que les [NullAttribute] attributs qui s’appliquent à une propriété dans son ensemble.

BlockCallback

Cet attribut est appliqué aux types de paramètres dans les déclarations de délégué C# pour informer le classeur que le paramètre en question est conforme à la Objective-C convention d’appel de bloc et doit le marshaler de cette façon.

Cela est généralement utilisé pour les rappels définis comme ceci dans Objective-C:

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

Voir aussi : CCallback.

CCallback

Cet attribut est appliqué aux types de paramètres dans les déclarations de délégué C# pour informer le classeur que le paramètre en question est conforme à la convention d’appel du pointeur de fonction ABI C et doit le marshaler de cette façon.

Cela est généralement utilisé pour les rappels définis comme ceci dans Objective-C:

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

Voir aussi : BlockCallback.

Paramètres

Vous pouvez utiliser l’attribut [Params] sur le dernier paramètre de tableau d’une définition de méthode pour que le générateur injecte un « params » dans la définition. Cela permet à la liaison d’autoriser facilement les paramètres facultatifs.

Par exemple, la définition suivante :

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

Autorise l’écriture du code suivant :

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

Cela présente l’avantage supplémentaire qu’il n’exige pas que les utilisateurs créent un tableau uniquement pour transmettre des éléments.

PlainString

Vous pouvez utiliser l’attribut [PlainString] devant les paramètres de chaîne pour indiquer au générateur de liaison de passer la chaîne en tant que chaîne C, au lieu de passer le paramètre en tant que NSString.

La plupart des Objective-C API consomment NSString des paramètres, mais une poignée d’API exposent une char * API pour passer des chaînes, au lieu de la NSString variante. Utilisez-le [PlainString] dans ces cas.

Par exemple, les déclarations suivantes Objective-C :

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

Doit être lié comme suit :

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

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

RetainAttribute

Indique au générateur de conserver une référence au paramètre spécifié. Le générateur fournit le magasin de stockage pour ce champ ou vous pouvez spécifier un nom (le WrapName) auquel stocker la valeur. Cela est utile pour contenir une référence à un objet managé passé en tant que paramètre et Objective-C lorsque vous savez que Objective-C seule cette copie de l’objet sera conservée. Par exemple, une API comme celle-ci SetDisplay (SomeObject) utiliserait cet attribut, car il est probable que SetDisplay ne pouvait afficher qu’un seul objet à la fois. Si vous devez effectuer le suivi de plusieurs objets (par exemple, pour une API de type Stack), vous utilisez l’attribut [RetainList] .

Syntaxe :

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

TransientAttribute

Cet attribut est appliqué aux paramètres et est utilisé uniquement lors de la transition vers Objective-C C#. Pendant ces transitions, les différents Objective-CNSObject paramètres sont encapsulés dans une représentation managée de l’objet.

Le runtime prend une référence à l’objet natif et conserve la référence jusqu’à ce que la dernière référence managée à l’objet soit supprimée, et le GC a la possibilité d’exécuter.

Dans quelques cas, il est important que le runtime C# ne conserve pas de référence à l’objet natif. Cela se produit parfois lorsque le code natif sous-jacent a attaché un comportement spécial au cycle de vie du paramètre. Par exemple : le destructeur du paramètre effectue une action de propre up ou supprime une ressource précieuse.

Cet attribut informe le runtime que vous souhaitez que l’objet soit supprimé si possible lors du retour à Objective-C partir de votre méthode remplacée.

La règle est simple : si le runtime a dû créer une représentation managée à partir de l’objet natif, puis à la fin de la fonction, le nombre de conservations pour l’objet natif sera supprimé et la propriété Handle de l’objet managé sera effacée. Cela signifie que si vous avez conservé une référence à l’objet managé, cette référence devient inutile (l’appel de méthodes dessus lève une exception).

Si l’objet passé n’a pas été créé ou s’il existe déjà une représentation managée en attente de l’objet, la suppression forcée n’a pas lieu.

Attributs de propriété

NotImplementedAttribute

Cet attribut est utilisé pour prendre en charge un Objective-C idiome où une propriété avec un getter est introduite dans une classe de base, et une sous-classe mutable introduit un setter.

Étant donné que C# ne prend pas en charge ce modèle, la classe de base doit avoir à la fois le setter et le getter, et une sous-classe peut utiliser overrideAttribute.

Cet attribut est utilisé uniquement dans les setters de propriétés et est utilisé pour prendre en charge l’idiome mutable dans Objective-C.

Exemple :

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

Attributs d’énumération

Le mappage NSString de constantes aux valeurs d’énumération est un moyen simple de créer une meilleure API .NET. Elle effectue les actions suivantes :

  • permet à la saisie semi-automatique du code d’être plus utile, en affichant uniquement les valeurs correctes pour l’API ;
  • ajoute la sécurité de type, vous ne pouvez pas utiliser une autre NSString constante dans un contexte incorrect ; et
  • permet de masquer certaines constantes, ce qui rend la saisie semi-automatique du code afficher une liste d’API plus courte sans perdre de fonctionnalités.

Exemple :

enum NSRunLoopMode {

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

    [Field ("NSRunLoopCommonModes")]
    Common,

    [Field (null)]
    Other = 1000
}

À partir de la définition de liaison ci-dessus, le générateur crée le enum lui-même et crée également un *Extensions type statique qui inclut des méthodes de conversion bidirectionnelle entre les valeurs d’énumération et les NSString constantes. Cela signifie que les constantes restent disponibles pour les développeurs même s’ils ne font pas partie de l’API.

Exemples :

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

Vous pouvez décorer une valeur d’énumération avec cet attribut. Cela deviendra la constante retournée si la valeur d’énumération n’est pas connue.

Dans l’exemple ci-dessus :

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

Si aucune valeur d’énumération n’est décorée, une NotSupportedException valeur sera levée.

ErrorDomainAttribute

Les codes d’erreur sont liés sous forme de valeurs d’énumération. Il existe généralement un domaine d’erreur pour eux et il n’est pas toujours facile de trouver celui qui s’applique (ou s’il en existe même un).

Vous pouvez utiliser cet attribut pour associer le domaine d’erreur à l’énumération elle-même.

Exemple :

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

Vous pouvez ensuite appeler la méthode GetDomain d’extension pour obtenir la constante de domaine de toute erreur.

FieldAttribute

Il s’agit du même [Field] attribut que celui utilisé pour les constantes à l’intérieur du type. Il peut également être utilisé à l’intérieur d’énumérations pour mapper une valeur avec une constante spécifique.

Une null valeur peut être utilisée pour spécifier la valeur d’énumération à retourner si une nullNSString constante est spécifiée.

Dans l’exemple ci-dessus :

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

Si aucune valeur n’est null présente, une ArgumentNullException valeur est levée.

Attributs globaux

Les attributs globaux sont appliqués à l’aide du [assembly:] modificateur d’attribut comme le [LinkWithAttribute] ou peuvent être utilisés n’importe où, comme les attributs de disponibilité.

LinkWithAttribute

Il s’agit d’un attribut au niveau de l’assembly qui permet aux développeurs de spécifier les indicateurs de liaison requis pour réutiliser une bibliothèque liée sans forcer le consommateur de la bibliothèque à configurer manuellement les arguments gcc_flags et mtouch supplémentaires passés à une bibliothèque.

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

Cet attribut est appliqué au niveau de l’assembly, par exemple, c’est ce que les liaisons CorePlot utilisent :

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

Lorsque vous utilisez l’attribut [LinkWith] , le spécifié libraryName est incorporé dans l’assembly résultant, ce qui permet aux utilisateurs d’expédier une seule DLL qui contient les dépendances non managées ainsi que les indicateurs de ligne de commande nécessaires pour consommer correctement la bibliothèque à partir de Xamarin.iOS.

Il est également possible de ne pas fournir un libraryName, auquel cas l’attribut LinkWith peut être utilisé uniquement pour spécifier des indicateurs d’éditeur de liens supplémentaires :

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

Constructeurs LinkWithAttribute

Ces constructeurs vous permettent de spécifier la bibliothèque à lier et à incorporer dans votre assembly résultant, les cibles prises en charge prises en charge par la bibliothèque et les indicateurs de bibliothèque facultatifs nécessaires pour établir un lien avec la bibliothèque.

Notez que l’argument LinkTarget est déduit par Xamarin.iOS et n’a pas besoin d’être défini.

Exemples :

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

La ForceLoad propriété est utilisée pour déterminer si l’indicateur de -force_load lien est utilisé ou non pour lier la bibliothèque native. Pour l’instant, cela devrait toujours être vrai.

LinkWithAttribute.Frameworks

Si la bibliothèque liée a une exigence difficile sur les infrastructures (autres que Foundation et UIKit), vous devez définir la Frameworks propriété sur une chaîne contenant une liste délimitée par un espace des infrastructures de plateforme requises. Par exemple, si vous liez une bibliothèque qui nécessite CoreGraphics et CoreTextque vous définissez la propriété "CoreGraphics CoreText"sur Frameworks .

LinkWithAttribute.IsCxx

Définissez cette propriété sur true si l’exécutable résultant doit être compilé à l’aide d’un compilateur C++ au lieu de la valeur par défaut, qui est un compilateur C. Utilisez cette option si la bibliothèque que vous liaison avez été écrite en C++.

LinkWithAttribute.LibraryName

Nom de la bibliothèque non managée à regrouper. Il s’agit d’un fichier avec l’extension .a" et il peut contenir du code objet pour plusieurs plateformes (par exemple, ARM et x86 pour le simulateur).

Les versions antérieures de Xamarin.iOS case activée la LinkTarget propriété pour déterminer la plateforme prise en charge par votre bibliothèque, mais elle est désormais détectée automatiquement et la LinkTarget propriété est ignorée.

LinkWithAttribute.LinkerFlags

La LinkerFlags chaîne permet aux auteurs de liaison de spécifier les indicateurs d’éditeur de liens supplémentaires nécessaires lors de la liaison de la bibliothèque native à l’application.

Par exemple, si la bibliothèque native nécessite libxml2 et zlib, vous devez définir la LinkerFlags chaîne "-lxml2 -lz"sur .

LinkWithAttribute.LinkTarget

Les versions antérieures de Xamarin.iOS case activée la LinkTarget propriété pour déterminer la plateforme prise en charge par votre bibliothèque, mais elle est désormais détectée automatiquement et la LinkTarget propriété est ignorée.

LinkWithAttribute.NeedsGccExceptionHandling

Définissez cette propriété sur true si la bibliothèque que vous liez nécessite la bibliothèque gcc Exception Handling (gcc_eh)

La SmartLink propriété doit être définie sur true pour permettre à Xamarin.iOS de déterminer si ForceLoad elle est requise ou non.

LinkWithAttribute.WeakFrameworks

La WeakFrameworks propriété fonctionne de la même façon que la Frameworks propriété, sauf qu’au moment du lien, le -weak_framework spécificateur est passé à gcc pour chacun des frameworks répertoriés.

WeakFrameworks permet aux bibliothèques et applications de lier faiblement les infrastructures de plateforme afin qu’elles puissent éventuellement les utiliser si elles sont disponibles, mais ne sont pas dépendantes de celles-ci, ce qui est utile si votre bibliothèque est destinée à ajouter des fonctionnalités supplémentaires sur les versions plus récentes d’iOS. Pour plus d’informations sur la liaison faible, consultez la documentation d’Apple sur la liaison faible.

Les bons candidats à la liaison faible seraient Frameworks similaires aux comptes, CoreBluetooth, CoreImage, GLKitNewsstandKit et Twitter étant donné qu’ils ne sont disponibles que dans iOS 5.

AdviceAttribute

Utilisez cet attribut pour donner aux développeurs un conseil sur d’autres API qui peuvent être plus pratiques à utiliser. Par exemple, si vous fournissez une version fortement typée d’une API, vous pouvez utiliser cet attribut sur l’attribut faiblement typé pour diriger le développeur vers la meilleure API.

Les informations de cet attribut sont présentées dans la documentation et les outils peuvent être développés pour donner des suggestions à l’utilisateur sur la façon d’améliorer

NécessiteSuperAttribute

Il s’agit d’une sous-classe spécialisée de l’attribut [Advice] qui peut être utilisée pour indiquer au développeur que la substitution d’une méthode nécessite un appel à la méthode de base (substituée).

Cela correspond à clang__attribute__((objc_requires_super))

ZeroCopyStringsAttribute

Disponible uniquement dans Xamarin.iOS 5.4 et versions ultérieures.

Cet attribut indique au générateur que la liaison pour cette bibliothèque spécifique (si elle est appliquée avec [assembly:]) ou le type doit utiliser le marshaling rapide de chaîne de copie zéro. Cet attribut équivaut à passer l’option --zero-copy de ligne de commande au générateur.

Lors de l’utilisation de la copie zéro pour les chaînes, le générateur utilise efficacement la même chaîne C# que la chaîne qui Objective-C consomme sans entraîner la création d’un nouvel NSString objet et éviter de copier les données des chaînes C# dans la Objective-C chaîne. Le seul inconvénient de l’utilisation de chaînes de copie zéro est que vous devez vous assurer que toute propriété de chaîne que vous encapsulez qui se produit pour être marquée comme retain ou copy avec l’attribut [DisableZeroCopy] défini. Cela est nécessaire, car le handle pour les chaînes de copie zéro est alloué sur la pile et n’est pas valide lors du retour de la fonction.

Exemple :

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

Vous pouvez également appliquer l’attribut au niveau de l’assembly et s’applique à tous les types de l’assembly :

[assembly:ZeroCopyStrings]

Dictionnaires fortement typés

Avec Xamarin.iOS 8.0, nous avons introduit la prise en charge de la création facile de classes fortement typées qui encapsulent NSDictionaries.

Bien qu’il ait toujours été possible d’utiliser le type de données DictionaryContainer avec une API manuelle, il est désormais beaucoup plus simple de procéder. Pour plus d’informations, consultez Surfacing Strong Types.

StrongDictionary

Lorsque cet attribut est appliqué à une interface, le générateur produit une classe portant le même nom que l’interface qui dérive de DictionaryContainer et transforme chaque propriété définie dans l’interface en getter fortement typé et setter pour le dictionnaire.

Cela génère automatiquement une classe qui peut être instanciée à partir d’un élément existant NSDictionary ou créé.

Cet attribut prend un paramètre, le nom de la classe contenant les clés utilisées pour accéder aux éléments du dictionnaire. Par défaut, chaque propriété de l’interface avec l’attribut recherche un membre dans le type spécifié pour un nom avec le suffixe « Key ».

Par exemple :

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

Dans le cas ci-dessus, la MyOption classe produit une propriété de chaîne pour Name laquelle elle utilisera la MyOptionKeys.NameKey clé dans le dictionnaire pour récupérer une chaîne. Et utilise la MyOptionKeys.AgeKey clé comme clé dans le dictionnaire pour récupérer un NSNumber élément qui contient une int.

Si vous souhaitez utiliser une autre clé, vous pouvez utiliser l’attribut d’exportation sur la propriété, par exemple :

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

Types de dictionnaires forts

Les types de données suivants sont pris en charge dans la StrongDictionary définition :

Type d’interface C# NSDictionarytype de Stockage
bool Boolean stocké dans un NSNumber
Valeurs d’énumération entier stocké dans un NSNumber
int Entier 32 bits stocké dans un NSNumber
uint Entier non signé 32 bits stocké dans un NSNumber
nint NSInteger stocké dans un NSNumber
nuint NSUInteger stocké dans un NSNumber
long Entier 64 bits stocké dans un NSNumber
float Entier 32 bits stocké sous la forme d’un NSNumber
double Entier 64 bits stocké sous la forme d’un NSNumber
NSObject et sous-classes NSObject
NSDictionary NSDictionary
string NSString
NSString NSString
C# Array de NSObject NSArray
C# Array d’énumérations NSArray contenant des NSNumber valeurs