Почему этот пример кода на сайте разработчиков Apple объявляет три интерфейса для одного класса? - PullRequest
8 голосов
/ 28 июля 2010

Я погружаюсь в разработку iOS, пытаясь понять Objective-C, и я все еще нахожусь в той фазе, когда, где бы я ни смотрел, я вижу вещи, которые не имеют никакого смысла для такого опытного программиста на Си, как я.В этом примере Game Kit на сайте разработчика Apple один из заголовочных файлов объявляет интерфейс класса три раза ...

@interface SessionManager : NSObject <GKSessionDelegate> {
    NSString *sessionID;
    GKSession *myGKSession;
    NSString *currentConfPeerID;
    NSMutableArray *peerList;
    id lobbyDelegate;
    id gameDelegate;
    ConnectionState sessionState;
}

@property (nonatomic, readonly) NSString *currentConfPeerID;
@property (nonatomic, readonly) NSMutableArray *peerList;
@property (nonatomic, assign) id lobbyDelegate;
@property (nonatomic, assign) id gameDelegate;

- (void) setupSession;
- (void) connect:(NSString *)peerID;
- (BOOL) didAcceptInvitation;
- (void) didDeclineInvitation;
- (void) sendPacket:(NSData*)data ofType:(PacketType)type;
- (void) disconnectCurrentCall;
- (NSString *) displayNameForPeer:(NSString *)peerID;

@end

// Class extension for private methods.
@interface SessionManager ()

- (BOOL) comparePeerID:(NSString*)peerID;
- (BOOL) isReadyToStart;
- (void) voiceChatDidStart;
- (void) destroySession;
- (void) willTerminate:(NSNotification *)notification;
- (void) willResume:(NSNotification *)notification;

@end

@interface SessionManager (VoiceManager) <GKVoiceChatClient>

- (void) setupVoice;

@end

Я вижу, что каждый интерфейс отличается, ноукажите то же имя класса.

  1. В чем причина этого?
  2. Я также заметил такое же поведение в других примерах кода, только вместо объявления нескольких интерфейсов в заголовочном файле вы увидитедополнительный блок @interface объявлен в верхней части файла реализации .m, обычно над блоком @implementation.Почему?

Большое спасибо за вашу мудрость!

Ответы [ 4 ]

9 голосов
/ 28 июля 2010

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

Они используются для группировки методов в куски вместо того, чтобы объединить их все в один большойгроздь.Они также могут быть размещены отдельно от объявления основного класса.Это особенно полезно в файлах .m, где вам может потребоваться создать служебные методы для вашего класса, но вы не хотите, чтобы они были видны другим объектам по какой-либо причине (поэтому вы не помещаете их в .h, которыйимпортируется другими классами).Другое распространенное использование - это группировка методов, которые соответствуют определенной логической категории , неформальному протоколу или тому, что у вас есть.Категории могут быть названы (@interface MyClass (MyCategory)) или анонимными (@interface MyClass ()).Последний обычно используется для общих закрытых методов в вашем заголовке.

(Причина, по которой вам нужны категории для объявления закрытых методов в вашем .m, заключается в том, что компилятор знает о методах - в противном случае вы получите предупреждениекогда вы пытаетесь вызвать такой метод.)

Кроме того, вы можете использовать категории для добавления методов в существующие классы.Например, UIKit содержит категорию на NSString, которая называется NSString (UIStringDrawing).Или, если вы хотите создать свой собственный:

@interface NSString (MyFoo)
+ (NSString *)fooString;
@end
//... somewhere else...
@implementation NSString (MyFoo)
+ (NSString *)fooString { return @"foo!"; }
@end

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

4 голосов
/ 28 июля 2010

Это не определение интерфейса 3 раза - есть только один интерфейс.

вы видите категории, которые добавляют методы к классу

Существует базовый интерфейс, который определяетатрибуты и некоторые методы - есть только один из этих муравьев, он определяет, как объект хранится в памяти, и является единственным, который необходим.

Objective C ищет методы во время выполнения.Эти методы не нужно искать во время компиляции и, следовательно, их не нужно объявлять в заголовках / интерфейсах и т. Д. Если они не объявлены и вы вызываете их из кода, вы получите предупреждения о времени компиляции.

Inв этом случае одна категория с пустым именем используется для частных функций.Обычно я помещаю этот интерфейс только в файл .m класса, поэтому он не виден другому коду, как не в заголовке.

Вторая категория - добавить методы, чтобы SessionManager соответствовал протоколу GKVoiceChatClient.Обычной причиной для этого является группировка кода, охватывающего определенное поведение.

Другая причина использования категорий - это добавление методов в существующий класс, такой как NSString, - вы можете создавать свои собственные методы добавления категорий без разделения на классы.как и во многих других языках ОО, включая Java и C ++

1 голос
/ 28 июля 2010

По порядку:

Первое объявление интерфейса - это фактическое объявление интерфейса, которое объявляет класс как подкласс NSObject и реализующий протокол GKSessionDelegate.Он также объявляет переменные экземпляра и выбор методов.

Второе объявление интерфейса является расширением класса.Это можно рассматривать как своего рода анонимную категорию.Поэтому мы пока пропустим его и вернемся к нему.

Третий интерфейс - это объявление категории.Категории позволяют делать две вещи.Они позволяют разделить реализацию класса на несколько исходных файлов.В приведенном выше примере у вас будет

@implementation SessionManager

// methods declared in the first @interface

@end

@implementation SessionManager(VoiceManager)

// methods declared in the third @interface

@end

Два @implementations не обязательно должны находиться в одном исходном файле.

Еще одна вещь, которую может сделать категория, - это позволить вам расширить уже существующиеclasses.eg @interface NSString(MyStringMethods)...

Возвращаясь к расширению класса, это немного похоже на анонимную категорию.Реализации объявленных в нем методов должны находиться в основном блоке @implementation.Цель расширения класса - позволить вам объявить закрытый API отдельно от заголовочного файла класса.Я обычно помещаю один в файл .m вверху, если у меня есть методы, которые должны использоваться только из класса.Хотя обратите внимание, что это только ограничение времени компиляции.Ничто не мешает отправке сообщения расширения класса кем-либо во время выполнения.

1 голос
/ 28 июля 2010

Это для целей поддержки кода, я верю ... легче просматривать различные помеченные интерфейсы, например (VoiceManager), который предназначен для настройки голосового менеджера и методов, связанных с этим, и у вас есть один интерфейс, связанный сМетоды делегирования GK и любое взаимодействие с gamekit будет ... в отличие от просмотра одного огромного файла интерфейса и необходимости выбирать то, что вы ищете ... Они также могут разделить реализации таким же образом, чтобы было прощепросматривать и перемещаться.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...