Perché dovrei chiamare self =

Diciamo che creo la mia class e il suo metodo init . Perché dovrei chiamare e restituire il valore della superclass init assegnata a self? In quali casi copre?

Gradirei gli esempi perché ne avrei bisogno per la superclass e il non-cocoa Cocoa.

Intendi perché?

 self = [super init]; 

piuttosto che

 [super init]; 

Due ragioni:

  1. in fase di inizializzazione, l’errore viene indicato restituendo nil. È necessario sapere se l’inizializzazione dell’object super è fallita.
  2. la super class potrebbe scegliere di sostituire il sé restituito da + alloc con un object diverso. Questo è raro ma accade più frequentemente con i cluster di class .

Modificato in risposta al commento di Michael:

Posso capire perché ho bisogno di salvare e restituire [super init]. Ma è solo convenzione e bell’aspetto che ci fa usare come variabile temporanea per passare il risultato?

N. Le variabili di istanza sono accessibili in relazione al puntatore automatico, quindi nel modo seguente:

 -(id) init { self = [super init]; if (self != nil) { myBoolIvar = YES; // The above is an implicit version of self->myBoolIvar = YES; } return self; } 

il sé deve chiaramente indicare il giusto blocco di memoria, cioè quello che si intende restituire.

L’altro punto è che se super init restituisce un’istanza di class diversa, il resto del codice dopo quella linea potrebbe non avere senso, portare a perdite di memoria e arresti anomali, senza nemmeno parlare dell’istanza creata da quella class.

Questo potrebbe essere un problema. Se ho sottoclassato NSNumber e [super init] ho deciso di restituire un NSString (che potrebbe – non c’è nulla che lo impedisca) che sarebbe chiaramente un disastro. Qualunque super-ritorni da -init deve essere “compatibile” con la sottoclass nel senso di fornire spazio per ivars ed essere ulteriormente sottoclassato o è un bug orrendo (a meno che, ovviamente, il problema non sia documentato). Quindi, in generale, non devi preoccuparti di controllare la class. Tuttavia, leggere la documentazione. Si veda ad esempio la sezione sulla sottoclassi di NSString nei documenti di NSString.

So che è un po ‘tardi per la mia risposta, ma non posso impedirmi di pubblicare un link che ho trovato molto utile per chiarire il mio dubbio su questo problema.

Matt Gallagher: Cosa significa quando assegni [super init] a sé?

EDIT: Come da commenti, ecco i punti essenziali del link

Per capire perché self=[super init]; dobbiamo considerare molti punti. Affrontiamolo uno per uno.

Cos’è il self

Ogni metodo ha due parametri nascosti: self e _cmd . Quindi la chiamata al metodo

 - (id)initWithString:(NSString *)aString 

viene modificato dal compilatore in una chiamata di funzione come questa

 id initWithString(id self, SEL _cmd, NSString *aString); 

Perché abbiamo bisogno di noi stessi?

La realtà è che il compilatore utilizza il parametro self per risolvere qualsiasi riferimento a una variabile di istanza all’interno di un metodo.

Supponiamo di avere un metodo setValueToZero e value è una variabile di istanza della class a cui appartiene, quindi l’implementazione

 - (void)setValueToZero { value = 0; } 

sarà convertito dal compilatore in una funzione come questa

 void setValueToZero(id self, SEL _cmd) { self->value = 0; } 

Il self già un valore quando viene chiamato init ?

Di seguito è riportato un esempio di creazione e inizializzazione di un object tipico.

 [[MyClass alloc] initWithString:@"someString"] 

Qui, nel momento in cui initWithString metodo initWithString , self avrà come object l’object appena assegnato (ovvero il valore restituito da [MyClass alloc] ). In effetti, è quasi garantito il valore finale corretto.

Perché self = [super init]; ?

È perché [super init] è autorizzato a fare una delle tre cose:

  1. Restituisce il proprio ricevitore (il puntatore self non cambia) con i valori di istanza ereditati inizializzati.
  2. Restituisce un object diverso con i valori di istanza ereditati inizializzati.
  3. Restituire nil , indicando un errore.

Nel primo caso, l’assegnazione non ha alcun effetto su di self . Nel terzo caso, l’inizializzazione è fallita, self è impostato su nil e viene restituito.

La ragione dietro l’assegnazione a self è con il secondo caso. Considera quanto segue

 - (id)initWithString:(NSString *)aString { self = [super init]; if (self) { instanceString = [aString retain]; } return self; } 

Vogliamo la conversione da

 instanceString = [aString retain]; 

a

 self->instanceString = [aString retain]; 

agire sul valore corretto e quindi dobbiamo cambiare il valore di self .

Quando [super init] restituisce un object diverso?

In una delle seguenti situazioni

  1. Oggetto Singleton (restituisce sempre il singleton invece di qualsiasi allocazione successiva)
  2. Altri oggetti univoci ( [NSNumber numberWithInteger:0] restituisce sempre l’object “zero” globale)
  3. I cluster di class sostituiscono le sottoclassi private quando si inizializza un’istanza della superclass.
  4. Classi che scelgono di riallocare la stessa class (o compatibile) in base ai parametri passati nell’inizializzatore.

In tutti tranne il caso finale, continuare a inizializzare l’object restituito se cambia è un errore – l’object restituito è già completamente inizializzato e non è più necessario correlato alla class. Quindi un approccio di init migliore sarà il seguente

 - (id)initWithString:(NSString *)aString { id result = [super init]; if (self == result) { instanceString = [aString retain]; } return result; } 

Conclusione

Non è necessario assegnare [super init] a self per far funzionare la maggior parte delle classi. In alcuni casi oscuri, è in realtà la cosa sbagliata da fare.

Allora, perché continuiamo ad assegnarci a self ? È il modello tradizionale per un inizializzatore e, sebbene in alcuni casi sia sbagliato, è giusto in altri casi che sono stati scritti per prevedere questo approccio.

Fondamentalmente ogni class Objective-C è una sottoclass. È o una class che hai specificato o NSObject.

Nella sottoclass (la tua class su cui stai lavorando) chiami self = [super init]

Ciò che sostanzialmente fa è chiamare il metodo init della super class (quelli che ho menzionato sopra) (il costruttore) e lo assegna alla class corrente.

Questo assicura che venga chiamato il metodo di inizializzazione delle superclassi.

Now for If (self) In pratica controlla se il codice di cui sopra funziona.

Questo è fatto per assicurare che se chiami qualche variabile istanza della super class, sarai in grado di farlo.

Nella maggior parte dei casi, l’impostazione di sé per [super init] non fa nulla poiché [super init] si riavvolgerà comunque. Ci sono alcuni casi rari, tuttavia, in cui [super init] restituirà qualcosa di diverso. Può tornare a zero se non riesce a inizializzare la superclass per qualche motivo o può decidere di restituire un object completamente diverso.

fonte


Implementazione di Initializer designato

**

se stesso

** All’interno di un metodo, self è una variabile locale implicita. Non è necessario dichiararlo e viene automaticamente impostato per puntare all’object a cui è stato inviato il messaggio. (Qualcosa di simile nella programmazione Android.) In genere, viene utilizzato self che un object può inviare un messaggio a se stesso. Esempio qui:

  return self; 

**

super

** Quando sostituiamo un metodo, vogliamo mantenere il metodo della superclass e fare in modo che la sottoclass aggiunga qualcosa di nuovo. Per semplificare, c’è una direttiva del compilatore in Objective-C chiamata super. Come funziona super? Di solito quando si invia un messaggio a un object, la ricerca di un metodo con quel nome inizia nella class dell’object. Se non esiste un tale metodo, la ricerca continua nella superclass dell’object. La ricerca continuerà la gerarchia dell’ereditarietà fino a trovare un metodo adatto. (Se raggiunge la cima della gerarchia e non viene trovato alcun metodo, viene generata un’eccezione). Quando inviamo un messaggio a super, stiamo inviando un messaggio a self, ma la ricerca del metodo salta la class dell’object e inizia dalla superclass. Nel caso precedente, inviamo il messaggio init a super. Questo chiama il metodo init di NSObject.

Poiché devi in ​​qualche modo inizializzare l’object, e presumibilmente vuoi fare un’inizializzazione, è necessaria una superclass, dal momento che stai scendendo da essa.