self
può essere utilizzato in un metodo di classe come un'istanza di classe polimorfica.
quindi, il metodo della classe new
può essere implementato in questo modo:
+ (id)new
{
return [[self alloc] init];
}
e sarebbe tornato il tipo corretto per l'istanza di classe che è messaged:
es un:
NSArray * a = [NSArray new]; // << a is an NSArray
ex b:
NSMutableArray * a = [NSMutableArray new]; // << a is an NSMutableArray
vedi nota sotto.
Quindi quello che si sta veramente affrontando è garantire che ci siano solo metodi di istanza nel protocollo e che i metodi di sé (Classe) siano mappati per adottare i metodi di istanza nel protocollo.
Per quanto riguarda il design ... beh, diciamo che non l'avrei scritto in questo modo. Un singleton sarebbe stato più chiaro e corretto, ma non mi piacciono nemmeno i singleton, quindi non avrei preso quella strada.
L'avvertimento viene prodotto in quanto il Classe esempio (quello che viene passato) non adotta il @protocol
specificato dal parametro delegate
. L'istanza Class
non è un'istanza della classe. Una dichiarazione di protocollo si applica realmente alle istanze della classe. Ad esempio, se si adotta NSLocking
, il compilatore prevede di implementare anche metodi di classe per ogni metodo di istanza dichiarato nel protocollo? Risposta: mai. L'implementazione che hai a che fare è IMO, uno di quei casi in cui è un uso improprio della lingua, ma capita di funzionare.
Per chiarire la terminologia:
Il "Class
istanza" è self
in un metodo di classe:
+ (void)foo { self; }
"istanza della classe" è self
in un metodo di istanza:
- (void)foo { self; }
In pratica, -[NSObject conformsToProtocol:]
è +[NSObject conformsToProtocol:]
e +[NSObject class]
restituisce solo self
quindi non ci sono errori in fase di esecuzione.
Non sono ancora chiaro, quindi, perché sto ricevendo un avviso, se il codice soddisfa i criteri che hai descritto.
I criteri ho descritto vale per l'esecuzione , ma si discosta dalla semantica del linguaggio - così, il compilatore è assolutamente corretto su questo.
Per una risoluzione al problema: non c'è nessun modo per dire al compilatore "La mia istanza di classe è conforme al protocollo " perché la dichiarazione di adozione si applica al istanze della classe.
si hanno due opzioni principali:
Il pulita, approccio corretto: utilizzare un'istanza della classe e attuare il protocollo come definito.
o Typecast l'istanza di classe al protocollo:
id = delegato (id) stesso; fbSession = [FBSession sessionForApplication: SHKFacebookKey getSessionProxy: SHKFacebookSessionProxyURL delegato: delegate];
Se si sceglie # 2, può aiutare a definire le modalità del protocollo di istanza per utilizzare i metodi della classe, in questo modo:
+ (void)protocolMethod { /* do stuff */ }
- (void)protocolMethod { [self.class protocolMethod]; }
che anche implicare mai bisogno di esempi. Sarebbe utile perché aggiungerà avvertimenti se il protocollo cambierà. Questi avvertimenti diventerebbero dei metodi di classe quando seguirai la convenzione.
Per ridurre il rumore, si può anche prendere in considerazione la creazione di un metodo per ridurre il typecast in un'unica posizione:
+ (id<SomeProtocol>)sharedSomeProtocolDelegate
{
return (id<SomeProtocol>)self;
}
- (id<SomeProtocol>)sharedSomeProtocolDelegate
{
return [[self class] sharedSomeProtocolDelegate];
}
allora si può solo scrivere:
fbSession = [FBSession sessionForApplication:SHKFacebookKey
getSessionProxy:SHKFacebookSessionProxyURL
delegate:[self sharedSomeProtocolDelegate]];
(si noti che le implementazioni di questi tipi sono in realtà cluster di classi e vedrai qualcosa di diverso nel debugger o se stampato)
La tua modifica lo rende chiaro. Il protocollo contiene solo metodi di istanza e nessuno di loro si riferisce al ricevitore, a proposito. Non sono ancora chiaro, quindi, perché sto ricevendo un avviso, se il codice soddisfa i criteri che hai descritto. – Jim
@Jim aggiunto – justin