Clang agrega una palabra clave instancetype
que, por lo que puedo ver, reemplaza id
como un tipo de retorno en -alloc
y init
.
¿Hay algún beneficio en usar en instancetype
lugar de id
?
objective-c
instancetype
griotspeak
fuente
fuente
id
se han reemplazado muchos métodos que solían regresarinstancetype
, inclusoinit
desdeNSObject
. Si desea que su código sea compatible con Swift, debe usarloinstancetype
Respuestas:
Definitivamente hay un beneficio. Cuando usas 'id', básicamente no obtienes ninguna verificación de tipo. Con el tipo de instancia, el compilador y el IDE saben qué tipo de cosas se devuelven, y pueden verificar su código mejor y autocompletar mejor.
Úselo solo donde tenga sentido, por supuesto (es decir, un método que devuelve una instancia de esa clase); Identificación sigue siendo útil.
fuente
alloc
,init
, Etc., están promovidos automáticamenteinstancetype
por el compilador. Eso no quiere decir que no haya beneficio; hay, pero no es esto.Sí, hay beneficios de usar
instancetype
en todos los casos donde se aplica. Explicaré con más detalle, pero permítanme comenzar con esta declaración en negrita: useinstancetype
siempre que sea apropiado, que es cuando una clase devuelve una instancia de esa misma clase.De hecho, esto es lo que Apple dice ahora sobre el tema:
Con eso fuera del camino, sigamos adelante y expliquemos por qué es una buena idea.
Primero, algunas definiciones:
Para una fábrica de clase, siempre debe usar
instancetype
. El compilador no se convierte automáticamenteid
ainstancetype
. Eseid
es un objeto genérico. Pero si lo haces uninstancetype
compilador, sabe qué tipo de objeto devuelve el método.Este no es un problema académico. Por ejemplo,
[[NSFileHandle fileHandleWithStandardOutput] writeData:formattedData]
generará un error en Mac OS X ( solo ) Múltiples métodos llamados 'writeData:' encontrados con resultados no coincidentes, tipo de parámetro o atributos . La razón es que tanto NSFileHandle como NSURLHandle proporcionan awriteData:
. Como[NSFileHandle fileHandleWithStandardOutput]
devuelve unid
, el compilador no está seguro de qué clasewriteData:
se está llamando.Necesita solucionar esto, usando:
o:
Por supuesto, la mejor solución es declarar
fileHandleWithStandardOutput
que devuelve uninstancetype
. Entonces el reparto o la tarea no es necesaria.(Tenga en cuenta que en iOS, este ejemplo no producirá un error, ya que solo
NSFileHandle
proporciona unwriteData:
allí. Existen otros ejemplos, como, por ejemplolength
, que devuelve unCGFloat
deUILayoutSupport
pero unNSUInteger
deNSString
).Nota : desde que escribí esto, los encabezados de macOS se han modificado para devolver un en
NSFileHandle
lugar de unid
.Para los inicializadores, es más complicado. Cuando escribes esto:
... el compilador fingirá que escribiste esto en su lugar:
Esto era necesario para ARC. Esto se describe en Extensiones de lenguaje Clang Tipos de resultados relacionados . Es por eso que la gente le dirá que no es necesario usarlo
instancetype
, aunque yo afirmo que debería hacerlo. El resto de esta respuesta trata de esto.Hay tres ventajas:
Explícito
Es cierto que no hay ningún beneficio técnico al regresar
instancetype
de uninit
. Pero esto se debe a que el compilador convierte automáticamente elid
ainstancetype
. Estás confiando en este capricho; mientras escribe queinit
devuelve unid
, el compilador lo interpreta como si devolviera uninstancetype
.Estos son equivalentes al compilador:
Estos no son equivalentes a tus ojos. En el mejor de los casos, aprenderá a ignorar la diferencia y pasarla por alto. Esto no es algo que debas aprender a ignorar.
Patrón
Si bien no hay ninguna diferencia con
init
otros métodos, no es una diferencia tan pronto como se define un generador de clases.Estos dos no son equivalentes:
Quieres la segunda forma. Si está acostumbrado a escribir
instancetype
como el tipo de retorno de un constructor, siempre lo hará bien.Consistencia
Finalmente, imagina si lo pones todo junto: quieres una
init
función y también una fábrica de clase.Si usas
id
parainit
, terminas con un código como este:Pero si usas
instancetype
, obtienes esto:Es más consistente y más legible. Vuelven lo mismo, y ahora eso es obvio.
Conclusión
A menos que esté escribiendo código intencionalmente para compiladores antiguos, debe usarlo
instancetype
cuando sea apropiado.Debes dudar antes de escribir un mensaje que regrese
id
. Pregúntese: ¿Esto devuelve una instancia de esta clase? Si es así, es uninstancetype
.Ciertamente, hay casos en los que necesita regresar
id
, pero probablemente lo usará coninstancetype
mucha más frecuencia.fuente
instancetype
vsid
realmente no es una decisión de estilo. Los cambios recientesinstancetype
realmente dejan en claro que debemos usarinstancetype
en lugares como-init
donde queremos decir 'una instancia de mi clase'Las respuestas anteriores son más que suficientes para explicar esta pregunta. Solo me gustaría agregar un ejemplo para que los lectores lo entiendan en términos de codificación.
Clase A
Clase B
TestViewController.m
fuente
También puede obtener detalles en The Designated Initializer
** **
TIPO DE INSTANCIA
** Esta palabra clave solo se puede usar para el tipo de retorno, que coincide con el tipo de retorno del receptor. El método init siempre declara devolver el tipo de instancia. ¿Por qué no hacer que el tipo de devolución Party para party, por ejemplo? Eso causaría un problema si la clase Party alguna vez se subclasificara. La subclase heredaría todos los métodos de Party, incluido el inicializador y su tipo de retorno. Si a una instancia de la subclase se le envió este mensaje inicializador, ¿eso sería devuelto? No es un puntero a una instancia de Party, sino un puntero a una instancia de subclase. Puede pensar que no hay problema, anularé el inicializador en la subclase para cambiar el tipo de retorno. Pero en Objective-C, no puede tener dos métodos con el mismo selector y diferentes tipos de retorno (o argumentos). Al especificar que un método de inicialización devuelve "
CARNÉ DE IDENTIDAD
** Antes de que se introdujera el tipo de instancia en Objective-C, los inicializadores devuelven id (eye-dee). Este tipo se define como "un puntero a cualquier objeto". (id es muy parecido a void * en C.) Al momento de escribir esto, las plantillas de clase XCode todavía usan id como el tipo de retorno de inicializadores agregados en el código repetitivo. A diferencia del tipo de instancia, id puede usarse como algo más que un tipo de retorno. Puede declarar variables o parámetros de método de identificación de tipo cuando no está seguro de a qué tipo de objeto la variable terminará apuntando. Puede usar id cuando usa la enumeración rápida para iterar sobre una matriz de tipos de objetos múltiples o desconocidos. Tenga en cuenta que debido a que la identificación no está definida como "un puntero a ningún objeto", no incluye un * al declarar una variable o parámetro de objeto de este tipo.
fuente