Подкласс класса Objective-C без привязки к суперклассу?

Я пишу подключаемый модуль SIMBL для Spotlight и пытаюсь создать подкласс внутренний тип прожектора. Хотя я могу получить заголовки непосредственно из исполняемого файла, используя class-dump, у меня нет статическая библиотека для компоновки, поэтому компиляция подкласса одного из этих внутренних классов завершается ошибкой (даже несмотря на то, что классы будут доступны во время выполнения). Я следовал инструкциям Майка Эша на подклассы классов во время выполнения, но это довольно неудобно. Есть ли способ создать подкласс класса Objective-C без доступа к суперклассу во время компоновки?


person nate777    schedule 02.11.2014    source источник
comment
NSClassFromString() и objc_allocateClassPair() — ваши друзья. Нет, это будет не так удобно, как делать это во время компиляции.   -  person The Paramagnetic Croissant    schedule 02.11.2014
comment
Ах, увы. Я надеялся, что есть более простой способ...   -  person nate777    schedule 03.11.2014


Ответы (1)


Это вполне возможно, и на самом деле не очень сложно сделать. Вот простой пример с NSValue:

@interface MySubclass : NSObject

-(void) someMethod;

@end

@implementation MySubclass

+(void) load {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated"

    class_setSuperclass(self, NSClassFromString(@"NSValue"));

#pragma clang diagnostic pop
}

-(void) someMethod {
    NSLog(@"%@", [self superclass]);
}

-(const char *) objCType {
    return @encode(int);
}

-(void) getValue:(void *)value {
    if (value) {
        *((int *) value) = 10;
    }
}

@end

int main() {
    MySubclass *theSubclass = [MySubclass new];
    [theSubclass someMethod];

    NSLog(@"%i", [theSubclass isKindOfClass:[NSValue class]]);
}

class_setSuperclass, несмотря на то, что он устарел, все еще имеет реализацию, начиная с OS X 10.10, и его можно выполнить после регистрации класса. Однако я не полностью исследовал последствия изменения надкласса класса после создания экземпляра этого класса, поэтому будьте осторожны, если вы собираетесь делать это в любой момент после +load или +initialize.

Это может затруднить вызов методов в super, но это можно обойти, просто объявив категорию в NSObject (или в любом другом суперклассе, от которого вы решите наследоваться в своей реализации).

person Richard J. Ross III    schedule 23.02.2015