Использование self в методе класса

Я наткнулся на этот код в ShareKit, и я не понимаю, что имел в виду автор, используя self в методе класса. Есть предупреждение: несовместимые типы указателей отправляют "класс" в тип параметра id<FBSessionDelegate>, Я хочу убрать эти предупреждения, чтобы видеть те, которые могут пострадать позже. Что я могу / должен сделать, чтобы это не сломалось?

Это файл 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];
}

1 ответ

Решение

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

следовательно, метод класса new может быть реализовано так:

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

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

пример:

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

пример б:

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

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

Итак, с чем вы действительно сталкиваетесь, так это с гарантией того, что в протоколе присутствуют только методы экземпляра, и что методы (Class) self планируют использовать методы экземпляра в протоколе.

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

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

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

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

+ (void)foo { self; }

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

- (void)foo { self; }

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

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

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

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

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

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

  2. или введите тип класса в протокол:

    идентификатор делегата = (идентификатор) себя; fbSession = [FBSession sessionForApplication:SHKFacebookKey getSessionProxy:SHKFacebookSessionProxyURL делегат: делегат];

Если вы выберете #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]];

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

Другие вопросы по тегам