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:
- Atualizar aplicativos existentes
- Atualizar aplicativos iOS existentes
- Atualizar aplicativos Mac existentes
- Atualizar aplicativos Xamarin.Forms existentes
- Migrar uma associação para a API unificada
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 eXamMac.dll
. - API unificada: Suporte ao desenvolvimento de 32 e 64 bits com uma única API disponível nos
Xamarin.iOS.dll
assemblies eXamarin.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.
ouMonoMac.
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 nuint
nfloat
fornecendo nint
tipos 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 Action
padrã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 bool
já true
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.