2012-01-27 19 views
8

Ho trovato questo codice in ShareKit e non capisco ciò che lo scrittore aveva in mente, usando self in un metodo di classe. C'è un avvertimento: tipi di puntatori incompatibili che inviano "Classe" al tipo di parametro id<FBSessionDelegate>. Voglio ripulire questi avvisi, così posso vedere quelli che potrebbero far male in seguito. Cosa posso/dovrei fare per non romperlo?Utilizzo del metodo self-class

Questo è il file è SHKFacebook.m e il nome della classe è SHKFacebook

+ (void)logout 
{ 
    FBSession *fbSession; 

    if(!SHKFacebookUseSessionProxy){ 
     fbSession = [FBSession sessionForApplication:SHKFacebookKey 
               secret:SHKFacebookSecret 
               delegate:self]; 

    }else { 
     fbSession = [FBSession sessionForApplication:SHKFacebookKey 
             getSessionProxy:SHKFacebookSessionProxyURL 
               delegate:self]; 
    } 

    [fbSession logout]; 
} 

risposta

13

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:

  1. Il pulita, approccio corretto: utilizzare un'istanza della classe e attuare il protocollo come definito.

  2. 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)

+0

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

+0

@Jim aggiunto – justin

Problemi correlati