Visão geral da API Unificada

A API Unificada do Xamarin possibilita compartilhar código entre Mac e iOS e dar suporte a aplicativos de 32 e 64 bits com o mesmo binário. A API Unificada é usada por padrão em novos projetos Xamarin.iOS e Xamarin.Mac.

Importante

A API Clássica do Xamarin, que precedeu a API Unificada, foi preterida.

  • A última versão do Xamarin.iOS para dar suporte à API Clássica (monotouch.dll) foi o Xamarin.iOS 9.10.
  • O Xamarin.Mac ainda dá suporte à API Clássica, mas não é mais atualizada. Como ele foi preterido, os desenvolvedores devem mover seus aplicativos para a API Unificada.

Atualizando aplicativos clássicos baseados em API

Siga as instruções relevantes para sua plataforma:

Dicas para atualizar o código para a API unificada

Independentemente de quais aplicativos você está migrando, marcar essas dicas para ajudá-lo a atualizar com êxito para a API Unificada.

Divisão de biblioteca

Desse ponto em diante, nossas APIs serão exibidas de duas maneiras:

  • API clássica: Limitado a 32 bits (somente) e exposto nos monotouch.dll assemblies e XamMac.dll .
  • API unificada: Suporte ao desenvolvimento de 32 e 64 bits com uma única API disponível nos Xamarin.iOS.dll assemblies e Xamarin.Mac.dll .

Isso significa que, para desenvolvedores corporativos (sem direcionar o App Store), você pode continuar usando as APIs Clássicas existentes, pois continuaremos mantendo-as para sempre ou você pode atualizar para as novas APIs.

Alterações de namespace

Para reduzir o atrito para compartilhar código entre nossos produtos Mac e iOS, estamos alterando os namespaces das APIs nos produtos.

Estamos descartando o prefixo "MonoTouch" do nosso produto iOS e "MonoMac" do nosso produto Mac nos tipos de dados.

Isso simplifica o compartilhamento de código entre as plataformas Mac e iOS sem recorrer à compilação condicional e reduzirá o ruído na parte superior dos arquivos de código-fonte.

  • API clássica: Namespaces usam MonoTouch. ou MonoMac. prefixo.
  • API unificada: Nenhum prefixo de namespace

Padrões de runtime

Por padrão, a API Unificada usa o coletor de lixo SGen e o novo sistema de contagem de referências para acompanhar a propriedade do objeto. Esse mesmo recurso foi portado para o Xamarin.Mac.

Isso resolve uma série de problemas que os desenvolvedores enfrentam com o sistema antigo e também facilitam o gerenciamento de memória.

Observe que é possível habilitar o Novo Refcount mesmo para a API Clássica, mas o padrão é conservador e não exige que os usuários façam alterações. Com a API Unificada, aproveitamos a oportunidade de alterar o padrão e fornecer aos desenvolvedores todas as melhorias ao mesmo tempo que eles refatoram e refaçam seu código.

Alterações de API

A API Unificada remove métodos preteridos e há algumas instâncias em que houve erros de digitação nos nomes de API quando eles foram associados aos namespaces MonoTouch e MonoMac originais nas APIs Clássicas. Essas instâncias foram corrigidas nas novas APIs Unificadas e precisarão ser atualizadas em seus aplicativos de componente, iOS e Mac. Aqui está uma lista das mais comuns que você pode encontrar:

Nome do método da API clássica Nome do método de API unificada
UINavigationController.PushViewControllerAnimated() UINavigationController.PushViewController()
UINavigationController.PopViewControllerAnimated() UINavigationController.PopViewController()
CGContext.SetRGBFillColor() CGContext.SetFillColor()
NetworkReachability.SetCallback() NetworkReachability.SetNotification()
CGContext.SetShadowWithColor CGContext.SetShadow
UIView.StringSize UIKit.UIStringDrawing.StringSize

Para obter uma lista completa das alterações ao alternar do Clássico para a API Unificada, consulte nossa documentação de diferenças de API Clássica (monotouch.dll) vs Unified (Xamarin.iOS.dll ).

Atualizando para Unificado

Várias API antigas/interrompidas/preteridas no clássico não estão disponíveis na API Unificada . Pode ser mais fácil corrigir os CS0616 avisos antes de iniciar a atualização (manual ou automatizada), pois você terá a [Obsolete] mensagem de atributo (parte do aviso) para guiá-lo para a API certa.

Observe que estamos publicando uma comparação das alterações de API clássicas versus unificadas que podem ser usadas antes ou depois das atualizações do projeto. Ainda corrigir as chamadas obsoletas no Clássico geralmente será um tempo de economia (menos pesquisas de documentação).

Siga estas instruções para atualizar aplicativos iOS existentes ou aplicativos Mac para a API Unificada. Examine o restante desta página e estas dicas para obter informações adicionais sobre como migrar seu código.

NuGet

Os pacotes NuGet que anteriormente suportavam o Xamarin.iOS por meio da API Clássica publicavam seus assemblies usando o moniker da plataforma Monotouch10 .

A API Unificada apresenta um novo identificador de plataforma para pacotes compatíveis – Xamarin.iOS10. Os pacotes NuGet existentes precisarão ser atualizados para adicionar suporte a essa plataforma, criando em relação à API Unificada.

Importante

Se você tiver um erro no formato "Erro 3 Não é possível incluir 'monotouch.dll' e 'Xamarin.iOS.dll' no mesmo projeto Xamarin.iOS – 'Xamarin.iOS.dll' é referenciado explicitamente, enquanto 'monotouch.dll' é referenciado por 'xxx, Version=0.0.000, Culture=neutral, PublicKeyToken=null'" depois de converter seu aplicativo para as APIs Unificadas, normalmente é devido a ter um componente ou pacote NuGet no projeto que não foi atualizado para a API Unificada. Você precisará remover o componente/NuGet existente, atualizar para uma versão que dê suporte às APIs Unificadas e fazer um build limpo.

O caminho para 64 bits

Para obter informações sobre como dar suporte a aplicativos de 32 e 64 bits e informações sobre estruturas, consulte as Considerações de plataforma de 32 e 64 bits.

Novos tipos de dados

No centro da diferença, as APIs do Mac e do iOS usam tipos de dados específicos da arquitetura que são sempre de 32 bits em plataformas de 32 bits e de 64 bits em plataformas de 64 bits.

Por exemplo, Objective-C mapeia o NSInteger tipo de dados para int32_t em sistemas de 32 bits e para int64_t em sistemas de 64 bits.

Para corresponder a esse comportamento, em nossa API Unificada, estamos substituindo os usos anteriores de int (que no .NET é definido como sempre sendo System.Int32) para um novo tipo de dados: System.nint. Você pode pensar no "n" como "nativo", portanto, o tipo inteiro nativo da plataforma.

Estamos introduzindo e nuintnfloat fornecendo ninttipos de dados criados com base neles quando necessário.

Para saber mais sobre essas alterações de tipo de dados, consulte o documento Tipos Nativos .

Como detectar a arquitetura de aplicativos iOS

Pode haver situações em que seu aplicativo precisa saber se ele está em execução em um sistema iOS de 32 ou 64 bits. O código a seguir pode ser usado para marcar a arquitetura:

if (IntPtr.Size == 4) {
    Console.WriteLine ("32-bit App");
} else if (IntPtr.Size == 8) {
    Console.WriteLine ("64-bit App");
}

Matrizes e System.Collections.Generic

Como os indexadores C# esperam um tipo de int, você precisará converter nint valores explicitamente para int acessar os elementos em uma coleção ou matriz. Por exemplo:

public List<string> Names = new List<string>();
...

public string GetName(nint index) {
    return Names[(int)index];
}

Esse é o comportamento esperado, pois a conversão de int para nint é perdida em 64 bits, uma conversão implícita não é feita.

Convertendo DateTime em NSDate

Ao usar as APIs Unificadas, a conversão implícita de DateTime em NSDate valores não é mais executada. Esses valores precisarão ser convertidos explicitamente de um tipo para outro. Os seguintes métodos de extensão podem ser usados para automatizar esse processo:

public static DateTime NSDateToDateTime(this NSDate date)
{
    // NSDate has a wider range than DateTime, so clip
    // the converted date to DateTime.Min|MaxValue.
    double secs = date.SecondsSinceReferenceDate;
    if (secs < -63113904000)
        return DateTime.MinValue;
    if (secs > 252423993599)
        return DateTime.MaxValue;
    return (DateTime) date;
}

public static NSDate DateTimeToNSDate(this DateTime date)
{
    if (date.Kind == DateTimeKind.Unspecified)
        date = DateTime.SpecifyKind (date, /* DateTimeKind.Local or DateTimeKind.Utc, this depends on each app */)
    return (NSDate) date;
}

APIs e erros de digitação preteridos

Dentro da API clássica do Xamarin.iOS (monotouch.dll), o [Obsolete] atributo foi usado de duas maneiras diferentes:

  • API do iOS preterida: É quando a Apple sugere que você pare de usar uma API porque ela está sendo substituída por uma mais recente. A API Clássica ainda está correta e geralmente é necessária (se você der suporte à versão mais antiga do iOS). Essa API (e o [Obsolete] atributo) são incluídos nos novos assemblies Xamarin.iOS.
  • API incorreta Algumas APIs tinham erros de digitação em seus nomes.

Para os assemblies originais (monotouch.dll e XamMac.dll), mantivemos o código antigo disponível para compatibilidade, mas eles foram removidos dos assemblies de API Unificada (Xamarin.iOS.dll e Xamarin.Mac)

NSObject subclasses .ctor(IntPtr)

Cada NSObject subclasse tem um construtor que aceita um IntPtr. É assim que podemos instanciar uma nova instância gerenciada de um identificador ObjC nativo.

No clássico, este era um public construtor. No entanto, foi fácil usar indevidamente esse recurso no código do usuário, por exemplo, criando várias instâncias gerenciadas para uma única instância do ObjC ou criando uma instância gerenciada que não teria o estado gerenciado esperado (para subclasses).

Para evitar esse tipo de problema, os IntPtr construtores agora protected estão na API unificada , a serem usados apenas para subclasse. Isso garantirá que a API correta/segura seja usada para criar uma instância gerenciada de identificadores, ou seja,

var label = Runtime.GetNSObject<UILabel> (handle);

Essa API retornará uma instância gerenciada existente (se ela já existir) ou criará uma nova (quando necessário). Ele já está disponível na API clássica e unificada.

Observe que o .ctor(NSObjectFlag) agora também protected é, mas este raramente era usado fora da subclasse.

NSAction substituído por ação

Com as APIs Unificadas, NSAction foi removido em favor do .NET Actionpadrão. Essa é uma grande melhoria porque Action é um tipo .NET comum, enquanto NSAction foi específico do Xamarin.iOS. Ambos fazem exatamente a mesma coisa, mas eram tipos distintos e incompatíveis e resultaram em mais código precisando ser escrito para obter o mesmo resultado.

Por exemplo, se o aplicativo Xamarin existente incluiu o seguinte código:

UITapGestureRecognizer singleTap = new UITapGestureRecognizer (new NSAction (delegate() {
    ShowDropDownAnimated (tblDataView);
}));

Agora ele pode ser substituído por um lambda simples:

UITapGestureRecognizer singleTap = new UITapGestureRecognizer (() => ShowDropDownAnimated(tblDataView));

Anteriormente, isso seria um erro do compilador porque um Action não pode ser atribuído a NSAction, mas como UITapGestureRecognizer agora usa um Action em vez de um NSAction , ele é válido nas APIs Unificadas.

Delegados personalizados substituídos pela Ação<T>

Em unificar alguns delegados .net simples (por exemplo, um parâmetro) foram substituídos Action<T>por . Por ex.:

public delegate void NSNotificationHandler (NSNotification notification);

agora pode ser usado como um Action<NSNotification>. Isso promove a reutilização de código e reduz a duplicação de código dentro do Xamarin.iOS e de seus próprios aplicativos.

Tarefa<bool> substituída por Task<Boolean,NSError>>

No clássico , havia algumas APIs assíncronas retornando Task<bool>. No entanto, alguns deles onde devem ser usados quando um NSError fazia parte da assinatura, ou seja, o booltrue era e você tinha que capturar uma exceção para obter o NSError.

Como alguns erros são muito comuns e o valor retornado não foi útil, esse padrão foi alterado em unificado para retornar um Task<Tuple<Boolean,NSError>>. Isso permite que você marcar o êxito e qualquer erro que possa ter acontecido durante a chamada assíncrona.

NSString vs string

Em alguns casos, algumas constantes tiveram que ser alteradas de string para NSString, por exemplo, UITableViewCell

Clássico

public virtual string ReuseIdentifier { get; }

Unificada

public virtual NSString ReuseIdentifier { get; }

Em geral, preferimos o tipo .NET System.String . No entanto, apesar das diretrizes da Apple, algumas API nativas estão comparando ponteiros constantes (não a cadeia de caracteres em si) e isso só pode funcionar quando expõemos as constantes como NSString.

Objective-C Protocolos

O MonoTouch original não tinha suporte total para protocolos ObjC e algumas API não ideais foram adicionadas para dar suporte ao cenário mais comum. Essa limitação não existe mais, mas, para compatibilidade com versões anteriores, várias APIs são mantidas por dentro monotouch.dll e XamMac.dll.

Essas limitações foram removidas e limpas nas APIs Unificadas. A maioria das alterações terá esta aparência:

Clássico

public virtual AVAssetResourceLoaderDelegate Delegate { get; }

Unificada

public virtual IAVAssetResourceLoaderDelegate Delegate { get; }

O I prefixo significa que a unificação expõe uma interface, em vez de um tipo específico, para o protocolo ObjC. Isso facilitará os casos em que você não deseja subclasse o tipo específico fornecido pelo Xamarin.iOS.

Também permitiu que alguma API fosse mais precisa e fácil de usar, por exemplo:

Clássico

public virtual void SelectionDidChange (NSObject uiTextInput);

Unificada

public virtual void SelectionDidChange (IUITextInput uiTextInput);

Essa API agora é mais fácil para nós, sem se referir à documentação, e a conclusão do código do IDE fornecerá sugestões mais úteis com base no protocolo/interface.

Protocolo NSCoding

Nossa associação original incluía um .ctor(NSCoder) para cada tipo , mesmo que não oferecesse suporte ao NSCoding protocolo. Um único Encode(NSCoder) método estava presente no NSObject para codificar o objeto. Mas esse método só funcionaria se a instância estivesse em conformidade com o protocolo NSCoding.

Na API Unificada, corrigimos isso. Os novos assemblies só terão o .ctor(NSCoder) se o tipo estiver em conformidade com NSCoding. Além disso, esses tipos agora têm um Encode(NSCoder) método que está em conformidade com a INSCoding interface .

Baixo Impacto: na maioria dos casos, essa alteração não afetará os aplicativos, pois os construtores antigos, removidos, não puderam ser usados.

Dicas adicionais

Alterações adicionais a serem consideradas estão listadas nas dicas para atualizar aplicativos para a API Unificada.