ios objective-c xcode initialization xcode6

Inicializadores designados iOS: utilizando NS_DESIGNATED_INITIALIZER



objective-c xcode (3)

Tenemos esta nueva macro introducida en XCode 6: NS_DESIGNATED_INITIALIZER

Busqué en la red, pero no pude encontrar ninguna buena documentación sobre cómo usar esto.

Sintácticamente, podemos usarlo como:

- (instancetype)initWithCoder:(NSCoder *)coder NS_DESIGNATED_INITIALIZER;

Pero, ¿cuáles son las posibles ventajas de marcar un inicializador con esta macro y también cuáles son las cosas que deberíamos considerar al usar esto?

Estoy principalmente interesado en los casos de uso de esta macro. Cualquier enlace / documentación sería apreciado.


El uso de NS_DESIGNATED_INITIALIZER está muy bien explicado en http://useyourloaf.com/blog/2014/08/19/xcode-6-objective-c-modernization.html :

El inicializador designado garantiza que el objeto esté completamente inicializado al enviar un mensaje de inicialización a la superclase. El detalle de implementación se vuelve importante para un usuario de la clase cuando lo subclase. Las reglas para los inicializadores designados en detalle:

  • Un inicializador designado debe llamar (a través de super) un inicializador designado de la superclase. Donde NSObject es la superclase, esto es solo [superinicio].
  • Cualquier iniciador de conveniencia debe llamar a otro inicializador de la clase, lo que finalmente conduce a un inicializador designado.
  • Una clase con inicializadores designados debe implementar todos los inicializadores designados de la superclase.

Como ejemplo, si su interfaz es

@interface MyClass : NSObject @property(copy, nonatomic) NSString *name; -(instancetype)initWithName:(NSString *)name NS_DESIGNATED_INITIALIZER; -(instancetype)init; @end

a continuación, el compilador comprueba si el iniciador (de conveniencia) init llama al inicializador (designado) initWithName: , por lo que esto provocaría una advertencia:

-(instancetype)init { self = [super init]; return self; }

y esto estaría bien:

-(instancetype)init { self = [self initWithName:@""]; return self; }

En Swift, las reglas sobre inicializadores designados y convenientes son aún más estrictas, y si mezcla el código Objective-C y Swift, marcar los inicializadores designados de Objective-C ayuda al compilador a aplicar las reglas.

Por ejemplo, esta subclase Swift causaría un error de compilación:

class SwClass: MyClass { var foo : String init(foo : String) { self.foo = foo super.init() } }

y esto estaría bien:

class SwClass: MyClass { var foo : String init(foo : String) { self.foo = foo super.init(name: "") } }


Los inicializadores designados definen cómo estructuramos nuestros inicializadores al crear subclases; son el "inicializador canónico" para su clase. Garantizó ser confiable independientemente del inicializador designado en la cadena de superclase que usted llame, y siempre irá desde el ancestro más lejano hasta el descendiente más lejano.

Un inicializador designado no define qué inicializador debe usar al crear un objeto. Está muy explicado en https://blog.twitter.com/2014/how-to-objective-c-initializer-patterns .


Mi forma más común de hacer esto:

@interface Person : NSObject - (nullable instancetype)initWithName:(nonnull NSString *)name NS_DESIGNATED_INITIALIZER; - (nullable instancetype)init NS_UNAVAILABLE; @property (nonatomic, nonnull) NSString *name; @end

E implementación

@implementation Person - (instancetype)initWithName:(NSString *)name { self = [super init]; if (self) { self.name = name; } return self; } @end

En este caso, no debe anular NS_DESIGNATED_INITIALIZER de su método de superclase ( init: NSObject init: en este caso) - usamos NS_UNAVAILABLE para marcar este método como innecesario. O puede anularlo para llamar a su inicializador designado con los parámetros predeterminados.