Guía de referencia de tipos de enlace

En este documento se describe la lista de atributos que puede usar para anotar los archivos de contrato de API para controlar el enlace y el código generado.

Los contratos de API de Xamarin.iOS y Xamarin.Mac se escriben principalmente en C# como definiciones de interfaz que definen la forma en que Objective-C el código se expone a C#. El proceso implica una combinación de declaraciones de interfaz más algunas definiciones de tipo básicas que el contrato de API podría requerir. Para obtener una introducción a los tipos de enlace, consulte nuestra guía complementaria Bibliotecas de Objective-C enlaces.

Definiciones de tipo

Sintaxis:

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

Cada interfaz de la definición del contrato que tiene el [BaseType] atributo declara el tipo base para el objeto generado. En la declaración anterior, se generará un MyType tipo de clase C# que se enlaza a un Objective-C tipo denominado MyType.

Si especifica algún tipo después del typename (en el ejemplo anterior Protocol1 y Protocol2) con la sintaxis de herencia de interfaz, el contenido de esas interfaces se insertará como si hubieran sido parte del contrato para MyType. La forma en que Xamarin.iOS muestra que un tipo adopta un protocolo consiste en insertar todos los métodos y propiedades que se declararon en el protocolo en el propio tipo.

A continuación se muestra cómo se definiría la Objective-C declaración para UITextField en un contrato de Xamarin.iOS:

@interface UITextField : UIControl <UITextInput> {

}

Se escribiría así como un contrato de API de C#:

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

Puede controlar muchos otros aspectos de la generación de código aplicando otros atributos a la interfaz, así como configurando el [BaseType] atributo .

Generación de eventos

Una característica del diseño de la API de Xamarin.iOS y Xamarin.Mac es que asignamos Objective-C clases delegadas como eventos y devoluciones de llamada de C#. Los usuarios pueden elegir en cada instancia si quieren adoptar el patrón de programación mediante la Objective-C asignación a propiedades como Delegate una instancia de una clase que implemente los distintos métodos a los que llamaría el Objective-C runtime o eligiendo las propiedades y eventos de estilo C#.

Veamos un ejemplo de cómo usar el Objective-C modelo:

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

En el ejemplo anterior, puede ver que hemos elegido sobrescribir dos métodos, una notificación de que se ha realizado un evento de desplazamiento y la segunda que es una devolución de llamada que debe devolver un valor booleano que indica scrollView si debe desplazarse hacia la parte superior o no.

El modelo de C# permite al usuario de la biblioteca escuchar notificaciones mediante la sintaxis de eventos de C# o la sintaxis de propiedad para enlazar devoluciones de llamada que se espera que devuelvan valores.

Así es como el código de C# de la misma característica es similar al uso 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 ();
}

Dado que los eventos no devuelven valores (tienen un tipo de valor devuelto void), puede conectar varias copias. No ShouldScrollToTop es un evento, sino una propiedad con el tipo UIScrollViewCondition que tiene esta firma:

public delegate bool UIScrollViewCondition (UIScrollView scrollView);

Devuelve un bool valor, en este caso, la sintaxis lambda nos permite devolver el valor de la MakeDecision función.

El generador de enlaces admite la generación de eventos y propiedades que vinculan una clase como UIScrollView con su UIScrollViewDelegate (bien llamada a esta clase Model), esto se hace anotando [BaseType] la definición con los Events parámetros y Delegates (descritos a continuación). Además de anotar con [BaseType] esos parámetros, es necesario informar al generador de algunos componentes más.

Para los eventos que toman más de un parámetro (en Objective-C la convención es que el primer parámetro de una clase delegada es la instancia del objeto remitente), debe proporcionar el nombre que desea que sea la clase generada EventArgs . Esto se hace con el [EventArgs] atributo en la declaración de método en la clase Model. Por ejemplo:

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

La declaración anterior generará una UIImagePickerImagePickedEventArgs clase que deriva de EventArgs y empaqueta ambos parámetros, y UIImage .NSDictionary El generador genera esto:

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

A continuación, expone lo siguiente en la UIImagePickerController clase :

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

Los métodos de modelo que devuelven un valor se enlazan de forma diferente. Estos requieren un nombre para el delegado de C# generado (la firma del método) y también un valor predeterminado para devolver en caso de que el usuario no proporcione una implementación. Por ejemplo, la ShouldScrollToTop definición es esta:

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

Lo anterior creará un UIScrollViewCondition delegado con la firma que se mostró anteriormente y, si el usuario no proporciona una implementación, el valor devuelto será true.

Además del [DefaultValue] atributo , también puede usar el [DefaultValueFromArgument] atributo que dirige al generador para devolver el valor del parámetro especificado en la llamada o el [NoDefaultValue] parámetro que indica al generador que no hay ningún valor predeterminado.

BaseTypeAttribute

Sintaxis:

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

Utilice la Name propiedad para controlar el nombre al que este tipo se enlazará en el Objective-C mundo. Normalmente se usa para asignar al tipo de C# un nombre que sea compatible con las directrices de diseño de .NET Framework, pero que se asigna a un nombre en Objective-C que no sigue esa convención.

Por ejemplo, en el siguiente caso asignamos el Objective-CNSURLConnection tipo a NSUrlConnection, ya que las directrices de diseño de .NET Framework usan "Url" en lugar de "URL":

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

El nombre especificado se usa como valor para el atributo generado [Register] en el enlace. Si Name no se especifica, el nombre corto del tipo se usa como valor para el [Register] atributo en la salida generada.

BaseType.Events y BaseType.Delegates

Estas propiedades se usan para impulsar la generación de eventos de estilo C#en las clases generadas. Se usan para vincular una clase determinada con su Objective-C clase delegada. Encontrará muchos casos en los que una clase usa una clase delegada para enviar notificaciones y eventos. Por ejemplo, un BarcodeScanner tendría una clase complementaria BardodeScannerDelegate . Normalmente, la BarcodeScanner clase tendría una Delegate propiedad a la que asignaría una instancia de BarcodeScannerDelegate , mientras esto funciona, es posible que quiera exponer a los usuarios una interfaz de eventos de estilo similar a C#, y en esos casos usaría las Events propiedades y Delegates del [BaseType] atributo .

Estas propiedades siempre se establecen juntas y deben tener el mismo número de elementos y mantenerse sincronizadas. La Delegates matriz contiene una cadena para cada delegado de tipo débil que quiera encapsular y la Events matriz contiene un tipo para cada tipo que quiera asociar.

[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 aplica este atributo cuando se crean nuevas instancias de esta clase, la instancia de ese objeto se mantendrá hasta que se haya invocado el método al que hace referencia .KeepRefUntil Esto es útil para mejorar la facilidad de uso de las API, cuando no desea que el usuario mantenga una referencia a un objeto alrededor para usar el código. El valor de esta propiedad es el nombre de un método de la Delegate clase , por lo que también debe usarlo en combinación con las Events propiedades y Delegates .

En el ejemplo siguiente se muestra cómo lo usa UIActionSheet en 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);
}

DesignadoDefaultCtorAttribute

Cuando este atributo se aplica a la definición de interfaz, generará un [DesignatedInitializer] atributo en el constructor predeterminado (generado), que se asigna al init selector.

DisableDefaultCtorAttribute

Cuando este atributo se aplica a la definición de interfaz, impedirá que el generador genere el constructor predeterminado.

Use este atributo cuando necesite que el objeto se inicialice con uno de los otros constructores de la clase .

PrivateDefaultCtorAttribute

Cuando este atributo se aplica a la definición de interfaz, marcará el constructor predeterminado como privado. Esto significa que todavía puede crear instancias del objeto de esta clase internamente desde el archivo de extensión, pero no será accesible para los usuarios de la clase.

CategoryAttribute

Use este atributo en una definición de tipo para enlazar Objective-C categorías y exponerlos como métodos de extensión de C# para reflejar la forma Objective-C en que expone la funcionalidad.

Las categorías son un Objective-C mecanismo que se usa para ampliar el conjunto de métodos y propiedades disponibles en una clase. En la práctica, se usan para ampliar la funcionalidad de una clase base (por ejemplo NSObject) cuando un marco específico está vinculado en (por ejemplo UIKit), haciendo que sus métodos estén disponibles, pero solo si el nuevo marco está vinculado. En algunos otros casos, se usan para organizar las características de una clase por funcionalidad. Son similares en espíritu a los métodos de extensión de C#.

Este es el aspecto de una categoría en Objective-C:

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

El ejemplo anterior se encuentra en una biblioteca que extendería las instancias de UIView con el método makeBackgroundRed.

Para enlazarlos, puede usar el [Category] atributo en una definición de interfaz. Cuando se usa el [Category] atributo , el significado del [BaseType] atributo cambia de usarse para especificar la clase base que se va a extender, a ser el tipo que se va a extender.

A continuación se muestra cómo se enlazan las UIView extensiones y se convierten en métodos de extensión de C#:

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

Lo anterior creará una MyUIViewExtension clase que contiene el método de MakeBackgroundRed extensión. Esto significa que ahora puede llamar MakeBackgroundRed a en cualquier UIView subclase, lo que le proporciona la misma funcionalidad que obtendría en Objective-C.

En algunos casos, encontrará miembros estáticos dentro de categorías como en el ejemplo siguiente:

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

Esto dará lugar a una definición de interfaz de Categoría C# incorrecta :

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

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

Esto es incorrecto porque para usar la BoolMethod extensión necesita una instancia de FooObject , pero está enlazando una extensión estática de ObjC, este es un efecto secundario debido al hecho de cómo se implementan los métodos de extensión de C#.

La única manera de usar las definiciones anteriores es mediante el siguiente código feo:

(null as FooObject).BoolMethod (range);

La recomendación para evitar esto es insertar la BoolMethod definición dentro de la propia definición de interfaz FooObject , lo que le permitirá llamar a esta extensión como se pretende FooObject.BoolMethod (range).

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

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

Se emitirá una advertencia (BI1117) cada vez que se encuentre un [Static] miembro dentro de una [Category] definición. Si realmente desea tener [Static] miembros dentro de las [Category] definiciones, puede silenciar la advertencia mediante [Category (allowStaticMembers: true)] o mediante la decoración de la definición de su miembro o [Category] interfaz con [Internal].

StaticAttribute

Cuando este atributo se aplica a una clase, simplemente generará una clase estática, una que no deriva de NSObject, por lo que se omite el [BaseType] atributo. Las clases estáticas se usan para hospedar variables públicas de C que desea exponer.

Por ejemplo:

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

Generará una clase de C# con la API siguiente:

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

Definiciones de protocolo o modelo

Normalmente, la implementación del protocolo usa modelos. Difieren en que el tiempo de ejecución solo se registrará con Objective-C los métodos que realmente se han sobrescrito. De lo contrario, el método no se registrará.

Esto en general significa que, cuando se subclase una clase marcada con ModelAttribute, no debe llamar al método base. Al llamar a ese método, se producirá la siguiente excepción: Foundation.You_Should_Not_Call_base_In_This_Method. Se supone que debe implementar todo el comportamiento en la subclase para cualquier método que invalide.

AbstractAttribute

De forma predeterminada, los miembros que forman parte de un protocolo no son obligatorios. Esto permite a los usuarios crear una subclase del Model objeto simplemente derivando de la clase en C# y invalidando solo los métodos que les interesan. A veces, el Objective-C contrato requiere que el usuario proporcione una implementación para este método (se marcan con la @required directiva en Objective-C). En esos casos, debe marcar esos métodos con el [Abstract] atributo .

El [Abstract] atributo se puede aplicar a métodos o propiedades y hace que el generador marque el miembro generado como abstracto y la clase sea una clase abstracta.

A continuación se toma de Xamarin.iOS:

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

DefaultValueAttribute

Especifica el valor predeterminado que va a devolver un método de modelo si el usuario no proporciona un método para este método determinado en el objeto Model.

Sintaxis:

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

Por ejemplo, en la siguiente clase de delegado imaginario para una Camera clase, proporcionamos un ShouldUploadToServer que se expondría como una propiedad en la Camera clase . Si el usuario de la Camera clase no establece explícitamente un valor en una expresión lambda que pueda responder a true o false, el valor predeterminado devuelto en este caso sería false, el valor especificado en el DefaultValue atributo :

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

Si el usuario establece un controlador en la clase imaginaria, este valor se omitiría:

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

Vea también: [NoDefaultValue], [DefaultValueFromArgument].

DefaultValueFromArgumentAttribute

Sintaxis:

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

Este atributo cuando se proporciona en un método que devuelve un valor en una clase de modelo indicará al generador que devuelva el valor del parámetro especificado si el usuario no proporcionó su propio método o lambda.

Ejemplo:

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

En el caso anterior si el usuario de la NSAnimation clase eligió usar cualquiera de los eventos o propiedades de C# y no se estableció NSAnimation.ComputeAnimationCurve en un método o lambda, el valor devuelto sería el valor pasado en el parámetro progress.

Vea también: [NoDefaultValue], [DefaultValue]

IgnoredInDelegateAttribute

A veces, tiene sentido no exponer una propiedad de evento o delegado de una clase Model en la clase host, por lo que agregar este atributo indicará al generador que evite la generación de cualquier método decorado con él.

[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

Este atributo se usa en los métodos Model que devuelven valores para establecer el nombre de la firma de delegado que se va a usar.

Ejemplo:

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

Con la definición anterior, el generador generará la siguiente declaración pública:

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

DelegateApiNameAttribute

Este atributo se usa para permitir que el generador cambie el nombre de la propiedad generada en la clase host. A veces resulta útil cuando el nombre del método de clase FooDelegate tiene sentido para la clase Delegate, pero tendría un aspecto extraño en la clase host como una propiedad.

Además, esto es realmente útil (y necesario) cuando tiene dos o más métodos de sobrecarga que tiene sentido mantenerlos denominados como está en la clase FooDelegate, pero desea exponerlos en la clase host con un nombre mejor dado.

Ejemplo:

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

Con la definición anterior, el generador generará la siguiente declaración pública en la clase host:

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

EventArgsAttribute

Para los eventos que toman más de un parámetro (en Objective-C la convención es que el primer parámetro de una clase delegada es la instancia del objeto remitente), debe proporcionar el nombre que desea que sea la clase EventArgs generada. Esto se hace con el atributo en la [EventArgs] declaración de método de Model la clase .

Por ejemplo:

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

La declaración anterior generará una UIImagePickerImagePickedEventArgs clase que deriva de EventArgs y empaqueta ambos parámetros, y UIImage .NSDictionary El generador genera esto:

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

A continuación, expone lo siguiente en la UIImagePickerController clase :

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

EventNameAttribute

Este atributo se usa para permitir que el generador cambie el nombre de un evento o propiedad generado en la clase . A veces resulta útil cuando el nombre del método de clase Model tiene sentido para la clase de modelo, pero tendría un aspecto extraño en la clase de origen como un evento o propiedad.

Por ejemplo, usa UIWebView el siguiente bit de :UIWebViewDelegate

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

Lo anterior expone LoadingFinished como el método de UIWebViewDelegate, pero LoadFinished como el evento al que se va a enlazar en :UIWebView

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

ModelAttribute

Cuando se aplica el [Model] atributo a una definición de tipo en la API de contrato, el tiempo de ejecución generará código especial que solo mostrará invocaciones a métodos de la clase si el usuario ha sobrescrito un método en la clase . Este atributo se suele aplicar a todas las API que encapsulan una Objective-C clase de delegado.

NoDefaultValueAttribute

Especifica que el método del modelo no proporciona un valor devuelto predeterminado.

Esto funciona con el Objective-C tiempo de ejecución respondiendo false a la solicitud en Objective-C tiempo de ejecución para determinar si el selector especificado se implementa en esta clase.

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

Vea también: [DefaultValue], [DefaultValueFromArgument]

Protocolos

El Objective-C concepto de protocolo no existe realmente en C#. Los protocolos son similares a las interfaces de C#, pero difieren en que no todos los métodos y propiedades declarados en un protocolo deben implementarse mediante la clase que la adopta. En lugar de algunos de los métodos y propiedades son opcionales.

Algunos protocolos se suelen usar como clases Model, que deben enlazarse mediante el [Model] atributo .

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

A partir de Xamarin.iOS 7.0, se ha incorporado una nueva y mejorada funcionalidad de enlace de protocolo. Cualquier definición que contenga el [Protocol] atributo generará realmente tres clases auxiliares que mejoran enormemente la forma en que se consumen protocolos:

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

La implementación de la clase proporciona una clase abstracta completa que puede invalidar métodos individuales de y obtener seguridad completa de tipos. Pero debido a que C# no admite varias herencias, hay escenarios en los que podría requerir una clase base diferente, pero aún desea implementar una interfaz.

Aquí es donde entra la definición de interfaz generada. Es una interfaz que tiene todos los métodos necesarios del protocolo. Esto permite a los desarrolladores que quieran implementar el protocolo simplemente implementar la interfaz. El tiempo de ejecución registrará automáticamente el tipo al adoptar el protocolo.

Observe que la interfaz solo enumera los métodos necesarios y expone los métodos opcionales. Esto significa que las clases que adoptan el protocolo obtendrán una comprobación de tipos completa para los métodos necesarios, pero tendrán que recurrir a tipos débiles (mediante el uso manual de atributos Export y la coincidencia de la firma) para los métodos de protocolo opcionales.

Para que sea conveniente consumir una API que use protocolos, la herramienta de enlace también generará una clase de método de extensiones que expone todos los métodos opcionales. Esto significa que, siempre que consuma una API, podrá tratar los protocolos como tener todos los métodos.

Si quiere usar las definiciones de protocolo en la API, deberá escribir interfaces vacías de esqueleto en la definición de API. Si desea usar MyProtocol en una API, deberá hacerlo:

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

Lo anterior es necesario porque en el momento del IMyProtocol enlace no existiría, es por eso que necesita proporcionar una interfaz vacía.

Adopción de interfaces generadas por protocolos

Cada vez que implemente una de las interfaces generadas para los protocolos, de la siguiente manera:

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

La implementación de los métodos de interfaz necesarios se exporta con el nombre adecuado, por lo que es equivalente a esto:

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

Esto funcionará para todos los miembros de protocolo necesarios, pero hay un caso especial con selectores opcionales que se deben tener en cuenta.

Los miembros de protocolo opcionales se tratan de forma idéntica al usar la clase base:

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

pero cuando se usa la interfaz de protocolo, es necesario agregar el [Export]. El IDE lo agregará a través de autocompletar al agregarlo a partir de la invalidación.

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

Hay una ligera diferencia de comportamiento entre las dos en tiempo de ejecución:

  • Los usuarios de la clase base (NSUrlSessionDownloadDelegate en el ejemplo) proporcionan todos los selectores obligatorios y opcionales, devolviendo valores predeterminados razonables.
  • Los usuarios de la interfaz (INSUrlSessionDownloadDelegate en el ejemplo) solo responden a los selectores exactos proporcionados.

Algunas clases poco frecuentes pueden comportarse de forma diferente aquí. En casi todos los casos, sin embargo, es seguro usar cualquiera de las dos.

Inserción de protocolos

Mientras enlaza los tipos existentes Objective-C que se han declarado como adopción de un protocolo, querrá insertar el protocolo directamente. Para ello, simplemente declare el protocolo como una interfaz sin ningún [BaseType] atributo y enumere el protocolo en la lista de interfaces base de la interfaz.

Ejemplo:

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

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

Definiciones de miembros

Los atributos de esta sección se aplican a miembros individuales de un tipo: propiedades y declaraciones de método.

AlignAttribute

Se usa para especificar el valor de alineación para los tipos devueltos de propiedad. Algunas propiedades toman punteros a direcciones que deben alinearse en determinados límites (en Xamarin.iOS esto sucede, por ejemplo, con algunas GLKBaseEffect propiedades que deben estar alineadas con 16 bytes). Puede usar esta propiedad para decorar el captador y usar el valor de alineación. Normalmente se usa con los OpenTK.Vector4 tipos y OpenTK.Matrix4 cuando se integran con Objective-C las API.

Ejemplo:

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

AppearanceAttribute

El [Appearance] atributo se limita a iOS 5, donde se introdujo el administrador de apariencias.

El [Appearance] atributo se puede aplicar a cualquier método o propiedad que participe en el UIAppearance marco. Cuando este atributo se aplica a un método o propiedad de una clase, dirigirá al generador de enlaces para crear una clase de apariencia fuertemente tipada que se usa para aplicar estilo a todas las instancias de esta clase o a las instancias que coinciden con determinados criterios.

Ejemplo:

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

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

Lo anterior generaría el código siguiente en 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)

Use en métodos [AutoReleaseAttribute] y propiedades para encapsular la invocación de método al método en .NSAutoReleasePool

En Objective-C hay algunos métodos que devuelven valores que se agregan al valor predeterminado NSAutoReleasePool. De forma predeterminada, estos van al subproceso NSAutoReleasePool, pero dado que Xamarin.iOS también mantiene una referencia a los objetos siempre que el objeto administrado resida, es posible que no desee conservar una referencia adicional en la NSAutoReleasePool que solo se purgará hasta que el subproceso devuelva el control al siguiente subproceso o vuelva al bucle principal.

Este atributo se aplica por ejemplo en propiedades pesadas (por ejemplo UIImage.FromFile) que devuelve objetos que se han agregado al valor predeterminado NSAutoReleasePool. Sin este atributo, las imágenes se conservarían siempre y cuando el subproceso no devolviera el control al bucle principal. Uf tu subproceso era algún tipo de descargador de fondo que siempre está vivo y esperando trabajo, las imágenes nunca se liberarían.

ForcedTypeAttribute

[ForcedTypeAttribute] se usa para aplicar la creación de un tipo administrado aunque el objeto no administrado devuelto no coincida con el tipo descrito en la definición de enlace.

Esto resulta útil cuando el tipo descrito en un encabezado no coincide con el tipo devuelto del método nativo, por ejemplo, tome la siguiente Objective-C definición de NSURLSession:

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

Indica claramente que devolverá una NSURLSessionDownloadTask instancia, pero sin embargo devuelve un NSURLSessionTask, que es una superclase y, por tanto, no se puede convertir en NSURLSessionDownloadTask. Puesto que estamos en un contexto seguro para tipos, se producirá una InvalidCastException excepción.

Para cumplir con la descripción del encabezado y evitar InvalidCastException, [ForcedTypeAttribute] se usa .

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

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

[ForcedTypeAttribute] también acepta un valor booleano denominado Owns que es false de forma predeterminada [ForcedType (owns: true)]. El parámetro owns se usa para seguir la directiva de propiedad para los objetos de Core Foundation .

solo [ForcedTypeAttribute] es válido en parámetros, propiedades y valor devuelto.

BindAsAttribute

[BindAsAttribute] permite enlazar NSNumbery NSValueNSString(enumeraciones) en tipos de C# más precisos. El atributo se puede usar para crear una API de .NET mejor, más precisa, a través de la API nativa.

Puede decorar métodos (en el valor devuelto), parámetros y propiedades con BindAs. La única restricción es que el miembro no debe estar dentro de una [Protocol] interfaz o [Model] .

Por ejemplo:

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

Se generaría lo siguiente:

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

Internamente haremos las bool?conversiones ->NSNumber y CGRect<->NSValue .<

Los tipos de encapsulación admitidos actuales son:

  • NSValue
  • NSNumber
  • NSString

NSValue

Se admiten los siguientes tipos de datos de C# para encapsularse desde y hacia NSValue:

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

NSNumber

Se admiten los siguientes tipos de datos de C# para encapsularse desde y hacia NSNumber:

  • bool
  • byte
  • double
  • FLOAT
  • short
  • int
  • long
  • sbyte
  • ushort
  • uint
  • ulong
  • nfloat
  • nint
  • nuint
  • Enumeraciones

NSString

[BindAs] funciona en conjunción con enumeraciones respaldadas por una constante NSString para que pueda crear una mejor API de .NET, por ejemplo:

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

Se generaría lo siguiente:

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

Controlaremos la enum<conversión ->NSString solo si el tipo de enumeración proporcionado a [BindAs] está respaldado por una constante NSString.

Matrices

[BindAs] también admite matrices de cualquiera de los tipos admitidos; puede tener la siguiente definición de API como ejemplo:

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

Se generaría lo siguiente:

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

El rects parámetro se encapsulará en un NSArray objeto que contiene un NSValue para cada CGRect y, de vuelta, obtendrá una matriz de CAScroll? la que se ha creado utilizando los valores del devuelto NSArray que contiene NSStrings.

BindAttribute

El [Bind] atributo tiene dos usos uno cuando se aplica a un método o declaración de propiedad, y otro cuando se aplica al captador individual o establecedor en una propiedad .

Cuando se usa para un método o propiedad, el efecto del [Bind] atributo es generar un método que invoca el selector especificado. Pero el método generado resultante no está decorado con el [Export] atributo , lo que significa que no puede participar en la invalidación del método. Normalmente se usa en combinación con el [Target] atributo para implementar Objective-C métodos de extensión.

Por ejemplo:

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

Cuando se usa en un captador o establecedor, el [Bind] atributo se usa para modificar los valores predeterminados inferidos por el generador de código al generar los nombres de selector de captador y establecedor Objective-C para una propiedad. De forma predeterminada, al marcar una propiedad con el nombre fooBar, el generador generaría una fooBar exportación para el captador y setFooBar: para el establecedor. En algunos casos, Objective-C no sigue esta convención, normalmente cambian el nombre del captador a isFooBar. Usaría este atributo para informar al generador de esto.

Por ejemplo:

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

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

AsyncAttribute

Solo está disponible en Xamarin.iOS 6.3 y versiones posteriores.

Este atributo se puede aplicar a métodos que toman un controlador de finalización como último argumento.

Puede usar el [Async] atributo en métodos cuyo último argumento es una devolución de llamada. Al aplicar esto a un método, el generador de enlaces generará una versión de ese método con el sufijo Async. Si la devolución de llamada no toma ningún parámetro, el valor devuelto será , Tasksi la devolución de llamada toma un parámetro, el resultado será .Task<T>

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

A continuación, se generará este método asincrónico:

Task LoadFileAsync (string file);

Si la devolución de llamada toma varios parámetros, debe establecer o ResultTypeResultTypeName para especificar el nombre deseado del tipo generado que contendrá todas las propiedades.

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

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

Lo siguiente generará este método asincrónico, donde FileLoading contiene propiedades para acceder a y filesbyteCount:

Task<FileLoading> LoadFile (string file);

Si el último parámetro de la devolución de llamada es , NSErrorel método generado Async comprobará si el valor no es NULL y, si es así, el método asincrónico generado establecerá la excepción de tarea.

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

El elemento anterior genera el siguiente método asincrónico:

Task<string> UploadAsync (string file);

Y en caso de error, la tarea resultante tendrá la excepción establecida en un NSErrorException objeto que encapsula el resultante NSError.

AsyncAttribute.ResultType

Utilice esta propiedad para especificar el valor del objeto devuelto Task . Este parámetro toma un tipo existente, por lo que debe definirse en una de las definiciones de API principales.

AsyncAttribute.ResultTypeName

Utilice esta propiedad para especificar el valor del objeto devuelto Task . Este parámetro toma el nombre del tipo deseado, el generador generará una serie de propiedades, una para cada parámetro que toma la devolución de llamada.

AsyncAttribute.MethodName

Utilice esta propiedad para personalizar el nombre de los métodos asincrónicos generados. El valor predeterminado es usar el nombre del método y anexar el texto "Async", puede usarlo para cambiar este valor predeterminado.

DesignadoInitializerAttribute

Cuando este atributo se aplica a un constructor, generará lo mismo [DesignatedInitializer] en el ensamblado de plataforma final. Esto sirve para ayudar al IDE a indicar qué constructor se debe usar en subclases.

Esto debe asignarse al Objective-Cuso de /clang de __attribute__((objc_designated_initializer)).

DisableZeroCopyAttribute

Este atributo se aplica a parámetros de cadena o propiedades de cadena e indica al generador de código que no use la serialización de cadenas de copia cero para este parámetro y, en su lugar, cree una nueva instancia de NSString a partir de la cadena de C#. Este atributo solo es necesario en cadenas si se indica al generador que use la serialización de cadenas de copia cero mediante la --zero-copy opción de línea de comandos o estableciendo el atributo ZeroCopyStringsAttributede nivel de ensamblado .

Esto es necesario en los casos en los que la propiedad se declara en Objective-C para ser una retain propiedad o assign en lugar de una copy propiedad. Normalmente, estos se producen en bibliotecas de terceros que los desarrolladores han "optimizado" de forma incorrecta. En general, o assignNSString las propiedades son incorrectas, retain ya que NSMutableString o las clases derivadas del usuario de NSString pueden modificar el contenido de las cadenas sin el conocimiento del código de biblioteca, lo que interrumpirá la aplicación de forma subdirección. Normalmente esto sucede debido a la optimización prematura.

A continuación se muestran dos propiedades de este tipo en Objective-C:

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

DisposeAttribute

Cuando se aplica [DisposeAttribute] a una clase, se proporciona un fragmento de código que se agregará a la Dispose() implementación del método de la clase .

Dado que el Dispose método se genera automáticamente mediante las bmac-native herramientas y btouch-native , debe usar el [Dispose] atributo para insertar código en la implementación del método generado Dispose .

Por ejemplo:

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

ExportAttribute

El [Export] atributo se usa para marcar un método o una propiedad que se expondrá al Objective-C tiempo de ejecución. Este atributo se comparte entre la herramienta de enlace y los entornos de ejecución reales de Xamarin.iOS y Xamarin.Mac. En el caso de los métodos, el parámetro se pasa textualmente al código generado, para las propiedades, se generan exportaciones de captador y establecedor en función de la declaración base (vea la sección de para [BindAttribute] obtener información sobre cómo modificar el comportamiento de la herramienta de enlace).

Sintaxis:

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

El selector representa el nombre del método o propiedad subyacente Objective-C que se enlaza.

ExportAttribute.ArgumentSemantic

FieldAttribute

Este atributo se usa para exponer una variable global de C como un campo que se carga a petición y se expone al código de C#. Normalmente, esto es necesario para obtener los valores de las constantes definidas en C o Objective-C y que podrían ser tokens usados en algunas API, o cuyos valores son opacos y deben usarse tal cual por código de usuario.

Sintaxis:

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

symbolName es el símbolo de C con el que se va a vincular. De forma predeterminada, se cargará desde una biblioteca cuyo nombre se deduce del espacio de nombres donde se define el tipo. Si no es la biblioteca donde se busca el símbolo, debe pasar el libraryName parámetro . Si va a vincular una biblioteca estática, use __Internal como libraryName parámetro .

Las propiedades generadas siempre son estáticas.

Las propiedades marcadas con el atributo Field pueden ser de los siguientes tipos:

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

No se admiten establecedores para enumeraciones respaldadas por constantes NSString, pero se pueden enlazar manualmente si es necesario.

Ejemplo:

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

InternalAttribute

El [Internal] atributo se puede aplicar a métodos o propiedades y tiene el efecto de marcar el código generado con la internal palabra clave de C# que hace que el código solo sea accesible para el código en el ensamblado generado. Normalmente se usa para ocultar las API que son demasiado de bajo nivel o proporcionan una API pública poco óptima que desea mejorar o para las API que no son compatibles con el generador y requieren alguna codificación manual.

Al diseñar el enlace, normalmente ocultaría el método o la propiedad con este atributo y proporcionaría un nombre diferente para el método o la propiedad y, a continuación, en el archivo de soporte complementario de C#, agregaría un contenedor fuertemente tipado que expone la funcionalidad subyacente.

Por ejemplo:

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

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

Después, en el archivo auxiliar, podría tener código similar al siguiente:

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

IsThreadStaticAttribute

Este atributo marca el campo de respaldo de una propiedad que se va a anotar con el atributo .NET [ThreadStatic] . Esto es útil si el campo es una variable estática de subproceso.

MarshalNativeExceptions (Xamarin.iOS 6.0.6)

Este atributo hará que un método admita excepciones nativas (Objective-C). En lugar de llamar objc_msgSend directamente, la invocación pasará por una línea de trampolín personalizada que captura las excepciones de ObjectiveC y las serializa en excepciones administradas.

Actualmente solo se admiten algunas objc_msgSend firmas (averiguará si no se admite una firma cuando la vinculación nativa de una aplicación que usa el enlace produce un error con un símbolo que falta monotouch__objc_msgSend ), pero se puede agregar más a petición.

NewAttribute

Este atributo se aplica a métodos y propiedades para que el generador genere la new palabra clave delante de la declaración.

Se usa para evitar advertencias del compilador cuando se introduce el mismo nombre de método o propiedad en una subclase que ya existía en una clase base.

NotificationAttribute

Puede aplicar este atributo a los campos para que el generador genere una clase de notificaciones auxiliares fuertemente tipadas.

Este atributo se puede usar sin argumentos para las notificaciones que no contienen ninguna carga, o puede especificar un System.Type que haga referencia a otra interfaz en la definición de API, normalmente con el nombre que termina con "EventArgs". El generador convertirá la interfaz en una clase que subclase EventArgs e incluirá todas las propiedades enumeradas allí. El [Export] atributo debe usarse en la EventArgs clase para enumerar el nombre de la clave utilizada para buscar el Objective-C diccionario para capturar el valor.

Por ejemplo:

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

El código anterior generará una clase MyClass.Notifications anidada con los métodos siguientes:

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

Los usuarios del código pueden suscribirse fácilmente a las notificaciones publicadas en NSDefaultCenter mediante código similar al siguiente:

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

O bien, para establecer un objeto específico que se va a observar. Si pasa null a objectToObserve este método se comportará igual que su otro elemento del mismo nivel.

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

El valor devuelto de ObserveDidStart se puede usar para dejar fácilmente de recibir notificaciones, de la siguiente manera:

token.Dispose ();

También puede llamar a NSNotification.DefaultCenter.RemoveObserver y pasar el token. Si la notificación contiene parámetros, debe especificar una EventArgs interfaz auxiliar, de la siguiente manera:

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

Lo anterior generará una MyScreenChangedEventArgs clase con las ScreenX propiedades y ScreenY que capturarán los datos del diccionario NSNotification.UserInfo mediante las claves ScreenXKey y ScreenYKey , respectivamente, y aplicarán las conversiones adecuadas. El [ProbePresence] atributo se usa para que el generador sondee si la clave está establecida en , en UserInfolugar de intentar extraer el valor. Esto se usa para los casos en los que la presencia de la clave es el valor (normalmente para los valores booleanos).

Esto le permite escribir código similar al siguiente:

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

En algunos casos, no hay ninguna constante asociada al valor pasado en el diccionario. Apple a veces usa constantes de símbolos públicos y, a veces, usa constantes de cadena. De forma predeterminada, el [Export] atributo de la clase proporcionada EventArgs usará el nombre especificado como símbolo público para que se examine en tiempo de ejecución. Si este no es el caso y, en su lugar, se supone que se debe buscar como una constante de cadena, pase el ArgumentSemantic.Assign valor al atributo Export.

Novedades de Xamarin.iOS 8.4

A veces, las notificaciones comenzarán a crearse sin argumentos, por lo que el uso de [Notification] sin argumentos es aceptable. Pero a veces, se introducirán parámetros en la notificación. Para admitir este escenario, el atributo se puede aplicar más de una vez.

Si va a desarrollar un enlace y desea evitar interrumpir el código de usuario existente, debería convertir una notificación existente de:

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

En una versión que muestra el atributo de notificación dos veces, de la siguiente manera:

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

NullAllowedAttribute

Cuando esto se aplica a una propiedad marca la propiedad como permitir que el valor null se le asigne. Esto solo es válido para los tipos de referencia.

Cuando se aplica a un parámetro en una firma de método, indica que el parámetro especificado puede ser NULL y que no se debe realizar ninguna comprobación para pasar null valores.

Si el tipo de referencia no tiene este atributo, la herramienta de enlace generará una comprobación para el valor que se va a asignar antes de pasarlo a Objective-C y generará una comprobación que producirá un ArgumentNullException si el valor asignado es null.

Por ejemplo:

// In properties

[NullAllowed]
UIImage IconFile { get; set; }

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

OverrideAttribute

Use este atributo para indicar al generador de enlaces que el enlace de este método en particular debe marcarse con una override palabra clave .

PreSnippetAttribute

Puede usar este atributo para insertar código que se va a insertar después de validar los parámetros de entrada, pero antes de que el código llame a en Objective-C.

Ejemplo:

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

PrologueSnippetAttribute

Puede usar este atributo para insertar código que se va a insertar antes de que cualquiera de los parámetros se valide en el método generado.

Ejemplo:

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

PostGetAttribute

Indica al generador de enlaces que invoque la propiedad especificada de esta clase para capturar un valor de ella.

Esta propiedad se usa normalmente para actualizar la memoria caché que apunta a objetos de referencia que mantienen al gráfico de objetos al que se hace referencia. Normalmente se muestra en el código que tiene operaciones como Agregar o quitar. Este método se usa para que, después de agregar o quitar elementos, se actualice la memoria caché interna para asegurarnos de que se mantienen referencias administradas a objetos que realmente están en uso. Esto es posible porque la herramienta de enlace genera un campo de respaldo para todos los objetos de referencia de un enlace determinado.

Ejemplo:

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

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

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

En este caso, la Dependencies propiedad se invocará después de agregar o quitar dependencias del NSOperation objeto, lo que garantiza que tenemos un gráfico que representa los objetos cargados reales, lo que evita pérdidas de memoria, así como daños en la memoria.

PostSnippetAttribute

Puede usar este atributo para insertar código fuente de C# después de que el código haya invocado el método subyacente Objective-C .

Ejemplo:

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

ProxyAttribute

Este atributo se aplica para devolver valores para marcarlos como objetos proxy. Algunas Objective-C API devuelven objetos proxy que no se pueden diferenciar de los enlaces de usuario. El efecto de este atributo es marcar el objeto como un DirectBinding objeto . Para ver un escenario en Xamarin.Mac, puede ver la discusión sobre este error.

RetainListAttribute

Indica al generador que mantenga una referencia administrada al parámetro o quite una referencia interna al parámetro . Se usa para mantener los objetos a los que se hace referencia.

Sintaxis:

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

Si el valor de doAdd es true, el parámetro se agrega a __mt_{0}_var List<NSObject>;. Donde {0} se reemplaza por el especificado listName. Debe declarar este campo de respaldo en la clase parcial complementaria a la API.

Para obtener un ejemplo, consulte foundation.cs y NSNotificationCenter.cs.

ReleaseAttribute (Xamarin.iOS 6.0)

Esto se puede aplicar a los tipos devueltos para indicar que el generador debe llamar Release a en el objeto antes de devolverlo. Esto solo es necesario cuando un método proporciona un objeto retenido (en lugar de un objeto autoeleado, que es el escenario más común).

Ejemplo:

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

Además, este atributo se propaga al código generado, de modo que el entorno de ejecución de Xamarin.iOS sepa que debe conservar el objeto al volver a Objective-C desde dicha función.

SealedAttribute

Indica al generador que marque el método generado como sellado. Si no se especifica este atributo, el valor predeterminado es generar un método virtual (ya sea un método virtual, un método abstracto o una invalidación en función de cómo se usen otros atributos).

StaticAttribute

Cuando el [Static] atributo se aplica a un método o propiedad, esto genera un método o propiedad estáticos. Si no se especifica este atributo, el generador genera un método o propiedad de instancia.

TransientAttribute

Use este atributo para marcar las propiedades cuyos valores son transitorios, es decir, los objetos creados temporalmente por iOS, pero que no son de larga duración. Cuando este atributo se aplica a una propiedad, el generador no crea un campo de respaldo para esta propiedad, lo que significa que la clase administrada no mantiene una referencia al objeto .

WrapAttribute

En el diseño de los enlaces de Xamarin.iOS/Xamarin.Mac, el [Wrap] atributo se usa para encapsular un objeto débilmente tipado con un objeto fuertemente tipado. Esto entra en juego principalmente con Objective-C objetos delegados que normalmente se declaran como de tipo id o NSObject. La convención que usa Xamarin.iOS y Xamarin.Mac es exponer esos delegados o orígenes de datos como de tipo NSObject y se denominan mediante la convención "Débil" + el nombre que se expone. Una id delegate propiedad de Objective-C se expondría como una NSObject WeakDelegate { get; set; } propiedad en el archivo de contrato de API.

Pero normalmente el valor que se asigna a este delegado es de un tipo seguro, por lo que se expone el tipo seguro y se aplica el [Wrap] atributo, esto significa que los usuarios pueden optar por usar tipos débiles si necesitan algún control preciso o si necesitan recurrir a trucos de bajo nivel, o pueden usar la propiedad fuertemente tipada para la mayoría de sus trabajos.

Ejemplo:

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

Así es como el usuario usaría la versión débilmente tipada del delegado:

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

}

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

Y así es como el usuario usaría la versión fuertemente tipada, observe que el usuario aprovecha el sistema de tipos de C#y usa la palabra clave override para declarar su intención y que no tiene que decorar manualmente el método con [Export], ya que lo hicimos en el enlace para el usuario:

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

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

Otro uso del [Wrap] atributo es admitir la versión fuertemente tipada de métodos. Por ejemplo:

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

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

Cuando el [Wrap] atributo se aplica en un método dentro de un tipo decorado con un [Category] atributo , debe incluir This como primer argumento, ya que se genera un método de extensión. Por ejemplo:

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

Los miembros generados por [Wrap] no virtual son de forma predeterminada, si necesita un virtual miembro, puede establecerlo en true el parámetro opcional isVirtual .

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

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

[Wrap] también se puede usar directamente en captadores de propiedades y establecedores. Esto permite tener control total sobre ellos y ajustar el código según sea necesario. Por ejemplo, considere la siguiente definición de API que usa enumeraciones inteligentes:

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

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

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

Definición de interfaz:

// Property definition.

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

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

Atributos de parámetro

En esta sección se describen los atributos que se pueden aplicar a los parámetros de una definición de método, así como a los [NullAttribute] que se aplican a una propiedad en su conjunto.

BlockCallback

Este atributo se aplica a los tipos de parámetro de las declaraciones de delegado de C# para notificar al enlazador que el parámetro en cuestión se ajusta a la Objective-C convención de llamada de bloque y debe serializarlo de esta manera.

Esto se usa normalmente para las devoluciones de llamada que se definen de la siguiente manera en Objective-C:

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

Consulte también: CCallback.

CCallback

Este atributo se aplica a los tipos de parámetro en declaraciones de delegado de C# para notificar al enlazador que el parámetro en cuestión se ajusta a la convención de llamada del puntero de función ABI de C y debe serializarlo de esta manera.

Esto se usa normalmente para las devoluciones de llamada que se definen de la siguiente manera en Objective-C:

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

Consulte también: BlockCallback.

Params

Puede usar el [Params] atributo en el último parámetro de matriz de una definición de método para que el generador inserte un "parámetro" en la definición. Esto permite que el enlace permita fácilmente parámetros opcionales.

Por ejemplo, la definición siguiente:

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

Permite escribir el código siguiente:

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

Esto tiene la ventaja agregada de que no requiere que los usuarios creen una matriz únicamente para pasar elementos.

PlainString

Puede usar el [PlainString] atributo delante de los parámetros de cadena para indicar al generador de enlaces que pase la cadena como una cadena de C, en lugar de pasar el parámetro como .NSString

La mayoría Objective-C de las API consumen NSString parámetros, pero una serie de API exponen una char * API para pasar cadenas, en lugar de la NSString variación. Use [PlainString] en esos casos.

Por ejemplo, las siguientes Objective-C declaraciones:

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

Debe enlazarse de esta manera:

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

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

RetainAttribute

Indica al generador que mantenga una referencia al parámetro especificado. El generador proporcionará el almacén de respaldo para este campo o puede especificar un nombre (el ) en el WrapNameque almacenar el valor. Esto resulta útil para contener una referencia a un objeto administrado que se pasa como parámetro a Objective-C y cuando sepa que Objective-C solo conservará esta copia del objeto. Por ejemplo, una API como SetDisplay (SomeObject) usaría este atributo, ya que es probable que SetDisplay solo pudiera mostrar un objeto a la vez. Si necesita realizar un seguimiento de más de un objeto (por ejemplo, para una API similar a stack), usaría el [RetainList] atributo .

Sintaxis:

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

RetainListAttribute

Indica al generador que mantenga una referencia administrada al parámetro o quite una referencia interna al parámetro . Se usa para mantener los objetos a los que se hace referencia.

Sintaxis:

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

Si el valor de doAdd es true, el parámetro se agrega a __mt_{0}_var List<NSObject>. Donde {0} se reemplaza por el especificado listName. Debe declarar este campo de respaldo en la clase parcial complementaria a la API.

Para obtener un ejemplo, consulte foundation.cs y NSNotificationCenter.cs.

TransientAttribute

Este atributo se aplica a los parámetros y solo se usa al realizar la transición de Objective-C a C#. Durante esas transiciones, los distintos Objective-CNSObject parámetros se encapsulan en una representación administrada del objeto.

El tiempo de ejecución tomará una referencia al objeto nativo y mantendrá la referencia hasta que se haya ido la última referencia administrada al objeto y el GC tendrá la oportunidad de ejecutarse.

En algunos casos, es importante que el entorno de ejecución de C# no mantenga una referencia al objeto nativo. Esto sucede a veces cuando el código nativo subyacente ha asociado un comportamiento especial al ciclo de vida del parámetro. Por ejemplo: el destructor del parámetro realizará alguna acción de limpieza o eliminará algún recurso precioso.

Este atributo informa al tiempo de ejecución de que desea que el objeto se elimine si es posible al volver al Objective-C método sobrescrito.

La regla es sencilla: si el tiempo de ejecución tenía que crear una nueva representación administrada desde el objeto nativo, al final de la función, se quitará el recuento de retención del objeto nativo y se borrará la propiedad Handle del objeto administrado. Esto significa que si mantiene una referencia al objeto administrado, esa referencia será inútil (invocar métodos en él producirá una excepción).

Si el objeto pasado no se creó o si ya había una representación administrada pendiente del objeto, no se realiza la eliminación forzada.

Atributos de propiedad

NotImplementedAttribute

Este atributo se usa para admitir una Objective-C expresión en la que se introduce una propiedad con un captador en una clase base y una subclase mutable introduce un establecedor.

Dado que C# no admite este modelo, la clase base debe tener el establecedor y el captador, y una subclase puede usar OverrideAttribute.

Este atributo solo se usa en establecedores de propiedades y se usa para admitir la expresión mutable en Objective-C.

Ejemplo:

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

Atributos de enumeración

La asignación NSString de constantes a valores de enumeración es una manera fácil de crear una mejor API de .NET. Este:

  • permite que la finalización del código sea más útil, mostrando solo los valores correctos para la API;
  • agrega seguridad de tipos, no se puede usar otra NSString constante en un contexto incorrecto; y
  • permite ocultar algunas constantes, lo que hace que la finalización del código muestre una lista de API más corta sin perder la funcionalidad.

Ejemplo:

enum NSRunLoopMode {

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

    [Field ("NSRunLoopCommonModes")]
    Common,

    [Field (null)]
    Other = 1000
}

A partir de la definición de enlace anterior, el generador creará el enum propio y también creará un *Extensions tipo estático que incluye métodos de conversión de dos maneras entre los valores de enumeración y las NSString constantes. Esto significa que las constantes permanecen disponibles para los desarrolladores aunque no formen parte de la API.

Ejemplos:

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

Puede decorar un valor de enumeración con este atributo. Se convertirá en la constante que se devuelve si no se conoce el valor de enumeración.

En el ejemplo anterior:

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

Si no hay ningún valor de enumeración decorado, se producirá una NotSupportedException excepción .

ErrorDomainAttribute

Los códigos de error se enlazan como valores de enumeración. Por lo general, hay un dominio de error para ellos y no siempre es fácil encontrar cuál se aplica (o si existe uno).

Puede usar este atributo para asociar el dominio de error a la propia enumeración.

Ejemplo:

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

A continuación, puede llamar al método GetDomain de extensión para obtener la constante de dominio de cualquier error.

FieldAttribute

Este es el mismo [Field] atributo que se usa para las constantes dentro del tipo . También se puede usar dentro de enumeraciones para asignar un valor con una constante específica.

Se puede usar un null valor para especificar qué valor de enumeración se debe devolver si se especifica una nullNSString constante.

En el ejemplo anterior:

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

Si no hay ningún null valor presente, se producirá una ArgumentNullException excepción .

Atributos globales

Los atributos globales se aplican mediante el [assembly:] modificador de atributo como o [LinkWithAttribute] se pueden usar en cualquier lugar, como los [Lion] atributos y [Since] .

LinkWithAttribute

Se trata de un atributo de nivel de ensamblado que permite a los desarrolladores especificar las marcas de vinculación necesarias para reutilizar una biblioteca enlazada sin forzar al consumidor de la biblioteca a configurar manualmente los argumentos gcc_flags y mtouch adicionales pasados a una biblioteca.

Sintaxis:

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

Este atributo se aplica en el nivel de ensamblado, por ejemplo, esto es lo que usan los enlaces CorePlot :

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

Cuando se usa el [LinkWith] atributo , el especificado libraryName se inserta en el ensamblado resultante, lo que permite a los usuarios enviar un único archivo DLL que contenga las dependencias no administradas, así como las marcas de línea de comandos necesarias para consumir correctamente la biblioteca de Xamarin.iOS.

También es posible no proporcionar un libraryName, en cuyo caso el LinkWith atributo solo se puede usar para especificar marcas de enlazador adicionales:

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

Constructores LinkWithAttribute

Estos constructores permiten especificar la biblioteca con la que vincular e insertar en el ensamblado resultante, los destinos admitidos que la biblioteca admite y las marcas de biblioteca opcionales necesarias para vincular con la biblioteca.

Tenga en cuenta que Xamarin.iOS deduce el LinkTarget argumento y no es necesario establecerlo.

Ejemplos:

// 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 propiedad se usa para decidir si se usa o no la -force_load marca de vínculo para vincular la biblioteca nativa. Por ahora, esto siempre debería ser cierto.

LinkWithAttribute.Frameworks

Si la biblioteca enlazada tiene un requisito estricto en cualquier marco (distinto Foundation de y UIKit), debe establecer la Frameworks propiedad en una cadena que contenga una lista delimitada por espacios de los marcos de plataforma necesarios. Por ejemplo, si va a enlazar una biblioteca que requiere CoreGraphics y CoreText, establecería la Frameworks propiedad "CoreGraphics CoreText"en .

LinkWithAttribute.IsCxx

Establezca esta propiedad en true si el ejecutable resultante debe compilarse mediante un compilador de C++ en lugar del valor predeterminado, que es un compilador de C. Úselo si la biblioteca que está enlazando se escribió en C++.

LinkWithAttribute.LibraryName

Nombre de la biblioteca no administrada que se va a agrupar. Se trata de un archivo con la extensión ".a" y puede contener código de objeto para varias plataformas (por ejemplo, ARM y x86 para el simulador).

Las versiones anteriores de Xamarin.iOS comprobaron la propiedad para determinar la LinkTarget plataforma que admitía la biblioteca, pero ahora se detecta automáticamente y se omite la LinkTarget propiedad .

LinkWithAttribute.LinkerFlags

La LinkerFlags cadena proporciona una manera de que los autores de enlaces especifiquen las marcas de enlazador adicionales necesarias al vincular la biblioteca nativa a la aplicación.

Por ejemplo, si la biblioteca nativa requiere libxml2 y zlib, establecería la LinkerFlags cadena en "-lxml2 -lz".

LinkWithAttribute.LinkTarget

Las versiones anteriores de Xamarin.iOS comprobaron la propiedad para determinar la LinkTarget plataforma que admitía la biblioteca, pero ahora se detecta automáticamente y se omite la LinkTarget propiedad .

LinkWithAttribute.NeedsGccExceptionHandling

Establezca esta propiedad en true si la biblioteca que está vinculando requiere la biblioteca de control de excepciones de GCC (gcc_eh)

La SmartLink propiedad debe establecerse en true para permitir que Xamarin.iOS determine si ForceLoad es necesario o no.

LinkWithAttribute.WeakFrameworks

La WeakFrameworks propiedad funciona de la misma manera que la Frameworks propiedad , salvo que en el momento del vínculo, el -weak_framework especificador se pasa a gcc para cada uno de los marcos enumerados.

WeakFrameworks permite que las bibliotecas y las aplicaciones se vinculen débilmente con los marcos de plataforma para que puedan usarlas opcionalmente si están disponibles, pero no dependen de ellas de forma difícil, lo que resulta útil si la biblioteca está pensada para agregar características adicionales en las versiones más recientes de iOS. Para obtener más información sobre la vinculación débil, consulte la documentación de Apple sobre la vinculación débil.

Los buenos candidatos para la vinculación débil serían Frameworks como Cuentas, CoreBluetooth, CoreImage, GLKity , NewsstandKit ya Twitter que solo están disponibles en iOS 5.

SinceAttribute (iOS) y LionAttribute (macOS)

El atributo se usa para marcar las [Since] API como introducidas en un momento dado. El atributo solo se debe usar para marcar tipos y métodos que podrían causar un problema en tiempo de ejecución si la clase, el método o la propiedad subyacentes no están disponibles.

Sintaxis:

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

En general, no se debe aplicar a enumeraciones, restricciones o nuevas estructuras, ya que no provocarían un error en tiempo de ejecución si se ejecutan en un dispositivo con una versión anterior del sistema operativo.

Ejemplo cuando se aplica a un tipo:

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

Ejemplo cuando se aplica a un nuevo miembro:

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

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

El [Lion] atributo se aplica de la misma manera, pero para los tipos introducidos con Lion. La razón de usar [Lion] frente al número de versión más específico que se usa en iOS es que iOS se revisa muy a menudo, mientras que las versiones principales de OS X rara vez se producen y es más fácil recordar el sistema operativo por su nombre de código que por su número de versión.

AdviceAttribute

Use este atributo para proporcionar a los desarrolladores una sugerencia sobre otras API que podrían resultar más cómodas para que las usen. Por ejemplo, si proporciona una versión fuertemente tipada de una API, podría usar este atributo en el atributo débilmente tipado para dirigir al desarrollador a la mejor API.

La información de este atributo se muestra en la documentación y las herramientas se pueden desarrollar para proporcionar sugerencias de usuario sobre cómo mejorar

RequiresSuperAttribute

Se trata de una subclase especializada del [Advice] atributo que se puede usar para sugerir al desarrollador que invalidar un método requiere una llamada al método base (invalidado).

Esto corresponde a clang__attribute__((objc_requires_super))

ZeroCopyStringsAttribute

Solo está disponible en Xamarin.iOS 5.4 y versiones posteriores.

Este atributo indica al generador que el enlace para esta biblioteca específica (si se aplica con [assembly:]) o el tipo debe usar la serialización rápida de cadenas de copia cero. Este atributo equivale a pasar la opción --zero-copy de línea de comandos al generador.

Cuando se usa una copia cero para cadenas, el generador usa eficazmente la misma cadena de C# que la cadena que Objective-C consume sin incurrir en la creación de un nuevo NSString objeto y evitando copiar los datos de las cadenas de C# en la Objective-C cadena. El único inconveniente de usar cadenas de copia cero es que debe asegurarse de que cualquier propiedad de cadena que encapsula que se marque como retain o copy tenga el conjunto de [DisableZeroCopy] atributos. Esto es necesario porque el identificador de las cadenas de copia cero se asigna en la pila y no es válido en la devolución de la función.

Ejemplo:

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

También puede aplicar el atributo en el nivel de ensamblado y se aplicará a todos los tipos del ensamblado:

[assembly:ZeroCopyStrings]

Diccionarios fuertemente tipados

Con Xamarin.iOS 8.0 presentamos compatibilidad para crear fácilmente clases fuertemente tipadas que encapsulan NSDictionaries.

Aunque siempre ha sido posible usar el tipo de datos DictionaryContainer junto con una API manual, ahora es mucho más sencillo hacerlo. Para obtener más información, vea Surfacing Strong Types.

StrongDictionary

Cuando este atributo se aplica a una interfaz, el generador generará una clase con el mismo nombre que la interfaz que deriva de DictionaryContainer y convierte cada propiedad definida en la interfaz en un captador fuertemente tipado y establecedor para el diccionario.

Esto genera automáticamente una clase que se puede crear a partir de una existente NSDictionary o que se ha creado.

Este atributo toma un parámetro, el nombre de la clase que contiene las claves que se usan para tener acceso a los elementos del diccionario. De forma predeterminada, cada propiedad de la interfaz con el atributo buscará un miembro en el tipo especificado para un nombre con el sufijo "Key".

Por ejemplo:

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

En el caso anterior, la MyOption clase generará una propiedad de cadena para Name que usará MyOptionKeys.NameKey como clave en el diccionario para recuperar una cadena. Y usará como MyOptionKeys.AgeKey clave en el diccionario para recuperar un NSNumber objeto que contiene un valor int.

Si desea usar una clave diferente, puede usar el atributo export en la propiedad , por ejemplo:

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

Tipos de diccionario seguros

En la StrongDictionary definición se admiten los siguientes tipos de datos:

Tipo de interfaz de C# NSDictionary Tipo de almacenamiento
bool Boolean almacenados en un NSNumber
Valores de enumeración entero almacenado en un NSNumber
int Entero de 32 bits almacenado en un NSNumber
uint Entero sin signo de 32 bits almacenado en un NSNumber
nint NSInteger almacenados en un NSNumber
nuint NSUInteger almacenados en un NSNumber
long Entero de 64 bits almacenado en un NSNumber
float Entero de 32 bits almacenado como un NSNumber
double Entero de 64 bits almacenado como un NSNumber
NSObject y subclases NSObject
NSDictionary NSDictionary
string NSString
NSString NSString
C# Array de NSObject NSArray
C# Array de enumeraciones NSArray que contiene NSNumber valores