2012-01-27 5 views
8

Я столкнулся с этим кодом в ShareKit, и я не понимаю, что имел в виду автор, используя метод self в методе класса. Существует предупреждение: Несовместимые типы указателей, отправляющие «Класс» в тип параметра id<FBSessionDelegate>. Я хочу очистить эти предупреждения, поэтому я могу видеть те, которые могут пострадать позже. Что я могу сделать, это не нарушит это?Использование метода self в классе

Это является файл SHKFacebook.m и имя класса 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]; 
} 

ответ

13

self может быть использован в качестве метода класса в качестве экземпляра класса полиморфного.

поэтому метод класса new может быть реализован следующим образом:

+ (id)new 
{ 
    return [[self alloc] init]; 
} 

и вернет правильный тип для экземпляра класса, который обменивался сообщения:

франко:

NSArray * a = [NSArray new]; // << a is an NSArray 

ex b:

NSMutableArray * a = [NSMutableArray new]; // << a is an NSMutableArray 

см. Примечание ниже.

Итак, на самом деле вы сталкиваетесь с тем, что в протоколе есть только методы экземпляра, и методы (класса) self для отображения методов экземпляра в протоколе.

Что касается дизайна ... ну, скажем так, я бы не написал это так. Синглтон был бы яснее и правильнее, но мне даже не нравятся одиночки, поэтому я бы не пошел по этому пути.

Предупреждения производится, так как класса экземпляр (что передается) не принимает @protocol заданного параметром delegate. Экземпляр Class не является экземпляром класса. Объявление протокола действительно относится к экземплярам класса. Например, если вы принимаете NSLocking, компилятор ожидает, что вы также будете применять методы класса для каждого метода экземпляра, объявленного в протоколе? Ответ: Никогда. Реализация, с которой вы имеете дело, - это ИМО, один из тех случаев, когда это неправильное использование языка, но это происходит.

Для того, чтобы уточнить терминологию:

"Class экземпляр" является self в методе класса:

+ (void)foo { self; } 

"Экземпляр класса" находится в метод экземпляра self:

- (void)foo { self; } 

На практике -[NSObject conformsToProtocol:] является +[NSObject conformsToProtocol:] и +[NSObject class] всего лишь возвращает self, поэтому при выполнении ошибок нет ошибок.

По-прежнему неясно, почему я получаю предупреждение, если код соответствует указанным вами критериям.

Критериями я описал относится к исполнения, но она отличается от семантики языка - таким образом, компилятор абсолютно правильно на этом.

Для разрешения этой проблемы: Там нет никакого способа, чтобы сообщить компилятору «Мой экземпляр класса Соответствует протоколу», поскольку заявление о принятии относится к экземплярам класса.

У вас есть два основных варианта:

  1. Чистый, правильный подход: использовать экземпляр класса и реализации протокола, как определено.

  2. или напечатанный экземпляр класса к протоколу:

    ID Делегат = (ID) самостоятельно; fbSession = [FBSession sessionForApplication: SHKFacebookKey getSessionProxy: SHKFacebookSessionProxyURL делегат: delegate];

Если вы выбираете # 2, это может помочь определить методы экземпляра протокола использовать методы класса, например, так:

+ (void)protocolMethod { /* do stuff */ } 
- (void)protocolMethod { [self.class protocolMethod]; } 

, что также означает, вам не нужны экземпляры. Это поможет, потому что оно добавит предупреждения, если протокол изменится. Эти предупреждения будут выходить за рамки методов класса, когда вы будете следовать этому соглашению.

Для снижения уровня шума, вы можете также рассмотреть вопрос о создании какой-то способ, чтобы уменьшить приведение типа в одном месте:

+ (id<SomeProtocol>)sharedSomeProtocolDelegate 
{ 
    return (id<SomeProtocol>)self; 
} 

- (id<SomeProtocol>)sharedSomeProtocolDelegate 
{ 
    return [[self class] sharedSomeProtocolDelegate]; 
} 

, то вы можете просто написать:

fbSession = [FBSession sessionForApplication:SHKFacebookKey 
          getSessionProxy:SHKFacebookSessionProxyURL 
            delegate:[self sharedSomeProtocolDelegate]]; 

(обратите внимание, что реализации эти типы на самом деле являются классовыми кластерами, и вы увидите что-то другое в отладчике или напечатано)

+0

Ваше изменение дает понять. Протокол содержит только методы экземпляра, и, кстати, ни один из них не ссылается на приемник. Я все еще не понимаю, почему я получаю предупреждение, если код соответствует указанным вами критериям. – Jim

+0

@ Jim подробно добавлено – justin

Смежные вопросы