Вопрос по objective-c – Переопределить метод через категорию ObjC и вызвать реализацию по умолчанию?

47

При использовании категорий вы можете переопределить методы реализации своими собственными, например:

// Base Class 
@interface ClassA : NSObject 
- (NSString *) myMethod;
@end
@implementation ClassA
- (NSString*) myMethod { return @"A"; }
@end

//Category
@interface ClassA (CategoryB) 
- (NSString *) myMethod;
@end
@implementation ClassA (CategoryB)
- (NSString*) myMethod { return @"B"; }
@end

Вызов метода «myMethod» после включения категории категории результат "B".

Какой самый простой способ для реализации категории myMethod в категории вызвать исходный myMethod класса A? Насколько я могу понять, вы должны использовать низкоуровневые вызовы, чтобы получить исходный метод для класса A и вызвать его, но казалось, что синтаксически будет проще сделать это.

Ваш Ответ

4   ответа
37

включающий в себя использование среды выполнения target-c, вы всегда можете использоватьметод метания (вставьте стандартные отказы от ответственности здесь.) Это позволит вам сохранить различные методы как произвольно названные селекторы, а затем поменять их во время выполнения по мере необходимости.

Это не обязательно «хакерский»; путь. Время выполнения Objective C существует по причине. Это то, что делает Objective-C превосходящим другие скомпилированные языки.
Исходя из моего опыта, переходя к погоне, вы хотите использовать JRSwizzle, как упомянуто в приведенной выше ссылке. Это было пуленепробиваемым для меня.
Ссылка на код JRSwizzle:github.com/rentzsch/jrswizzle & # X2026; Я полюбил это, метод swizzling ОЧЕНЬ эффективен, когда вы хотите настроить стороннюю библиотеку так, как вам нравится!
12

найденном в библиотеке разработчика Mac: http://codeshaker.blogspot.com/2012/01/calling-original-overridden-method-from.html

По сути, это то же самое, что и описанный выше метод Swizzling с кратким примером:

#import <objc/runtime.h>

@implementation Test (Logging)

- (NSUInteger)logLength {
    NSUInteger length = [self logLength];
    NSLog(@"Logging: %d", length);
    return length;
}

+ (void)load {
    method_exchangeImplementations(class_getInstanceMethod(self, @selector(length)), class_getInstanceMethod(self, @selector(logLength)));
}

@end
19

comp.lang.objective-C FAQ список: & quot;What if multiple categories implement the same method? Тогда ткань Вселенной, какой мы ее знаем, перестает существовать. На самом деле это не совсем так, но, безусловно, будут возникать некоторые проблемы. Когда категория реализует метод, который уже появился в классе (либо через другую категорию, либо через класс primary @implementation), определение этой категории перезаписывает определение, которое ранее присутствовало. Исходное определение больше не может быть достигнуто кодом Objective-C. Обратите внимание, что если две категории перезаписывают один и тот же метод, то какой из них был загружен последним, «выигрывает», что невозможно предсказать до запуска кода.

developer.apple.com: & quot; Когда категория переопределяет унаследованный метод, метод в категории может, как обычно, вызывать унаследованную реализацию через сообщение super. Однако если категория переопределяет метод, который уже существовал в классе категории, нет способа вызвать исходную реализацию & quot;

я думаю чтоsuper должен разрешить исходный объект. В конце концов, категория очень похожа на подкласс (например, вы можете переопределить методы).
Я, вероятно, не должен говорить, но на всякий случай для будущих читателей: категория на самом деле совсем не похожа на подкласс.super не будет преобразован в «исходный объект».
Я благодарю вас за комментарий, но я ищу, как это можно сделать (потому что я знаю, что это может быть, просто не легко), а не как это невозможно ... Kendall Helmstetter Gelner
Правильно ли переопределить в методе Category, объявленном и реализованном в категории суперкласса?
Да, это действительно не поддерживается языком.
1

ConciseKitвы на самом деле вызываете реализацию по умолчанию & # x2026;weirdly enough.. вызывая вашу реализацию SWIZZLED ..

Вы настроили это в+ (void) loadзвонит+ (BOOL)swizzleMethod:(SEL)originalSelector with:(SEL)anotherSelector in:(Class)klass;т.е.

[$ swizzleMethod:@selector(oldTired:) 
            with:@selector(swizzledHotness:) in:self.class];

и затем в методе swizzled ... предположим, что он возвращается-(id).. вы можете нанести вред, или по какой-либо другой причине, по которой вы черпаете в первую очередь & # x2026; а затем, вместо возврата объекта, илиselfили еще много чего ..

return [self swizzledHotness:yourSwizzledMethodsArgument];

Как объяснено здесь & # x2026;

In this method, it looks like we're calling the same method again, causing and endless recursion. But by the time this line is reached the two method have been swapped. So when we call swizzled_synchronize we're actually calling the original method.

Это выглядит и выглядит странно, но .. это работает. Это позволяет добавлять бесконечные украшения к существующим методам, и при этом «вызывать супер» (на самом деле самостоятельно) и пожинать плоды ручной работы оригинального метода & # x2026; даже без доступа к первоисточнику.

Похожие вопросы