¿Cómo usar NS_DESIGNATED_INITIALIZER y anular init?

Bien, esta es, ciertamente, un poco una pregunta de mejores prácticas, pero quiero hacerlo bien, así que espero que alguien pueda iluminarme:

El escenario es bastante estándar, pero tiene un giro: tengo una class en un marco que escribo que henetworkinga directamente de NSObject . Tiene un inicializador designado con bastantes arguments, la mayoría de los cuales son no nonnull . Dado que la cosa es parte de un marco, uso explícitamente la macro NS_DESIGNATED_INITIALIZER (que no siempre hago en aplicaciones personales más pequeñas). El problema es que esto lleva a que XCode me avise que también anule init , es decir, el inicializador designado de la superclass. Pero, además, exige que llame a mi initalizador designado a partir de él, lo que no puedo hacer, porque simplemente carezco de valores pnetworkingeterminados significativos para sus arguments. Realmente no quiero lanzar una exception en el init "pequeño", preferiría no devolver nil .

Para deshacerte de la advertencia, agregué init como un segundo intérprete designado en la extensión de mi class así:

 @interface MyClassName () // some other stuff not relevant` -(nullable instancetype)init NS_DESIGNATED_INITIALIZER; @end 

Ahora puedo return nil; security sin return nil; en el método de init anulado como lo quería. Eso significa mi documentation (estoy usando appledoc) y, por extensión, la finalización del código de XCode no le dirá a alguien que usa mi marco que init es en realidad también un inicializador designado (para que no lo utilicen accidentalmente), pero todavía está allí En las testings unitarias, por ejemplo, esto podría ser útil).

Mi pregunta es: ¿Hay algún peligro para esto además de que alguien lo esté usando en producción, enviando posts felizmente a cero después sin darse count? ¿Sería este uno de los pocos casos donde sería preferible lanzar una exception en init?

En lugar de simplemente devolver nil desde init (y tal vez agregar un comentario que diga que no debería llamarlo), debe marcarlo como no disponible.

Esto no solo desestimará la advertencia de que no reemplaza el inicializador designado de NSObject , sino que también generará un error de time de compilation si alguien intenta llamar a init lugar de su inicializador designado.

Para hacer esto, puede utilizar la macro NS_UNAVAILABLE , o usar el __attribute__ no disponible como se muestra en esta respuesta . La ventaja de usar __attribute__ es que puede especificar un post que el comstackdor presentará al usuario.

Por ejemplo:

 @interface Foo : NSObject -(instancetype) init __attribute__((unavailable("You cannot create a foo instance through init - please use initWithBar:"))); -(instancetype) initWithBar:(Bar*)bar NS_DESIGNATED_INITIALIZER; @end ... Foo* fooA = [[Foo alloc] init]; // ERROR: 'init' is unavailable: You cannot create a foo instance through init - please use initWithBar: Foo* fooB = [[Foo alloc] initWithBar:[[Bar alloc] init]]; // No error