Clang adiciona uma palavra-chave instancetype
que, até onde posso ver, substitui id
como tipo de retorno em -alloc
e init
.
Existe um benefício em usar em instancetype
vez de id
?
objective-c
instancetype
griotspeak
fonte
fonte
id
foram substituídosinstancetype
, mesmo ainit
partir deNSObject
. Se você deseja tornar seu código compatível com o swift, você deve usarinstancetype
Respostas:
Definitivamente, há um benefício. Quando você usa 'id', você não obtém praticamente nenhuma verificação de tipo. Com o instancetype, o compilador e o IDE sabem que tipo de coisa está sendo retornada e podem verificar melhor seu código e preencher automaticamente melhor.
Use-o apenas onde for mais claro (isto é, um método que está retornando uma instância dessa classe); id ainda é útil.
fonte
alloc
,init
etc. são automaticamente promovidosinstancetype
pelo compilador. Isso não quer dizer que não há benefício; existe, mas não é isso.Sim, há benefícios em usar
instancetype
em todos os casos em que se aplica. Explicarei com mais detalhes, mas deixe-me começar com esta declaração em negrito: Useinstancetype
sempre que apropriado, ou seja, sempre que uma classe retornar uma instância dessa mesma classe.De fato, eis o que a Apple diz agora sobre o assunto:
Com isso fora do caminho, vamos seguir em frente e explicar por que é uma boa ideia.
Primeiro, algumas definições:
Para uma fábrica de classe, você deve sempre usar
instancetype
. O compilador não converte automaticamenteid
parainstancetype
. Esseid
é um objeto genérico. Mas se você o fizer,instancetype
o compilador saberá que tipo de objeto o método retornará.Este não é um problema acadêmico. Por exemplo,
[[NSFileHandle fileHandleWithStandardOutput] writeData:formattedData]
gerará um erro no Mac OS X ( apenas ) Vários métodos denominados 'writeData:' encontrados com resultado, tipo de parâmetro ou atributos incompatíveis . O motivo é que NSFileHandle e NSURLHandle fornecem umwriteData:
. Como[NSFileHandle fileHandleWithStandardOutput]
retorna umid
, o compilador não tem certeza de qual classewriteData:
está sendo chamada.Você precisa contornar isso, usando:
ou:
Obviamente, a melhor solução é declarar
fileHandleWithStandardOutput
como retornando uminstancetype
. Então o elenco ou a tarefa não são necessários.(Observe que no iOS, este exemplo não produzirá um erro, pois apenas
NSFileHandle
fornece umwriteData:
lá. Existem outros exemplos, comolength
, que retorna umCGFloat
deUILayoutSupport
mas umNSUInteger
deNSString
.)Nota : Desde que escrevi isso, os cabeçalhos do macOS foram modificados para retornar um em
NSFileHandle
vez de umid
.Para inicializadores, é mais complicado. Quando você digita isso:
… O compilador fingirá que você digitou isso:
Isso foi necessário para o ARC. Isso é descrito em Tipos de resultados relacionados ao Clang Language Extensions . É por isso que as pessoas lhe dirão que não é necessário usá-lo
instancetype
, embora eu afirme que você deveria. O restante desta resposta lida com isso.Há três vantagens:
Explícito
É verdade que não há benefício técnico em retornar
instancetype
de uminit
. Mas isso ocorre porque o compilador converte automaticamente oid
parainstancetype
. Você está confiando nessa peculiaridade; enquanto você escreve queinit
retorna umid
, o compilador o interpreta como se retornasse uminstancetype
.Eles são equivalentes ao compilador:
Estes não são equivalentes aos seus olhos. Na melhor das hipóteses, você aprenderá a ignorar a diferença e examiná-la. Isso não é algo que você deve aprender a ignorar.
padronizar
Enquanto não há nenhuma diferença com
init
e outros métodos, não é uma diferença assim que você definir uma fábrica de classe.Estes dois não são equivalentes:
Você quer o segundo formulário. Se você está acostumado a digitar
instancetype
como o tipo de retorno de um construtor, sempre acertará.Consistência
Por fim, imagine se você juntar tudo: deseja uma
init
função e também uma fábrica de classes.Se você usar
id
parainit
, você acaba com um código como este:Mas se você usar
instancetype
, você obtém o seguinte:É mais consistente e mais legível. Eles retornam a mesma coisa, e agora isso é óbvio.
Conclusão
A menos que você esteja intencionalmente escrevendo código para compiladores antigos, use-o
instancetype
quando apropriado.Você deve hesitar antes de escrever uma mensagem que retorne
id
. Pergunte a si mesmo: isso está retornando uma instância desta classe? Se sim, é uminstancetype
.Certamente há casos em que você precisa retornar
id
, mas provavelmente usará cominstancetype
muito mais frequência.fonte
instancetype
vsid
realmente não é uma decisão de estilo. As recentes mudanças ao redorinstancetype
realmente deixam claro que devemos usarinstancetype
em lugares como o-init
que queremos dizer 'uma instância da minha classe'As respostas acima são mais que suficientes para explicar esta pergunta. Gostaria apenas de adicionar um exemplo para os leitores entenderem em termos de codificação.
Classe A
Classe B
TestViewController.m
fonte
Você também pode obter detalhes em The Designated Initializer
**
INSTANCETYPE
** Esta palavra-chave pode ser usada apenas para o tipo de retorno, que corresponde ao tipo de retorno do receptor. O método init sempre declara retornar o tipo de instância. Por que não fazer o tipo de retorno Parte para instância de parte, por exemplo? Isso causaria um problema se a classe Party fosse subclassificada. A subclasse herdaria todos os métodos do Party, incluindo o inicializador e seu tipo de retorno. Se uma instância da subclasse recebesse essa mensagem inicializadora, isso seria retornado? Não é um ponteiro para uma instância do Party, mas um ponteiro para uma instância da subclasse. Você pode pensar que isso não tem problema, substituirei o inicializador na subclasse para alterar o tipo de retorno. Mas no Objective-C, você não pode ter dois métodos com o mesmo seletor e diferentes tipos de retorno (ou argumentos). Especificando que um método de inicialização retorne "
EU IRIA
** Antes que o tipo de instância seja introduzido no Objective-C, os inicializadores retornam o id (eye-dee). Este tipo é definido como "um ponteiro para qualquer objeto". (id é muito parecido com void * em C.) Até o momento, os modelos de classe XCode ainda usam id como o tipo de retorno de inicializadores adicionados no código padrão. Ao contrário do tipo de instância, o id pode ser usado como mais do que apenas um tipo de retorno. Você pode declarar variáveis ou parâmetros de método do tipo id quando não tiver certeza de que tipo de objeto a variável acabará apontando. Você pode usar a identificação ao usar a enumeração rápida para iterar em uma matriz de vários tipos de objetos ou desconhecidos. Observe que, como id é indefinido como "um ponteiro para qualquer objeto", você não inclui um * ao declarar uma variável ou parâmetro de objeto desse tipo.
fonte