objective c - Anular el inicializador designado de la superclase
objective-c class (4)
Estoy leyendo un libro que tiene una guía:
"Si una clase declara un inicializador designado que es diferente de su superclase, el inicializador designado de la superclase debe anularse para llamar al nuevo inicializador designado"
Como entiendo esta pauta en otras palabras, si estoy subclasificando mi clase desde su superclase, y mi subclase tiene un inicializador designado que es diferente de des. inicializador de su superclase, luego en mi subclase debo anular el inicializador designado de mi superclase y dentro de él llamar al inicializador designado de mi subclase.
¿Es esto cierto? ¿Tenemos que hacer esto todo el tiempo? Gracias.
Básicamente se trata de decir que si una clase tiene un iniWithSomethingDomething
, entonces se prefiere hacer un
self = [super initWithSomethingSomeThing:......]
en tu propio inicializador
Yo como lo entiendo, si su clase tiene un init designado, quiere anular el supers init para que llame a su init designado.
en su implementación, tipo de cosas así.
hacer su init designado
-(id) initWithName:(NSString *)aName
{
self = [super init];
if (self){
[self setName:aName];
}
return self;
}
luego llámalo al anular las alzas
-(id) init
{
return [self initWithName: @""];
}
¿Es esto cierto? ¿Tenemos que hacer esto todo el tiempo?
Personalmente, lo considero una mala guía. No es lógico implementar el inicializador designado de la superclase (para hacer algo significativo) cuando se ha especificado un inicializador designado más estricto (por ejemplo, uno que introduce un parámetro).
Por ejemplo, -initWithDomain:code:userInfo:
es el inicializador designado de NSError
; ¿Podría [[NSError alloc] init]
devolver un error razonablemente descriptivo?
En todo caso, anule de manera privada el inicializador "eliminado" y trátelo como un error del programador para llamar, pero no pretenda que es aceptable que un cliente use un inicializador que no sea un inicializador designado.
Tenga en cuenta que su clase en algunos casos podrá admitir ambos inicializadores. En ese caso, solo redeclare en los inicializadores designados de su @interface
. Esto es suficiente para documentar un inicializador designado. O eso, o documente un inicializador o un conjunto de inicializadores como inicializadores designados, lo que invalidaría lógicamente los inicializadores designados de cualquier superclase.
Por supuesto, su inicializador debe llamar a uno de los inicializadores designados de la superclase en su inicialización.
Ej.1:
// implicitly adds a designated initializer. -init is still valid:
@interface MONObject : NSObject
- (instancetype)initWithString:(NSString *)pString;
@end
Ej.2:
// redefines the designated initializer. -init is not valid:
@interface MONObject : NSObject
// MONObject''s designated initializer
- (instancetype)initWithString:(NSString *)pString;
@end
Ex.3:
// define all designated initializers:
@interface MONObject : NSObject
// MONObject''s designated initializers:
- (instancetype)init;
- (instancetype)initWithString:(NSString *)pString;
@end
EDITAR
Pregunta aclarada en comentarios.
Cuando simplemente anula un inicializador declarado por la superclase:
¿Es esto cierto? ¿Tenemos que hacer esto todo el tiempo?
A menos que su clase tenga inicialización para realizar, no necesita anular explícitamente el inicializador designado de la superclase.
Su instancia se inicializará para tener memoria cero.
Dado:
@interface MONObject : NSObject
- (instancetype)initWithString:(NSString *)pString;
@property (nonatomic, copy, readwrite) NSString * string;
@end
@implementation MONObject
// if @property string should be initialized to nil, you may omit -[MONObject init]
// otherwise, initialize self here:
- (instancetype)init
{
// call super''s designated initializer:
self = [super init];
// test it:
if (nil == self) return nil;
// init your state
_string = @"(null)";
return self;
}
- (instancetype)initWithString:(NSString *)pString;
{
// call super''s designated initializer:
self = [super init]; // << will not call -[MONObject init]
// test it:
if (nil == self) return nil;
// init your state
_string = pString.copy;
return self;
}
@end
@justin básicamente está en el punto.
Los métodos en Objective-C son heredados. Eso significa que si la superclase tiene un método de inicialización (los inicializadores son solo métodos), y su subclase no la anula, entonces su subclase heredará el método de inicialización de esa superclase. Eso significa que las personas siempre pueden llamar el inicializador de esa superclase a un objeto de su subclase (consecuencia básica de herencia y polimorfismo de subtipo). Pero eso podría no ser lo que esperabas. El inicializador de la superclase podría no hacer toda la inicialización que su clase necesita.
Es por eso que debes anular el inicializador de la superclase. Si no desea que la gente use ese inicializador en un objeto de su clase, debe lanzar una excepción en ese inicializador. De lo contrario, debe anularlo para hacer la inicialización adecuada para su clase.