Share via


Guia de referência de tipos de vinculação

Este documento descreve a lista de atributos que você pode usar para anotar seus arquivos de contrato de API para conduzir a associação e o código gerado

Os contratos de API Xamarin.iOS e Xamarin.Mac são escritos em C# principalmente como definições de interface que definem a maneira como Objective-C o código é exibido em C#. O processo envolve uma combinação de declarações de interface mais algumas definições de tipo básicas que o contrato de API pode exigir. Para obter uma introdução aos tipos de vinculação, consulte nosso guia complementar Bibliotecas de vinculaçãoObjective-C.

Definições de tipo

Sintaxe:

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

Cada interface em sua definição de contrato que tem o [BaseType] atributo declara o tipo base para o objeto gerado. Na declaração acima, será gerado um MyType tipo de classe C# que se vincula a um Objective-C tipo chamado MyType.

Se você especificar quaisquer tipos após o typename (no exemplo acima Protocol1 e Protocol2) usando a sintaxe de herança de interface, o conteúdo dessas interfaces será embutido como se tivessem feito parte do contrato para MyType. A maneira como o Xamarin.iOS mostra que um tipo adota um protocolo é inserindo todos os métodos e propriedades que foram declarados no protocolo no próprio tipo.

A seguir mostra como a Objective-C declaração para UITextField seria definida em um contrato Xamarin.iOS:

@interface UITextField : UIControl <UITextInput> {

}

Seria escrito assim como um contrato de API C#:

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

Você pode controlar muitos outros aspectos da geração de código aplicando outros atributos à interface, bem como configurando o [BaseType] atributo.

Geração de eventos

Um recurso do design da API Xamarin.iOS e Xamarin.Mac é que mapeamos Objective-C classes delegadas como eventos C# e retornos de chamada. Os usuários podem escolher por instância se desejam adotar o Objective-C padrão de programação, atribuindo propriedades como Delegate uma instância de uma classe que implementa os vários métodos que o Objective-C tempo de execução chamaria ou escolhendo os eventos e propriedades no estilo C#.

Vejamos um exemplo de como usar o 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 ();
    }
}

No exemplo acima, você pode ver que optamos por substituir dois métodos, um uma notificação de que um evento de rolagem ocorreu e o segundo que é um retorno de chamada que deve retornar um valor booleano instruindo se scrollView ele deve rolar para o topo ou não.

O modelo C# permite que o usuário de sua biblioteca ouça notificações usando a sintaxe de evento C# ou a sintaxe de propriedade para conectar retornos de chamada que devem retornar valores.

É assim que o código C# para o mesmo recurso se parece usando 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 ();
}

Como os eventos não retornam valores (eles têm um tipo de retorno void), você pode conectar várias cópias. O ShouldScrollToTop não é um evento, é uma propriedade com o tipo UIScrollViewCondition que tem esta assinatura:

public delegate bool UIScrollViewCondition (UIScrollView scrollView);

Ele retorna um bool valor, neste caso a sintaxe lambda nos permite apenas retornar o valor da MakeDecision função.

O gerador de vinculação suporta a geração de eventos e propriedades que vinculam uma classe como UIScrollView com sua UIScrollViewDelegate (bem chamá-los de classe Model), isso é feito anotando sua [BaseType] definição com os Events parâmetros e Delegates (descritos abaixo). Além de anotar o [BaseType] com esses parâmetros, é necessário informar ao gerador mais alguns componentes.

Para eventos que usam mais de um parâmetro (na Objective-C convenção é que o primeiro parâmetro em uma classe delegada é a instância do objeto sender), você deve fornecer o nome que você gostaria que a classe gerada EventArgs fosse. Isso é feito com o [EventArgs] atributo na declaração de método em sua classe Model. Por exemplo:

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

A declaração acima gerará uma UIImagePickerImagePickedEventArgs classe que deriva de EventArgs e empacota ambos os parâmetros, o UIImage e o NSDictionary. O gerador produz o seguinte:

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

Em seguida, expõe o seguinte na UIImagePickerController aula:

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

Os métodos de modelo que retornam um valor são vinculados de forma diferente. Eles exigem um nome para o delegado C# gerado (a assinatura para o método) e também um valor padrão para retornar caso o usuário não forneça uma implementação. Por exemplo, a ShouldScrollToTop definição é esta:

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

O acima criará um UIScrollViewCondition delegado com a assinatura mostrada acima e, se o usuário não fornecer uma implementação, o valor de retorno será true.

Além do [DefaultValue] atributo, você também pode usar o [DefaultValueFromArgument] atributo que direciona o gerador para retornar o valor do parâmetro especificado na chamada ou o [NoDefaultValue] parâmetro que instrui o gerador de que não há nenhum valor padrão.

BaseTypeAttribute

Sintaxe:

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

Use a Name propriedade para controlar o nome ao qual esse tipo se vinculará no Objective-C mundo. Isso normalmente é usado para dar ao tipo C# um nome que é compatível com as diretrizes de design do .NET Framework, mas que mapeia para um nome que Objective-C não segue essa convenção.

Exemplo, no caso a seguir, mapeamos o Objective-CNSURLConnection tipo para NSUrlConnection, como as diretrizes de design do .NET Framework usam "Url" em vez de "URL":

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

O nome especificado é usado como o valor para o atributo gerado [Register] na associação. Se Name não for especificado, o nome curto do tipo será usado como o valor para o [Register] atributo na saída gerada.

BaseType.Events e BaseType.Delegates

Essas propriedades são usadas para conduzir a geração de eventos de estilo C# nas classes geradas. Eles são usados para vincular uma determinada classe com sua Objective-C classe delegada. Você encontrará muitos casos em que uma classe usa uma classe delegada para enviar notificações e eventos. Por exemplo, um teria uma classe companheira BarcodeScannerBardodeScannerDelegate . A BarcodeScanner classe normalmente teria uma Delegate propriedade à qual você atribuiria uma instância de BarcodeScannerDelegate , enquanto isso funciona, talvez você queira expor aos usuários uma interface de evento de estilo semelhante ao C# e, nesses casos, você usaria as Events propriedades e Delegates do [BaseType] atributo.

Essas propriedades são sempre definidas juntas e devem ter o mesmo número de elementos e ser mantidas em sincronia. A Delegates matriz contém uma cadeia de caracteres para cada delegado de tipo fraco que você deseja encapsular, e a Events matriz contém um tipo para cada tipo que você deseja associar a ela.

[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

Se você aplicar esse atributo quando novas instâncias dessa classe forem criadas, a instância desse objeto será mantida até que o método referenciado pelo KeepRefUntil tenha sido invocado. Isso é útil para melhorar a usabilidade de suas APIs, quando você não deseja que o usuário mantenha uma referência a um objeto para usar seu código. O valor dessa propriedade é o nome de um método na Delegate classe, portanto, você deve usá-lo em combinação com as Events propriedades e Delegates também.

O exemplo a seguir mostra como isso é usado pelo 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

Quando esse atributo é aplicado à definição de interface, ele gerará um [DesignatedInitializer] atributo no construtor padrão (gerado), que mapeia para o init seletor.

DisableDefaultCtorAttribute

Quando esse atributo é aplicado à definição de interface, ele impedirá que o gerador produza o construtor padrão.

Use esse atributo quando precisar que o objeto seja inicializado com um dos outros construtores na classe.

PrivateDefaultCtorAttribute

Quando esse atributo é aplicado à definição de interface, ele sinalizará o construtor padrão como private. Isso significa que você ainda pode instanciar o objeto dessa classe internamente a partir do seu arquivo de extensão, mas ele simplesmente não estará acessível aos usuários da sua classe.

CategoriaAtributo

Use esse atributo em uma definição de tipo para vincular Objective-C categorias e expô-las como métodos de extensão C# para espelhar a maneira como Objective-C expõe a funcionalidade.

Categorias são um Objective-C mecanismo usado para estender o conjunto de métodos e propriedades disponíveis em uma classe. Na prática, eles são usados para estender a funcionalidade de uma classe base (por exemplo NSObject) quando uma estrutura específica é vinculada (por exemplo UIKit), disponibilizando seus métodos, mas apenas se a nova estrutura estiver vinculada. Em alguns outros casos, eles são usados para organizar recursos em uma classe por funcionalidade. Eles são semelhantes em espírito aos métodos de extensão C#.

Esta é a aparência de uma categoria em Objective-C:

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

O exemplo acima é encontrado em uma biblioteca que estenderia instâncias de UIView com o método makeBackgroundRed.

Para vinculá-los, você pode usar o [Category] atributo em uma definição de interface. Ao usar o atributo [Category] , o [BaseType] significado do atributo muda de ser usado para especificar a classe base a ser estendida para ser o tipo a ser estendido.

A seguir mostra como as UIView extensões são vinculadas e transformadas em métodos de extensão C#:

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

O acima criará uma MyUIViewExtension classe que contém o método de MakeBackgroundRed extensão. Isso significa que agora você pode chamar MakeBackgroundRed qualquer UIView subclasse, dando-lhe a mesma funcionalidade que você obteria no Objective-C.

Em alguns casos, você encontrará membros estáticos dentro de categorias, como no exemplo a seguir:

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

Isso levará a uma definição incorreta da interface Categoria C#:

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

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

Isso está incorreto porque para usar a BoolMethod extensão você precisa de uma instância deFooObject, mas você está vinculando uma extensão estática ObjC, isso é um efeito colateral devido ao fato de como os métodos de extensão C# são implementados.

A única maneira de usar as definições acima é pelo seguinte código feio:

(null as FooObject).BoolMethod (range);

A recomendação para evitar isso é embutir a BoolMethod definição dentro da própria definição de FooObject interface, isso permitirá que você chame essa extensão como ela é pretendida FooObject.BoolMethod (range).

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

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

Emitiremos um aviso (BI1117) sempre que encontrarmos um [Static] membro dentro de uma [Category] definição. Se você realmente quer ter [Static] membros dentro de suas [Category] definições, você pode silenciar o aviso usando [Category (allowStaticMembers: true)] ou decorando seu membro ou [Category] definição de interface com [Internal].

StaticAttribute

Quando esse atributo é aplicado a uma classe, ele apenas gera uma classe estática, que não deriva de NSObject, para que o [BaseType] atributo seja ignorado. As classes estáticas são usadas para hospedar variáveis públicas C que você deseja expor.

Por exemplo:

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

Gerará uma classe C# com a seguinte API:

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

Definições de protocolo/modelo

Os modelos são normalmente usados pela implementação de protocolo. Eles diferem em que o tempo de execução só será registrado com Objective-C os métodos que realmente foram substituídos. Caso contrário, o método não será registrado.

Isso em geral significa que quando você subclasse uma classe que foi sinalizada com o ModelAttribute, você não deve chamar o método base. Chamar esse método lançará a seguinte exceção: Foundation.You_Should_Not_Call_base_In_This_Method. Você deve implementar todo o comportamento em sua subclasse para quaisquer métodos que você substituir.

Atributo Abstracto

Por padrão, os membros que fazem parte de um protocolo não são obrigatórios. Isso permite que os Model usuários criem uma subclasse do objeto simplesmente derivando da classe em C# e substituindo apenas os métodos que lhes interessam. Às vezes, o Objective-C contrato exige que o usuário forneça uma implementação para esse método (esses são sinalizados com a @required diretiva em Objective-C). Nesses casos, você deve sinalizar esses métodos com o [Abstract] atributo.

O [Abstract] atributo pode ser aplicado a métodos ou propriedades e faz com que o gerador sinalize o membro gerado como abstrato e a classe como uma classe abstrata.

O seguinte é retirado do Xamarin.iOS:

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

DefaultValueAttribute

Especifica o valor padrão a ser retornado por um método de modelo se o usuário não fornecer um método para esse método específico no objeto Model

Sintaxe:

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

Por exemplo, na classe de delegação imaginária a seguir para uma Camera classe, fornecemos uma ShouldUploadToServer que seria exposta como uma propriedade na Camera classe. Se o usuário da classe não definir explicitamente um valor para um lambda que pode responder true ou false, o retorno de Camera valor padrão nesse caso seria false, o valor que especificamos no DefaultValue atributo:

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

Se o usuário definir um manipulador na classe imaginária, esse valor será ignorado:

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

Veja também: [NoDefaultValue], [DefaultValueFromArgument].

DefaultValueFromArgumentAttribute

Sintaxe:

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

Esse atributo, quando fornecido em um método que retorna um valor em uma classe de modelo, instruirá o gerador a retornar o valor do parâmetro especificado se o usuário não fornecer seu próprio método ou lambda.

Exemplo:

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

No caso acima, se o usuário da classe optasse por usar qualquer um dos eventos/propriedades do C# e não definisse NSAnimation.ComputeAnimationCurve como um método ou lambda, o valor de NSAnimation retorno seria o valor passado no parâmetro progress.

Veja também: [NoDefaultValue], [DefaultValue]

IgnoredInDelegateAttribute

Às vezes, faz sentido não expor um evento ou delegar propriedade de uma classe Model na classe host, portanto, adicionar esse atributo instruirá o gerador a evitar a geração de qualquer método decorado com ele.

[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

Esse atributo é usado em métodos Model que retornam valores para definir o nome da assinatura delegada a ser usada.

Exemplo:

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

Com a definição acima, o gerador produzirá a seguinte declaração pública:

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

DelegateApiNameAttribute

Esse atributo é usado para permitir que o gerador altere o nome da propriedade gerada na classe host. Às vezes, é útil quando o nome do método de classe FooDelegate faz sentido para a classe Delegate, mas pareceria estranho na classe host como uma propriedade.

Além disso, isso é realmente útil (e necessário) quando você tem dois ou mais métodos de sobrecarga que faz sentido mantê-los nomeados como está na classe FooDelegate, mas você deseja expô-los na classe host com um nome próprio melhor.

Exemplo:

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

Com a definição acima, o gerador produzirá a seguinte declaração pública na classe host:

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

EventArgsAttribute

Para eventos que usam mais de um parâmetro (na Objective-C convenção é que o primeiro parâmetro em uma classe delegada é a instância do objeto sender), você deve fornecer o nome que deseja que a classe EventArgs gerada seja. Isso é feito com o [EventArgs] atributo na declaração de método em sua Model classe.

Por exemplo:

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

A declaração acima gerará uma UIImagePickerImagePickedEventArgs classe que deriva de EventArgs e empacota ambos os parâmetros, o UIImage e o NSDictionary. O gerador produz o seguinte:

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

Em seguida, expõe o seguinte na UIImagePickerController aula:

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

EventNameAttribute

Esse atributo é usado para permitir que o gerador altere o nome de um evento ou propriedade gerada na classe. Às vezes, é útil quando o nome do método de classe Model faz sentido para a classe de modelo, mas pareceria estranho na classe de origem como um evento ou propriedade.

Por exemplo, o UIWebView usa o seguinte bit do UIWebViewDelegate:

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

O acima expõe LoadingFinished como o método no UIWebViewDelegate, mas LoadFinished como o evento para se conectar em um UIWebView:

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

ModelAttribute

Quando você aplica o [Model] atributo a uma definição de tipo em sua API de contrato, o tempo de execução gerará código especial que só exibirá invocações para métodos na classe se o usuário tiver substituído um método na classe. Esse atributo normalmente é aplicado a todas as APIs que encapsulam uma Objective-C classe delegada.

O tempo de execução também gerará uma Objective-C classe que corresponde ao nome do protocolo correspondente.

É possível personalizar o Objective-C nome da classe de duas maneiras:

  1. Configuração AutoGeneratedName = true:

    [Model (AutoGeneratedName = true)]
    

    Isso fará com que o tempo de execução gere um nome exclusivo para o Objective-C tipo. O nome é atualmente baseado no nome do assembly e no nome completo do tipo do modelo (isso pode mudar no futuro).

  2. Especificando explicitamente o nome:

    [Model (Name = "CustomName")]
    

Recomenda-se o uso AutoGeneratedName = truedo . No .NET, o nome é sempre gerado (a menos que seja explicitamente especificado como em 2. acima) e a AutoGeneratedName propriedade não existe mais.

NoDefaultValueAttribute

Especifica que o método no modelo não fornece um valor de retorno padrão.

Isso funciona com o Objective-C tempo de execução respondendo false à solicitação de Objective-C tempo de execução para determinar se o seletor especificado é implementado nessa classe.

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

Veja também: [DefaultValue], [DefaultValueFromArgument]

Protocolos

O Objective-C conceito de protocolo realmente não existe em C#. Os protocolos são semelhantes às interfaces C#, mas diferem em que nem todos os métodos e propriedades declarados em um protocolo devem ser implementados pela classe que o adota. Em vez disso, alguns dos métodos e propriedades são opcionais.

Alguns protocolos são geralmente usados como classes Model, esses devem ser vinculados usando o [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 do Xamarin.iOS 7.0, uma nova e aprimorada funcionalidade de vinculação de protocolo foi incorporada. Qualquer definição que contenha o [Protocol] atributo realmente gerará três classes de suporte que melhoram muito a maneira como você consome 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);
    }
}

A implementação da classe fornece uma classe abstrata completa que você pode substituir métodos individuais e obter segurança de tipo completo. Mas, devido ao C# não oferecer suporte a várias heranças, há cenários em que você pode exigir uma classe base diferente, mas ainda deseja implementar uma interface.

É aqui que entra a definição de interface gerada. É uma interface que tem todos os métodos necessários do protocolo. Isso permite que os desenvolvedores que desejam implementar seu protocolo simplesmente implementem a interface. O tempo de execução registrará automaticamente o tipo como adotando o protocolo.

Observe que a interface lista apenas os métodos necessários e expõe os métodos opcionais. Isso significa que as classes que adotarem o protocolo obterão verificação de tipo completo para os métodos necessários, mas terão que recorrer à digitação fraca (usando manualmente os atributos Export e combinando a assinatura) para os métodos de protocolo opcionais.

Para tornar conveniente consumir uma API que usa protocolos, a ferramenta de vinculação também produzirá uma classe de método de extensões que expõe todos os métodos opcionais. Isso significa que, enquanto você estiver consumindo uma API, poderá tratar os protocolos como tendo todos os métodos.

Se você quiser usar as definições de protocolo em sua API, será necessário escrever interfaces vazias de esqueleto em sua definição de API. Se você quiser usar o MyProtocol em uma API, será necessário fazer o seguinte:

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

O acima é necessário porque no momento da vinculação o IMyProtocol não existiria, é por isso que você precisa fornecer uma interface vazia.

Adotando interfaces geradas por protocolo

Sempre que você implementar uma das interfaces geradas para os protocolos, assim:

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

A implementação para os métodos de interface necessários é exportada com o nome próprio, portanto, é equivalente a isto:

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

Isso funcionará para todos os membros do protocolo necessários, mas há um caso especial com seletores opcionais a serem observados.

Os membros opcionais do protocolo são tratados de forma idêntica ao usar a classe base:

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

mas ao usar a interface de protocolo é necessário adicionar o [Export]. O IDE irá adicioná-lo via preenchimento automático quando você adicioná-lo começando com a substituição.

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

Há uma pequena diferença de comportamento entre os dois em tempo de execução:

  • Os usuários da classe base (NSUrlSessionDownloadDelegate no exemplo) fornecem todos os seletores obrigatórios e opcionais, retornando valores padrão razoáveis.
  • Os usuários da interface (INSUrlSessionDownloadDelegate no exemplo) só respondem aos seletores exatos fornecidos.

Algumas classes raras podem se comportar de forma diferente aqui. Em quase todos os casos, no entanto, é seguro usar qualquer um.

Entrada de protocolo

Ao vincular tipos existentes Objective-C que foram declarados como adotando um protocolo, convém embutir o protocolo diretamente. Para fazer isso, basta declarar seu protocolo como uma interface sem nenhum [BaseType] atributo e listar o protocolo na lista de interfaces base para sua interface.

Exemplo:

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

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

Definições de membros

Os atributos nesta seção são aplicados a membros individuais de um tipo: propriedades e declarações de método.

AlignAttribute

Usado para especificar o valor de alinhamento para tipos de retorno de propriedade. Determinadas propriedades levam ponteiros para endereços que devem ser alinhados em determinados limites (no Xamarin.iOS, isso acontece, por exemplo, com algumas GLKBaseEffect propriedades que devem ser alinhadas de 16 bytes). Você pode usar essa propriedade para decorar o getter e usar o valor de alinhamento. Isso normalmente é usado com os OpenTK.Vector4 tipos e OpenTK.Matrix4 quando integrado com Objective-C APIs.

Exemplo:

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

AparênciaAtributo

O [Appearance] atributo é limitado ao iOS 5, onde o gerenciador de aparência foi introduzido.

O [Appearance] atributo pode ser aplicado a qualquer método ou propriedade que participe da UIAppearance estrutura. Quando esse atributo é aplicado a um método ou propriedade em uma classe, ele direcionará o gerador de vinculação para criar uma classe de aparência fortemente tipada que é usada para estilizar todas as instâncias dessa classe ou as instâncias que correspondem a determinados critérios.

Exemplo:

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

O acima geraria o seguinte código em 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 os [AutoReleaseAttribute] métodos on e as propriedades para encapsular a invocação do método para o método em um NSAutoReleasePoolarquivo .

Existem Objective-C alguns métodos que retornam valores que são adicionados ao padrão NSAutoReleasePool. Por padrão, eles iriam para o seu thread NSAutoReleasePool, mas como o Xamarin.iOS também mantém uma referência aos seus objetos enquanto o objeto gerenciado viver, talvez você não queira manter uma referência extra no que só será drenado NSAutoReleasePool até que o thread retorne o controle para o próximo thread, ou você volte para o loop principal.

Esse atributo é aplicado, por exemplo, em propriedades pesadas (por exemplo UIImage.FromFile) que retorna objetos que foram adicionados ao padrão NSAutoReleasePool. Sem esse atributo, as imagens seriam mantidas enquanto o thread não retornasse o controle para o loop principal. Uf seu tópico era algum tipo de downloader de fundo que está sempre vivo e esperando por trabalho, as imagens nunca seriam liberadas.

ForcedTypeAttribute

O [ForcedTypeAttribute] é usado para impor a criação de um tipo gerenciado mesmo se o objeto não gerenciado retornado não corresponder ao tipo descrito na definição de associação.

Isso é útil quando o tipo descrito em um cabeçalho não corresponde ao tipo retornado do método nativo, por exemplo, tome a seguinte Objective-C definição de NSURLSession:

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

Ele afirma claramente que retornará uma NSURLSessionDownloadTask instância, mas ainda assim retorna um NSURLSessionTask, que é uma superclasse e, portanto, não conversível em NSURLSessionDownloadTask. Como estamos em um contexto de tipo seguro, isso InvalidCastException acontecerá.

Para cumprir com a descrição do cabeçalho e evitar o InvalidCastException, o [ForcedTypeAttribute] é usado.

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

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

O [ForcedTypeAttribute] também aceita um valor booleano chamado Owns que é false por padrão [ForcedType (owns: true)]. O parâmetro owns é usado para seguir a Política de propriedade para objetos Core Foundation .

O [ForcedTypeAttribute] é válido apenas em parâmetros, propriedades e valor de retorno.

BindAsAttribute

O [BindAsAttribute] permite a vinculação NSNumbere NSValueNSString(enums) em tipos C# mais precisos. O atributo pode ser usado para criar uma API .NET melhor e mais precisa sobre a API nativa.

Você pode decorar métodos (no valor de retorno), parâmetros e propriedades com BindAs. A única restrição é que seu membro não deve estar dentro de uma [Protocol] interface ou [Model] .

Por exemplo:

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

Saída:

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

Internamente faremos as bool?<-NSNumber> e<CGRect ->NSValue conversões.

Os tipos de encapsulamento suportados atualmente são:

  • NSValue
  • NSNumber
  • NSString

NSValue

Os seguintes tipos de dados C# são suportados para serem encapsulados de/para NSValue:

  • CGAffineTransform
  • NSRange
  • CGVector
  • SCNMatrix4
  • CLLocationCoordinate2D
  • SCNVector3
  • SCNVector4
  • CGPoint / Ponto F
  • CGRect / RetânguloF
  • CGSize / SizeF
  • UIEdgeInsets
  • UIOffset
  • MKCoordinateSpan
  • CMTimeRange
  • CMTime
  • CMTimeMapping
  • CATransform3D

NSNumber

Os seguintes tipos de dados C# são suportados para serem encapsulados de/para NSNumber:

  • bool
  • byte
  • double
  • float
  • short
  • INT
  • longo
  • sbyte
  • ushort
  • uint
  • ulong
  • nfloat
  • nint
  • nuint
  • Enumerações

NSString

[BindAs] funciona em conjunto com enums apoiados por uma constante NSString para que você possa criar uma API .NET melhor, por exemplo:

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

Saída:

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

Manipularemos a enum<conversão ->NSString somente se o tipo de enum fornecido para [BindAs] for apoiado por uma constante NSString.

matrizes

[BindAs] também suporta matrizes de qualquer um dos tipos suportados, você pode ter a seguinte definição de API como exemplo:

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

Saída:

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

O rects parâmetro será encapsulado em um NSArray que contém um NSValue para cada CGRect e, em troca, você obterá uma matriz da CAScroll? qual foi criada usando os valores do retornado NSArray contendo NSStrings.

BindAttribute

O [Bind] atributo tem dois usos, um quando aplicado a um método ou declaração de propriedade e outro quando aplicado ao getter ou setter individual em uma propriedade.

Quando usado para um método ou propriedade, o [Bind] efeito do atributo é gerar um método que invoca o seletor especificado. Mas o método gerado resultante não é decorado com o atributo, o [Export] que significa que ele não pode participar da substituição do método. Isso normalmente é usado em combinação com o atributo para implementar Objective-C métodos de [Target] extensão.

Por exemplo:

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

Quando usado em um getter ou setter, o [Bind] atributo é usado para alterar os padrões inferidos pelo gerador de código ao gerar os nomes getter e setter Objective-C selector para uma propriedade. Por padrão, quando você sinaliza uma propriedade com o nome fooBar, o gerador geraria uma fooBar exportação para o getter e setFooBar: para o setter. Em alguns casos, Objective-C não segue essa convenção, geralmente eles mudam o nome getter para ser isFooBar. Você usaria esse atributo para informar o gerador disso.

Por exemplo:

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

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

AsyncAttribute

Disponível apenas no Xamarin.iOS 6.3 e mais recente.

Esse atributo pode ser aplicado a métodos que usam um manipulador de conclusão como seu último argumento.

Você pode usar o [Async] atributo em métodos cujo último argumento é um retorno de chamada. Quando você aplica isso a um método, o gerador de vinculação gerará uma versão desse método com o sufixo Async. Se o retorno de chamada não tiver parâmetros, o valor de retorno será um Task, se o retorno de chamada usar um parâmetro, o resultado será um Task<T>arquivo .

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

O seguinte gerará esse método assíncrono:

Task LoadFileAsync (string file);

Se o retorno de chamada tiver vários parâmetros, você deverá definir o ResultType ou ResultTypeName especificar o nome desejado do tipo gerado que manterá todas as propriedades.

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

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

O seguinte gerará esse método assíncrono, onde FileLoading contém propriedades para acessar e filesbyteCount:

Task<FileLoading> LoadFile (string file);

Se o último parâmetro do retorno de chamada for um NSError, o método gerado Async verificará se o valor não é nulo e, se esse for o caso, o método assíncrono gerado definirá a exceção de tarefa.

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

O acima gera o seguinte método assíncrono:

Task<string> UploadAsync (string file);

E em caso de erro, a Tarefa resultante terá a exceção definida como um NSErrorException que encapsula o .NSError

AsyncAttribute.ResultType

Use essa propriedade para especificar o valor do objeto de retorno Task . Esse parâmetro usa um tipo existente, portanto, ele precisa ser definido em uma de suas definições de api principais.

AsyncAttribute.ResultTypeName

Use essa propriedade para especificar o valor do objeto de retorno Task . Este parâmetro leva o nome do seu nome de tipo desejado, o gerador produzirá uma série de propriedades, uma para cada parâmetro que o retorno de chamada tomar.

AsyncAttribute.MethodName

Use essa propriedade para personalizar o nome dos métodos assíncronos gerados. O padrão é usar o nome do método e acrescentar o texto "Async", você pode usar isso para alterar esse padrão.

DesignatedInitializerAttribute

Quando esse atributo é aplicado a um construtor, ele gerará o mesmo [DesignatedInitializer] na montagem final da plataforma. Isso é para ajudar o IDE a indicar qual construtor deve ser usado em subclasses.

Isso deve mapear para Objective-C/clang uso de __attribute__((objc_designated_initializer)).

DisableZeroCopyAttribute

Esse atributo é aplicado a parâmetros de cadeia de caracteres ou propriedades de cadeia de caracteres e instrui o gerador de código a não usar o empacotamento de cadeia de caracteres de cópia zero para esse parâmetro e, em vez disso, criar uma nova instância NSString a partir da cadeia de caracteres C#. Esse atributo só é necessário em cadeias de caracteres se você instruir o gerador a usar o empacotamento de cadeia de caracteres de cópia zero usando a opção de --zero-copy linha de comando ou definindo o atributo ZeroCopyStringsAttributede nível de assembly .

Isso é necessário nos casos em que a propriedade é declarada como Objective-C sendo uma retain propriedade ou assign em vez de uma copy propriedade. Isso geralmente acontece em bibliotecas de terceiros que foram erroneamente "otimizadas" pelos desenvolvedores. Em geral, ou assignNSString as propriedades estão incorretas, retain uma vez que NSMutableString ou classes derivadas do usuário de NSString podem alterar o conteúdo das cadeias de caracteres sem o conhecimento do código da biblioteca, quebrando sutilmente o aplicativo. Normalmente, isso acontece devido à otimização prematura.

O seguinte mostra duas dessas propriedades em Objective-C:

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

DisposeAttribute

Ao aplicar o [DisposeAttribute] a uma classe, você fornece um trecho de código que será adicionado à Dispose() implementação do método da classe.

Como o Dispose método é gerado automaticamente pela bgen ferramenta, você precisa usar o [Dispose] atributo para injetar algum código na implementação do método gerado Dispose .

Por exemplo:

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

ExportAttribute

O [Export] atributo é usado para sinalizar um método ou propriedade a ser exposto ao Objective-C tempo de execução. Esse atributo é compartilhado entre a ferramenta de vinculação e os tempos de execução reais do Xamarin.iOS e do Xamarin.Mac. Para métodos, o parâmetro é passado textualmente para o código gerado, para propriedades, um getter e setter As exportações são geradas com base na declaração base (consulte a seção no [BindAttribute] para obter informações sobre como alterar o comportamento da ferramenta de vinculação).

Sintaxe:

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

O seletor representa o nome do método ou propriedade subjacente Objective-C que está sendo vinculado.

ExportAttribute.ArgumentSemantic

Atributo de campo

Esse atributo é usado para expor uma variável global C como um campo que é carregado sob demanda e exposto ao código C#. Normalmente, isso é necessário para obter os valores de constantes que são definidos em C ou Objective-C e que podem ser tokens usados em algumas APIs, ou cujos valores são opacos e devem ser usados como estão pelo código do usuário.

Sintaxe:

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

O symbolName é o símbolo C com o qual se vincular. Por padrão, isso será carregado de uma biblioteca cujo nome é inferido do namespace onde o tipo é definido. Se esta não for a biblioteca onde o símbolo é procurado, você deve passar o libraryName parâmetro. Se você estiver vinculando uma biblioteca estática, use __Internal como parâmetro libraryName .

As propriedades geradas são sempre estáticas.

As propriedades sinalizadas com o atributo Field podem ser dos seguintes tipos:

  • NSString
  • NSArray
  • nint / int / long
  • nuint / uint / ulong
  • nfloat / float
  • double
  • CGSize
  • System.IntPtr
  • Enumerações

Setters não são suportados para enums apoiados por constantes NSString, mas eles podem ser vinculados manualmente, se necessário.

Exemplo:

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

InternalAttribute

O [Internal] atributo pode ser aplicado a métodos ou propriedades e tem o efeito de sinalizar o código gerado com a internal palavra-chave C#, tornando o código acessível apenas ao código no assembly gerado. Isso geralmente é usado para ocultar APIs que são de nível muito baixo ou fornecer uma API pública abaixo do ideal que você deseja melhorar ou para APIs que não são suportadas pelo gerador e exigem alguma codificação manual.

Ao criar a associação, você normalmente ocultaria o método ou a propriedade usando esse atributo e forneceria um nome diferente para o método ou a propriedade e, em seguida, no arquivo de suporte complementar do C#, adicionaria um wrapper fortemente tipado que expõe a funcionalidade subjacente.

Por exemplo:

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

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

Então, em seu arquivo de suporte, você pode ter algum código como este:

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

IsThreadStaticAttribute

Esse atributo sinaliza o campo de suporte de uma propriedade a ser anotada com o atributo .NET [ThreadStatic] . Isso será útil se o campo for uma variável estática de thread.

MarshalNativeExceptions (Xamarin.iOS 6.0.6)

Esse atributo fará com que um método ofereça suporte a exceções nativas (Objective-C). Em vez de chamar objc_msgSend diretamente, a invocação passará por um trampolim personalizado que captura exceções ObjectiveC e as transforma em exceções gerenciadas.

Atualmente, apenas algumas objc_msgSend assinaturas são suportadas (você descobrirá se uma assinatura não é suportada quando a vinculação nativa de um aplicativo que usa a associação falhar com um símbolo de xamarin__objc_msgSend ausente), mas mais podem ser adicionados mediante solicitação.

NewAttribute

Esse atributo é aplicado a métodos e propriedades para que o gerador gere a new palavra-chave na frente da declaração.

Ele é usado para evitar avisos do compilador quando o mesmo método ou nome de propriedade é introduzido em uma subclasse que já existia em uma classe base.

NotificationAttribute

Você pode aplicar esse atributo a campos para que o gerador produza uma classe Notifications auxiliar fortemente tipada.

Esse atributo pode ser usado sem argumentos para notificações que não carregam carga útil ou você pode especificar uma que faça referência a System.Type outra interface na definição da API, normalmente com o nome terminando com "EventArgs". O gerador transformará a interface em uma classe que subclasses EventArgs e incluirá todas as propriedades listadas lá. O [Export] atributo deve ser usado na EventArgs classe para listar o nome da chave usada para procurar o Objective-C dicionário para buscar o valor.

Por exemplo:

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

O código acima gerará uma classe MyClass.Notifications aninhada com os seguintes métodos:

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

Os usuários do seu código podem assinar facilmente as notificações postadas no NSDefaultCenter usando um código como este:

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

Ou definir um objeto específico para observar. Se você passar null para objectToObserve este método irá se comportar como seu outro par.

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

O valor retornado de ObserveDidStart pode ser usado para parar facilmente de receber notificações, como esta:

token.Dispose ();

Ou você pode chamar NSNotification.DefaultCenter.RemoveObserver e passar o token. Se a notificação contiver parâmetros, você deverá especificar uma interface auxiliar EventArgs , como esta:

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

O acima gerará uma MyScreenChangedEventArgs classe com as ScreenX propriedades e ScreenY que buscará os dados do dicionário NSNotification.UserInfo usando as chaves ScreenXKey e ScreenYKey , respectivamente, e aplicará as conversões adequadas. O [ProbePresence] atributo é usado para o gerador sondar se a chave estiver definida no UserInfo, em vez de tentar extrair o valor. Isso é usado para casos em que a presença da chave é o valor (normalmente para valores booleanos).

Isso permite que você escreva um código como este:

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

Em alguns casos, não há nenhuma constante associada ao valor repassado no dicionário. A Apple às vezes usa constantes de símbolo público e às vezes usa constantes de cadeia de caracteres. Por padrão, o [Export] atributo em sua classe fornecida EventArgs usará o nome especificado como um símbolo público a ser pesquisado em tempo de execução. Se esse não for o caso e, em vez disso, ele deve ser pesquisado como uma constante de cadeia de caracteres, passe o ArgumentSemantic.Assign valor para o atributo Export.

Novo no Xamarin.iOS 8.4

Às vezes, as notificações começam a vida sem argumentos, então o uso de [Notification] sem argumentos é aceitável. Mas, às vezes, parâmetros para a notificação serão introduzidos. Para oferecer suporte a esse cenário, o atributo pode ser aplicado mais de uma vez.

Se você estiver desenvolvendo uma associação e quiser evitar a quebra do código de usuário existente, você deve ativar uma notificação existente de:

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

Em uma versão que lista o atributo de notificação duas vezes, como esta:

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

NullAllowedAttribute

Quando isso é aplicado a uma propriedade, ele sinaliza a propriedade como permitindo que o valor null seja atribuído a ela. Isso só é válido para tipos de referência.

Quando isso é aplicado a um parâmetro em uma assinatura de método, indica que o parâmetro especificado pode ser nulo e que nenhuma verificação deve ser executada para passar null valores.

Se o tipo de referência não tiver esse atributo, a ferramenta de vinculação gerará uma verificação para o valor que está sendo atribuído antes de passá-lo para Objective-C e gerará uma verificação que lançará um ArgumentNullException se o valor atribuído for null.

Por exemplo:

// In properties

[NullAllowed]
UIImage IconFile { get; set; }

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

OverrideAttribute

Use esse atributo para instruir o gerador de vinculação de que a associação para esse método específico deve ser sinalizada com uma override palavra-chave.

PreSnippetAttribute

Você pode usar esse atributo para injetar algum código a ser inserido depois que os parâmetros de entrada tiverem sido validados, mas antes que o código chame o Objective-C.

Exemplo:

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

PrologueSnippetAttribute

Você pode usar esse atributo para injetar algum código a ser inserido antes que qualquer um dos parâmetros seja validado no método gerado.

Exemplo:

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

PostGetAttribute

Instrui o gerador de vinculação a invocar a propriedade especificada dessa classe para buscar um valor dela.

Essa propriedade normalmente é usada para atualizar o cache que aponta para objetos de referência que mantêm o gráfico de objeto referenciado. Normalmente, ele aparece em código que tem operações como Adicionar/Remover. Esse método é usado para que, depois que os elementos forem adicionados ou removidos, o cache interno seja atualizado para garantir que mantenhamos referências gerenciadas a objetos que estão realmente em uso. Isso é possível porque a ferramenta de vinculação gera um campo de apoio para todos os objetos de referência em uma determinada associação.

Exemplo:

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

Nesse caso, a Dependencies propriedade será invocada após adicionar NSOperation ou remover dependências do objeto, garantindo que tenhamos um gráfico que represente os objetos carregados reais, evitando tanto vazamentos de memória quanto corrupção de memória.

PostSnippetAttribute

Você pode usar esse atributo para injetar algum código-fonte C# a ser inserido depois que o código tiver invocado o método subjacente Objective-C

Exemplo:

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

ProxyAttribute

Esse atributo é aplicado para retornar valores para sinalizá-los como sendo objetos proxy. Algumas Objective-C APIs retornam objetos de proxy que não podem ser diferenciados das associações de usuário. O efeito desse atributo é sinalizar o objeto como sendo um DirectBinding objeto. Para um cenário no Xamarin.Mac, você pode ver a discussão sobre esse bug.

ReleaseAttribute (Xamarin.iOS 6.0)

Isso pode ser aplicado a tipos de retorno para indicar que o gerador deve chamar Release o objeto antes de devolvê-lo. Isso só é necessário quando um método fornece um objeto retido (em oposição a um objeto liberado automaticamente, que é o cenário mais comum)

Exemplo:

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

Além disso, esse atributo é propagado para o código gerado, de modo que o tempo de execução do Xamarin.iOS saiba que deve reter o objeto ao retornar de Objective-C tal função.

SealedAttribute

Instrui o gerador a sinalizar o método gerado como lacrado. Se esse atributo não for especificado, o padrão será gerar um método virtual (um método virtual, um método abstrato ou uma substituição, dependendo de como outros atributos são usados).

StaticAttribute

Quando o [Static] atributo é aplicado a um método ou propriedade, isso gera um método estático ou propriedade. Se esse atributo não for especificado, o gerador produzirá um método ou propriedade de instância.

TransientAttribute

Use esse atributo para sinalizar propriedades cujos valores são transitórios, ou seja, objetos criados temporariamente pelo iOS, mas que não são de longa duração. Quando esse atributo é aplicado a uma propriedade, o gerador não cria um campo de suporte para essa propriedade, o que significa que a classe gerenciada não mantém uma referência ao objeto.

WrapAttribute

No design das associações Xamarin.iOS/Xamarin.Mac, o [Wrap] atributo é usado para encapsular um objeto de tipo fraco com um objeto de tipo forte. Isso entra em jogo principalmente com Objective-C objetos delegados que normalmente são declarados como sendo do tipo id ou NSObject. A convenção usada pelo Xamarin.iOS e Xamarin.Mac é expor esses delegados ou fontes de dados como sendo do tipo NSObject e são nomeados usando a convenção "Fraco" + o nome que está sendo exposto. Uma id delegate propriedade de seria exposta como uma NSObject WeakDelegate { get; set; } propriedade no arquivo de contrato de Objective-C API.

Mas, normalmente, o valor atribuído a esse delegado é de um tipo forte, então exibimos o tipo forte e aplicamos o [Wrap] atributo, isso significa que os usuários podem optar por usar tipos fracos se precisarem de algum controle fino ou se precisarem recorrer a truques de baixo nível, ou podem usar a propriedade fortemente tipada para a maior parte de seu trabalho.

Exemplo:

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

É assim que o usuário usaria a versão fracamente tipada do Delegate:

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

}

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

E é assim que o usuário usaria a versão fortemente tipada, observe que o usuário aproveita o sistema de tipos do C# e está usando a palavra-chave override para declarar sua intenção e não precisa decorar manualmente o método com [Export], já que fizemos esse trabalho na vinculação para o usuário:

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

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

Outro uso do [Wrap] atributo é oferecer suporte a versões fortemente tipadas de métodos. Por exemplo:

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

Quando o atributo é aplicado em um método dentro de um tipo decorado [Wrap] com um [Category] atributo, você precisa incluir This como o primeiro argumento, uma vez que um método de extensão está sendo gerado. Por exemplo:

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

Os membros gerados por [Wrap] não virtual são por padrão, se você precisar de um virtual membro, você pode definir para true o 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] também pode ser usado diretamente em getters e setters de propriedades. Isso permite ter controle total sobre eles e ajustar o código conforme necessário. Por exemplo, considere a seguinte definição de API que usa enums inteligentes:

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

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

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

Definição da interface:

// Property definition.

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

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

Atributos de parâmetro

Esta seção descreve os atributos que você pode aplicar aos parâmetros em uma definição de método, bem como o [NullAttribute] que se aplica a uma propriedade como um todo.

BlockCallback

Esse atributo é aplicado a tipos de parâmetro em declarações de delegação C# para notificar o fichário de que o parâmetro em questão está em conformidade com a convenção de chamada de Objective-C bloco e deve organizá-lo dessa maneira.

Isso normalmente é usado para retornos de chamada que são definidos assim em Objective-C:

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

Veja também: CCallback.

CCallback

Esse atributo é aplicado a tipos de parâmetro em declarações de delegação C# para notificar o fichário de que o parâmetro em questão está em conformidade com a convenção de chamada de ponteiro de função C ABI e deve organizá-lo dessa maneira.

Isso normalmente é usado para retornos de chamada que são definidos assim em Objective-C:

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

Consulte também: BlockCallback.

Parâmetros

Você pode usar o [Params] atributo no último parâmetro de matriz de uma definição de método para que o gerador injete um "params" na definição. Isso permite que a vinculação permita facilmente parâmetros opcionais.

Por exemplo, a seguinte definição:

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

Permite que o seguinte código seja escrito:

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

Isso tem a vantagem adicional de não exigir que os usuários criem uma matriz puramente para passar elementos.

Cadeia de caracteres simples

Você pode usar o [PlainString] atributo na frente dos parâmetros de cadeia de caracteres para instruir o gerador de vinculação a passar a cadeia de caracteres como uma cadeia de caracteres C, em vez de passar o parâmetro como um NSStringarquivo .

A maioria das Objective-C APIs consome NSString parâmetros, mas algumas APIs expõem uma char * API para passar cadeias de caracteres, em vez da NSString variação. Use [PlainString] nesses casos.

Por exemplo, as seguintes Objective-C declarações:

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

Deve ser encadernado assim:

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

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

RetainAttribute

Instrui o gerador a manter uma referência ao parâmetro especificado. O gerador fornecerá o armazenamento de backup para esse campo ou você poderá especificar um nome (o WrapName) para armazenar o valor. Isso é útil para manter uma referência a um objeto gerenciado que é passado como um parâmetro para Objective-C e quando você sabe que Objective-C só manterá essa cópia do objeto. Por exemplo, uma API como SetDisplay (SomeObject) usaria esse atributo, pois é provável que o SetDisplay só pudesse exibir um objeto por vez. Se você precisar controlar mais de um objeto (por exemplo, para uma API semelhante a uma pilha), use o [RetainList] atributo.

Sintaxe:

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

TransientAttribute

Esse atributo é aplicado a parâmetros e só é usado durante a transição de Objective-C para C#. Durante essas transições, os vários Objective-CNSObject parâmetros são encapsulados em uma representação gerenciada do objeto.

O tempo de execução fará uma referência ao objeto nativo e manterá a referência até que a última referência gerenciada ao objeto desapareça e o GC tenha a chance de ser executado.

Em alguns casos, é importante que o tempo de execução do C# não mantenha uma referência ao objeto nativo. Isso às vezes acontece quando o código nativo subjacente anexou um comportamento especial ao ciclo de vida do parâmetro. Por exemplo: o destruidor do parâmetro executará alguma ação de limpeza ou descartará algum recurso precioso.

Esse atributo informa ao tempo de execução que você deseja que o objeto seja descartado, se possível, ao retornar do Objective-C método substituído.

A regra é simples: se o tempo de execução tiver que criar uma nova representação gerenciada a partir do objeto nativo, no final da função, a contagem de retenção para o objeto nativo será descartada e a propriedade Handle do objeto gerenciado será limpa. Isso significa que, se você manteve uma referência ao objeto gerenciado, essa referência se tornará inútil (invocar métodos nele lançará uma exceção).

Se o objeto passado não foi criado, ou se já havia uma representação gerenciada pendente do objeto, o descarte forçado não ocorre.

Atributos da propriedade

NotImplementedAttribute

Esse atributo é usado para dar suporte a um Objective-C idioma em que uma propriedade com um getter é introduzida em uma classe base e uma subclasse mutável introduz um setter.

Como o C# não oferece suporte a esse modelo, a classe base precisa ter o setter e o getter, e uma subclasse pode usar o OverrideAttribute.

Esse atributo é usado apenas em setters de propriedades e é usado para dar suporte ao idioma mutável no Objective-C.

Exemplo:

[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 do Enum

O mapeamento NSString de constantes para valores de enum é uma maneira fácil de criar uma API .NET melhor. It:

  • permite que o autocompletar de código seja mais útil, mostrando apenas os valores corretos para a API;
  • adiciona segurança de tipo, você não pode usar outra NSString constante em um contexto incorreto;
  • permite ocultar algumas constantes, fazendo com que o autocompletar de código mostre uma lista de APIs mais curta sem perder a funcionalidade.

Exemplo:

enum NSRunLoopMode {

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

    [Field ("NSRunLoopCommonModes")]
    Common,

    [Field (null)]
    Other = 1000
}

A partir da definição de ligação acima, o gerador criará o enum si mesmo e também criará um *Extensions tipo estático que inclui métodos de conversão bidirecionais entre os valores de enum e as NSString constantes. Isso significa que as constantes permanecem disponíveis para os desenvolvedores mesmo que não façam parte da API.

Exemplos:

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

Você pode decorar um valor de enum com esse atributo. Isso se tornará a constante sendo retornada se o valor de enum não for conhecido.

Do exemplo acima:

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

Se nenhum valor de enum for decorado, então um NotSupportedException será lançado.

ErrorDomainAttribute

Os códigos de erro são vinculados como valores de enum. Geralmente há um domínio de erro para eles e nem sempre é fácil encontrar qual deles se aplica (ou se existe).

Você pode usar esse atributo para associar o domínio de erro ao próprio enum.

Exemplo:

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

Em seguida, você pode chamar o método GetDomain de extensão para obter a constante de domínio de qualquer erro.

Atributo de campo

Esse é o mesmo [Field] atributo usado para constantes dentro do tipo. Ele também pode ser usado dentro de enums para mapear um valor com uma constante específica.

Um null valor pode ser usado para especificar qual valor de enum deve ser retornado se uma nullNSString constante for especificada.

Do exemplo acima:

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

Se nenhum null valor estiver presente, então um ArgumentNullException testamento será lançado.

Atributos globais

Os atributos globais são aplicados usando o modificador de atributo [assembly:] , como o [LinkWithAttribute] ou podem ser usados em qualquer lugar, como os atributos de disponibilidade.

LinkWithAttribute

Esse é um atributo de nível de assembly que permite que os desenvolvedores especifiquem os sinalizadores de vinculação necessários para reutilizar uma biblioteca acoplada sem forçar o consumidor da biblioteca a configurar manualmente os argumentos gcc_flags e mtouch extra passados para uma biblioteca.

Sintaxe:

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

Esse atributo é aplicado no nível do assembly, por exemplo, isso é o que as ligações CorePlot usam:

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

Quando você usa o [LinkWith] atributo, o especificado libraryName é incorporado ao assembly resultante, permitindo que os usuários enviem uma única DLL que contém as dependências não gerenciadas, bem como os sinalizadores de linha de comando necessários para consumir corretamente a biblioteca do Xamarin.iOS.

Também é possível não fornecer um libraryName, caso em que o LinkWith atributo pode ser usado apenas para especificar sinalizadores de vinculador adicionais:

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

Construtores LinkWithAttribute

Esses construtores permitem que você especifique a biblioteca a ser vinculada e incorporada ao assembly resultante, os destinos com suporte que a biblioteca oferece suporte e quaisquer sinalizadores de biblioteca opcionais necessários para vincular à biblioteca.

Observe que o LinkTarget argumento é inferido pelo Xamarin.iOS e não precisa ser definido.

Exemplos:

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

A ForceLoad propriedade é usada para decidir se o sinalizador de -force_load link é ou não usado para vincular a biblioteca nativa. Por enquanto, isso deve ser sempre verdade.

LinkWithAttribute.Frameworks

Se a biblioteca que está sendo vinculada tiver um requisito rígido em qualquer estrutura (diferente de Foundation e UIKit), você deverá definir a Frameworks propriedade como uma cadeia de caracteres contendo uma lista delimitada por espaço das estruturas de plataforma necessárias. Por exemplo, se você estiver vinculando uma biblioteca que requer CoreGraphics e CoreText, você definiria a Frameworks propriedade como "CoreGraphics CoreText".

LinkWithAttribute.IsCxx

Defina essa propriedade como true se o executável resultante precisar ser compilado usando um compilador C++ em vez do padrão, que é um compilador C. Use isso se a biblioteca que você está vinculando foi escrita em C++.

LinkWithAttribute.LibraryName

O nome da biblioteca não gerenciada a ser agrupada. Este é um arquivo com a extensão ".a" e pode conter código de objeto para várias plataformas (por exemplo, ARM e x86 para o simulador).

Versões anteriores do Xamarin.iOS verificaram a LinkTarget propriedade para determinar a plataforma suportada pela biblioteca, mas isso agora é detectado automaticamente e a LinkTarget propriedade é ignorada.

LinkWithAttribute.LinkerFlags

A LinkerFlags cadeia de caracteres fornece uma maneira para vincular autores para especificar quaisquer sinalizadores de vinculador adicionais necessários ao vincular a biblioteca nativa ao aplicativo.

Por exemplo, se a biblioteca nativa exigir libxml2 e zlib, você definirá a LinkerFlags cadeia de caracteres como "-lxml2 -lz".

LinkWithAttribute.LinkTarget

Versões anteriores do Xamarin.iOS verificaram a LinkTarget propriedade para determinar a plataforma suportada pela biblioteca, mas isso agora é detectado automaticamente e a LinkTarget propriedade é ignorada.

LinkWithAttribute.NeedsGccExceptionHandling

Defina essa propriedade como true se a biblioteca que você está vinculando exigir a biblioteca de Tratamento de Exceções (gcc_eh) do GCC

A SmartLink propriedade deve ser definida como true para permitir que o Xamarin.iOS determine se ForceLoad é necessário ou não.

LinkWithAttribute.WeakFrameworks

A WeakFrameworks propriedade funciona da mesma maneira que a Frameworks propriedade, exceto que, em tempo de link, o -weak_framework especificador é passado para gcc para cada uma das estruturas listadas.

WeakFrameworks possibilita que bibliotecas e aplicativos se vinculem fracamente às estruturas da plataforma para que possam usá-las opcionalmente se estiverem disponíveis, mas não dependam muito delas, o que é útil se sua biblioteca for destinada a adicionar recursos extras em versões mais recentes do iOS. Para obter mais informações sobre vinculação fraca, consulte a documentação da Apple sobre vinculação fraca.

Bons candidatos para links fracos seriam Frameworks como Contas, CoreBluetooth, NewsstandKitCoreImageGLKit, e Twitter já que eles só estão disponíveis no iOS 5.

Atributo AdviceAttribute

Use esse atributo para dar aos desenvolvedores uma dica sobre outras APIs que podem ser mais convenientes para eles usarem. Por exemplo, se você fornecer uma versão fortemente tipada de uma API, poderá usar esse atributo no atributo de tipo fraco para direcionar o desenvolvedor para a API melhor.

As informações desse atributo são mostradas na documentação e ferramentas podem ser desenvolvidas para dar sugestões ao usuário sobre como melhorar

RequiresSuperAttribute

Essa é uma subclasse especializada do [Advice] atributo que pode ser usada para sugerir ao desenvolvedor que a substituição de um método requer uma chamada para o método base (substituído).

Isso corresponde a clang__attribute__((objc_requires_super))

ZeroCopyStringsAttribute

Disponível apenas no Xamarin.iOS 5.4 e mais recente.

Esse atributo instrui o gerador de que a associação para essa biblioteca específica (se aplicada com [assembly:]) ou tipo deve usar o empacotamento rápido de cadeia de caracteres de cópia zero. Esse atributo é equivalente a passar a opção --zero-copy de linha de comando para o gerador.

Ao usar cópia zero para cadeias de caracteres, o gerador usa efetivamente a mesma cadeia de caracteres C# que a cadeia de caracteres que Objective-C consome sem incorrer na criação de um novo NSString objeto e evitando copiar os dados das cadeias de caracteres C# para a Objective-C cadeia de caracteres. A única desvantagem de usar cadeias de caracteres Zero Copy é que você deve garantir que qualquer propriedade de cadeia de caracteres que você encapsular que aconteça para ser sinalizada como retain ou copy tem o [DisableZeroCopy] atributo definido. Isso é necessário porque o identificador para cadeias de caracteres de cópia zero é alocado na pilha e é inválido no retorno da função.

Exemplo:

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

Você também pode aplicar o atributo no nível do assembly e ele será aplicado a todos os tipos do assembly:

[assembly:ZeroCopyStrings]

Dicionários fortemente tipados

Com o Xamarin.iOS 8.0, introduzimos suporte para criar facilmente classes fortemente tipadas que encapsulam NSDictionarieso .

Embora sempre tenha sido possível usar o tipo de dados DictionaryContainer junto com uma API manual, agora é muito mais simples fazer isso. Para obter mais informações, consulte Sobrepondo tipos fortes.

StrongDictionary

Quando esse atributo é aplicado a uma interface, o gerador produzirá uma classe com o mesmo nome da interface que deriva de DictionaryContainer e transformará cada propriedade definida na interface em um getter e setter fortemente tipado para o dicionário.

Isso gera automaticamente uma classe que pode ser instanciada a partir de uma existente NSDictionary ou que foi criada nova.

Esse atributo usa um parâmetro, o nome da classe que contém as chaves usadas para acessar os elementos no dicionário. Por padrão, cada propriedade na interface com o atributo procurará um membro no tipo especificado por um nome com o sufixo "Key".

Por exemplo:

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

No caso acima, a MyOption classe produzirá uma propriedade string para Name que usará a MyOptionKeys.NameKey como a chave no dicionário para recuperar uma cadeia de caracteres. E usará o MyOptionKeys.AgeKey como a chave no dicionário para recuperar um NSNumber que contém um int.

Se você quiser usar uma chave diferente, poderá usar o atributo export na propriedade, por exemplo:

[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 dicionário fortes

Os seguintes tipos de dados são suportados StrongDictionary na definição:

Tipo de interface C# NSDictionary Tipo de armazenamento
bool Boolean armazenados em um NSNumber
Valores de enumeração inteiro armazenado em um NSNumber
int Inteiro de 32 bits armazenado em um NSNumber
uint Inteiro não assinado de 32 bits armazenado em um NSNumber
nint NSInteger armazenados em um NSNumber
nuint NSUInteger armazenados em um NSNumber
long Inteiro de 64 bits armazenado em um NSNumber
float Inteiro de 32 bits armazenado como um NSNumber
double Inteiro de 64 bits armazenado como um NSNumber
NSObject e subclasses NSObject
NSDictionary NSDictionary
string NSString
NSString NSString
C# Array de NSObject NSArray
C# Array de enumerações NSArray contendo NSNumber valores