Partilhar via


Como o Xamarin.Mac funciona

Na maioria das vezes, o desenvolvedor nunca precisará se preocupar com a "mágica" interna do Xamarin.Mac, no entanto, ter uma compreensão aproximada de como as coisas funcionam nos bastidores ajudará a interpretar a documentação existente com uma lente C# e problemas de depuração quando elas surgirem.

No Xamarin.Mac, um aplicativo conecta dois mundos: há o Objective-C runtime baseado que contém instâncias de classes nativas (NSString, NSApplicationetc.) e há o runtime do C# que contém instâncias de classes gerenciadas (System.String, HttpClientetc.). Entre esses dois mundos, o Xamarin.Mac cria uma ponte bidirecional para que um aplicativo possa chamar métodos (seletores) em Objective-C (como NSApplication.Init) e Objective-C pode chamar os métodos C# do aplicativo novamente (como métodos em um delegado de aplicativo). Em geral, as chamadas para Objective-C são tratadas de forma transparente por meio de P/Invokes e alguns códigos de runtime que o Xamarin fornece.

Expondo classes/métodos C# a Objective-C

No entanto, para Objective-C chamar novamente os objetos C# de um aplicativo, eles precisam ser expostos de uma maneira que Objective-C possa entender. Isso é feito por meio dos Register atributos e Export . Veja o exemplo seguinte:

[Register ("MyClass")]
public class MyClass : NSObject
{
   [Export ("init")]
   public MyClass ()
   {
   }

   [Export ("run")]
   public void Run ()
   {
   }
}

Neste exemplo, o Objective-C runtime agora saberá sobre uma classe chamada MyClass com seletores chamados init e run.

Na maioria dos casos, esse é um detalhe de implementação que o desenvolvedor pode ignorar, pois a maioria dos retornos de chamada recebidos por um aplicativo será por meio de métodos substituídos em base classes (como AppDelegate, Delegates, DataSources) ou em Ações passadas para APIs. Em todos esses casos, Export os atributos não são necessários no código C#.

Runthrough do construtor

Em muitos casos, o desenvolvedor precisará expor a API de construção de classes C# do aplicativo para o Objective-C runtime para que ele possa ser instanciado de locais como quando chamado em arquivos Storyboard ou XIB. Aqui estão os cinco construtores mais comuns usados em aplicativos Xamarin.Mac:

// Called when created from unmanaged code
public CustomView (IntPtr handle) : base (handle)
{
   Initialize ();
}

// Called when created directly from a XIB file
[Export ("initWithCoder:")]
public CustomView (NSCoder coder) : base (coder)
{
   Initialize ();
}

// Called from C# to instance NSView with a Frame (initWithFrame)
public CustomView (CGRect frame) : base (frame)
{
}

// Called from C# to instance NSView without setting the frame (init)
public CustomView () : base ()
{
}

// This is a special case constructor that you call on a derived class when the derived called has an [Export] constructor.
// For example, if you call init on NSString then you don’t want to call init on NSObject.
public CustomView () : base (NSObjectFlag.Empty)
{
}

Em geral, o desenvolvedor deve deixar os IntPtr construtores e NSCoder gerados ao criar alguns tipos, como personalizados NSViews . Se o Xamarin.Mac precisar chamar um desses construtores em resposta a uma solicitação Objective-C de runtime e você a tiver removido, o aplicativo falhará dentro do código nativo e poderá ser difícil descobrir exatamente o problema.

Ciclos e gerenciamento de memória

O gerenciamento de memória no Xamarin.Mac é, em muitos aspectos, muito semelhante ao Xamarin.iOS. Também é um tópico complexo, um além do escopo deste documento. Leia as Práticas Recomendadas de Memória e Desempenho.

Compilação antecipada

Normalmente, os aplicativos .NET não são compilados até o código do computador quando são criados, em vez disso, são compilados para uma camada intermediária chamada código IL que obtém JIT ( Just-In-Time ) compilado para o código do computador quando o aplicativo é iniciado.

O tempo necessário para o runtime mono compilar esse código do computador pode retardar a inicialização de um aplicativo Xamarin.Mac em até 20%, pois leva tempo para que o código do computador necessário seja gerado.

Devido às limitações impostas pela Apple no iOS, a compilação JIT do código IL não está disponível para o Xamarin.iOS. Como resultado, todos os aplicativos Xamarin.iOS são AOT ( Ahead-Of-Time ) completos compilados para o código do computador durante o ciclo de build.

Novo no Xamarin.Mac é a capacidade de AOT do código IL durante o ciclo de build do aplicativo, assim como o Xamarin.iOS pode. O Xamarin.Mac usa uma abordagem AOT híbrida que compila a maioria do código do computador necessário, mas permite que o runtime compile as trampolines necessárias e a flexibilidade para continuar a dar suporte a Reflection.Emit (e outros casos de uso que atualmente funcionam no Xamarin.Mac).

Há duas áreas principais em que o AOT pode ajudar um aplicativo Xamarin.Mac:

  • Melhores logs de falha "nativos" – se um aplicativo Xamarin.Mac falhar no código nativo, o que é comum ao fazer chamadas inválidas em APIs cocoa (como enviar um para um null método que não o aceita), os logs de falha nativos com quadros JIT são difíceis de analisar. Como os quadros JIT não têm informações de depuração, haverá várias linhas com deslocamentos hexadecimal e nenhuma pista do que estava acontecendo. O AOT gera quadros nomeados "reais" e os rastreamentos são muito mais fáceis de ler. Isso também significa que o aplicativo Xamarin.Mac interagirá melhor com ferramentas nativas, como lldb e Instruments.
  • Melhor desempenho do tempo de inicialização – para aplicativos Xamarin.Mac grandes, com um tempo de inicialização de vários segundos, a compilação JIT de todo o código pode levar um tempo significativo. O AOT faz esse trabalho antecipadamente.

Habilitando a compilação AOT

O AOT é habilitado no Xamarin.Mac clicando duas vezes no Nome do Projeto no Gerenciador de Soluções, navegando até o Build do Mac e adicionando --aot:[options] ao campo Argumentos mmp adicionais: (em [options] que é uma ou mais opções para controlar o tipo AOT, consulte abaixo). Por exemplo:

Adicionando AOT a argumentos mmp adicionais

Importante

Habilitar a compilação AOT aumenta drasticamente o tempo de build, às vezes até vários minutos, mas pode melhorar os tempos de inicialização do aplicativo em uma média de 20%. Como resultado, a compilação AOT só deve ser habilitada em builds de versão de um aplicativo Xamarin.Mac.

Opções de compilação Aot

Há várias opções diferentes que podem ser ajustadas ao habilitar a compilação AOT em um aplicativo Xamarin.Mac:

  • none - Sem compilação AOT. Essa é a configuração padrão.
  • all – O AOT compila todos os assembly no MonoBundle.
  • core – O AOT compila os Xamarin.Macassemblies e Systemmscorlib .
  • sdk - O AOT compila os Xamarin.Mac assemblies bcl (bibliotecas de classes base) e .
  • |hybrid – Adicionar isso a uma das opções acima permite o AOT híbrido, que permite a remoção de IL, mas resultará em tempos de compilação mais longos.
  • + – Inclui um único arquivo para compilação AOT.
  • - – Remove um único arquivo da compilação AOT.

Por exemplo, --aot:all,-MyAssembly.dll habilitaria a compilação AOT em todos os assemblies no MonoBundle , excetoMyAssembly.dll e --aot:core|hybrid,+MyOtherAssembly.dll,-mscorlib.dll habilitaria híbrido, o código AOT incluiria e MyOtherAssembly.dll excluindo o mscorlib.dll.

Estático parcial registrar

Ao desenvolver um aplicativo Xamarin.Mac, minimizar o tempo entre concluir uma alteração e testá-la pode se tornar importante para cumprir os prazos de desenvolvimento. Estratégias como modularização de bases de código e testes de unidade podem ajudar a diminuir os tempos de compilação, pois reduzem o número de vezes que um aplicativo exigirá uma recompilação completa cara.

Além disso, e novo no Xamarin.Mac, a Partial Static Registrar (como pioneira pelo Xamarin.iOS) pode reduzir drasticamente os tempos de inicialização de um aplicativo Xamarin.Mac na configuração de Depuração . Entender como usar o Partial Static Registrar pode espremer uma melhoria de quase 5x na inicialização de depuração terá um pouco de tela de fundo sobre o que registrar é, qual é a diferença entre estático e dinâmico e o que essa versão "estática parcial" faz.

Sobre o registrar

Nos bastidores de qualquer aplicativo Xamarin.Mac está a estrutura Cocoa da Apple e o Objective-C runtime. A criação de uma ponte entre esse "mundo nativo" e o "mundo gerenciado" do C# é a principal responsabilidade do Xamarin.Mac. Parte dessa tarefa é tratada pelo , que é executado dentro NSApplication.Init () do registrarmétodo . Esse é um dos motivos pelo qual qualquer uso de APIs cocoa no Xamarin.Mac precisa NSApplication.Init ser chamado primeiro.

O registrartrabalho do é informar o Objective-C runtime da existência das classes C# do aplicativo que derivam de classes como NSApplicationDelegate, NSView, NSWindowe NSObject. Isso requer uma verificação de todos os tipos no aplicativo para determinar o que precisa ser registrado e quais elementos em cada tipo relatar.

Essa verificação pode ser feita dinamicamente, na inicialização do aplicativo com reflexão ou estaticamente, como uma etapa de tempo de build. Ao escolher um tipo de registro, o desenvolvedor deve estar ciente do seguinte:

  • O registro estático pode reduzir drasticamente os tempos de inicialização, mas pode reduzir significativamente os tempos de build (normalmente mais do que o tempo de build de depuração dupla). Esse será o padrão para builds de configuração de versão .
  • O registro dinâmico atrasa esse trabalho até que o aplicativo seja iniciado e ignore a geração de código, mas esse trabalho adicional pode criar uma pausa perceptível (pelo menos dois segundos) na inicialização do aplicativo. Isso é especialmente perceptível em builds de configuração de depuração, que usa como padrão o registro dinâmico e cuja reflexão é mais lenta.

O Registro Estático Parcial, introduzido pela primeira vez no Xamarin.iOS 8.13, oferece ao desenvolvedor o melhor de ambas as opções. Ao pré-computar as informações de registro de cada elemento no Xamarin.Mac.dll e enviar essas informações com o Xamarin.Mac em uma biblioteca estática (que só precisa ser vinculada no momento da compilação), a Microsoft removeu a maior parte do tempo de reflexão da dinâmica registrar , não afetando o tempo de build.

Habilitando a estática parcial registrar

O Partial Static Registrar é habilitado no Xamarin.Mac clicando duas vezes no Nome do Projeto no Gerenciador de Soluções, navegando até Mac Build e adicionando --registrar:static ao campo Argumentos mmp adicionais: . Por exemplo:

Adicionando o estático registrar parcial a argumentos mmp adicionais

Recursos adicionais

Aqui estão algumas explicações mais detalhadas de como as coisas funcionam internamente: