2015-02-19 5 views
0

Представьте меня определить класс MyClass следующим образом:Необъявленные Методы против Категории в Objective-C

Файл интерфейса класса:

#import <Foundation/Foundation.h> 

@interface MyClass : NSObject 

@property (nonatomic) NSString *myProperty; 

- (void)myPublicMethod; 

@end 

Файл реализации класса с использованием категорий:

#import "MyClass.h" 

@interface MyClass (MyCategory) 

- (void)myPrivateMethod; 

@end 

@implementation MyClass 

- (void)myPublicMethod { 
    NSLog(@"myPublicMethod was called!"); 
    [self myPrivateMethod]; 
} 

- (void)myPrivateMethod { 
    NSLog(@"myPrivateMethod was called!"); 
} 

@end 

Файл реализации альтернативного класса НЕ с использованием категорий:

#import "MyClass.h" 

@ implementation MyClass 

- (void)myPublicMethod { 
    NSLog(@"myPublicMethod was called!"); 
    [self myPrivateMethod]; 

} 

- (void)myPrivateMethod { 
    NSLog(@"myPrivateMethod was called!"); 
} 

@end 

Хотел, чтобы кто-то мог объяснить разницу между двумя подходами к файлу реализации.

В случае, если использование категорий означает, что «частные» методы унаследованы любыми подклассами MyClass и не используют категории, означает, что «частные» методы - это , а не, унаследованные любыми подклассами?

+0

нет разница. (если вы не играете с низкоуровневым ObjC api, который все еще может не иметь разницы) –

+0

Если я подкласс MyClass, где MySubclass является подклассом MyClass. Интересно, что MySubclass не может напрямую ссылаться на myPrivateMethod MyClass независимо от того, использует ли MyClass категории или нет. Это имеет смысл, я думаю, поскольку публичный интерфейс MyClass объявляет только один метод myPublicMethod. – Steve

ответ

1

Все методы, которые существуют в классе, всегда наследуются и могут быть вызваны кем-либо независимо от того, как вы их объявляете. Главное отличие в том, знает ли кто-нибудь о них. Также существовала историческая потребность объявлять вещи перед использованием, что приводит к внутренним декларациям вперед в старом и старомодном коде.


Категория используется для добавления методов в существующий класс. Обычно используется расширение одного из существующих классов. Например, вы могли бы реализовать:

@interface NSURL (HTTPQueryParameters) 

- (NSDictionary *)httpQueryParameters; 

@end 

Так что с тех пор вы дали NSURL себе знание, необходимое для разбора HTTP параметров запроса протокола. Часто правильный факторинг позволяет добавлять функциональные возможности непосредственно к классам, для которых у вас нет источника.

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

В настоящее время методы Objective-C могут вызывать любой метод, который определен в любом месте блока компиляции, включая впоследствии в том же исходном файле. Поэтому теперь нормально не собирать ваши неопубликованные методы в категорию или расширение только в интересах компилятора.

Это оставляет категории для:

  • добавления функциональных возможностей существующих классов; и
  • сегментирование ваших классов, если они становятся очень большими;

расширения класса в настоящее время в первую очередь для:

  • объявляя @property сек без их публикации.

В Objective-C любой вызов метода может быть послан к любому объекту - объекты динамически типизированных. Таким образом, таблица отображения в памяти во время выполнения для каждого класса от имени метода до реализации. Процесс поиска - это увидеть, реализуется ли метод в классе, отправленном в. Если нет, то отправьте в суперкласс. Исключение будет поднято, если время выполнения закончится суперклассами.

+0

Человек, я забыл, что заявление/порядок использования имеет значение! Это очень хороший момент. «Любое сообщение может быть отправлено любому объекту» с единственным ограничением, которое ARC должно было видеть в каком-то методе _ с этим именем_ где-то или оно будет выходить из строя. –

+0

@JoshCaswell вы все еще можете захватить 'IMP' через runtime или через' + [NSObject instanceMethodForSelector] ', отбросить его до правильных аргументов числа и формата, а затем называть его стилем C. ARC будет делать правильные вещи с аргументами. – Tommy

+0

@Tommy Мой предыдущий комментарий (от игры с Xcode) противоречит вашему комментарию: «Все методы, которые существуют в классе, всегда унаследованы и могут быть вызваны кем угодно, независимо от того, как вы их объявляете». – Steve

0

Объявление метода в категории @interface служит только для того, чтобы разоблачить метод для пользователей этого класса, в том числе - как вы упомянули в ваших подклассах комментариев.

(Было бы гораздо обычнее использовать расширение класса (иногда называемое «анонимной категорией») объявить метод, который вы определяете в основном блоке реализации. На самом деле, я не уверен на 100%, что взаимодействие между объявлением вашей категории и определением основного блока - я бы не удивился, если бы он не скомпилировался, но это так.)

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

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

  • Нет связанных вопросов^_^