2015-03-30 2 views
2

У меня проблема, когда быстрый класс проверяется некоторым кодом Objective-c, я могу получить исходный метод для класса, но всякий раз, когда я устанавливаю элемент, он приводит к метод удаляется из класса.class_replaceMethod в Objective-c не работает над классом Swift

Я предполагаю, что мой IMP не соответствует спецификациям, необходимым для быстрого класса, но я не нашел много способов помочь в Интернете.

Моего простой пример выглядит следующим образом:

+(void)injectPropertyTrapsFor:(NSString*)propName reader:(IMP)r writer:(IMP)w typeEncoding:(const char*)type { 

    IMP oldMethod = class_replaceMethod([self class], NSSelectorFromString(propName), r, [[NSString stringWithFormat:@"%[email protected]:", type] UTF8String]); 
    IMP replacedMethod = class_getClassMethod([self class], NSSelectorFromString(propName)); 

} 

oldMethod не ноль и содержит (в моем случае) класс геттер быстрого для свойства. Но как только я заменил его, последующий вызов для получения метода снова возвращает nil.

Я пропустил методы, используя приведенный ниже код, и он возвращает довольно нормальные свойства propertyName и setPropertyName: как и следовало ожидать.

int unsigned numMethods; 
Method *methods = class_copyMethodList([self class], &numMethods); 
for (int i = 0; i < numMethods; i++) { 
    NSLog(@"%@", NSStringFromSelector(method_getName(methods[i]))); 
} 
free(methods); 

Выход, который производит следующее:

initWithPrimaryKeyValue: 
forename 
setForename: 
surname 
setSurname: 
favoriteColour 
setFavoriteColour: 
.cxx_destruct 
init 

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

Printing description of oldMethod: 
(IMP) oldMethod = 0x000000010d72f440 (DBAccess Test`@objc DBAccess_Test.ViewController.Person.surname.getter : Swift.ImplicitlyUnwrappedOptional<ObjectiveC.NSString> at ViewController.swift) 

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

TLDR Версия: Как перехватить get/set свойств из Objective-c в классе быстрого доступа, к которому у меня нет знаний или доступа к коду?

Edit:

Для справки это стремительная класс:

class Person: DBObject { 

    var forename:NSString! 
    var surname:NSString! 
    var age:Int! 
    var favoriteColour:NSString! 
} 

Благодаря

+0

Предполагая, что ваш код работает с классами Objective C, добавление динамического ключевого слова должно исправить обмен: 'dynamic var forename: ...' –

+0

Спасибо @BrianNickel, к сожалению, та же проблема существует. замена не работает. Я могу подтвердить, что этот код отлично работает с классом obj-c, но не с быстрым (он наследуется от класса Obj-c). –

+0

Хорошо, глядя на это, у меня есть нулевые доказательства, но это похоже на то, что я играю с реализацией методов класса, но свойства - это методы экземпляра, и он просто «всегда» работал раньше в obj-c. Больше от немой удачи, чем приличного кодирования. –

ответ

1

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

static let methodExchange :() = { 

    var sysSEL = #selector(sendAction(_:to:for:)) 
    var systemMethod = class_getInstanceMethod(WHCButton.self, sysSEL) 
    var mySEL = #selector(WHCSendAction(_:to:for:)) 
    var myMethod = class_getInstanceMethod(WHCButton.self, mySEL) 
    var didAddMethod = class_addMethod(WHCButton.self, sysSEL, method_getImplementation(myMethod), method_getTypeEncoding(myMethod)) 
    if didAddMethod == true 
    { 
     class_replaceMethod(WHCButton.self, mySEL, method_getImplementation(systemMethod), method_getTypeEncoding(systemMethod)) 
    } 
    else 
    { 
     method_exchangeImplementations(systemMethod, myMethod) 
    } 
}() 

dynamic func WHCSendAction(_ action: Selector, to target: Any?, for event: UIEvent?) 
{ 
    if (NSDate().timeIntervalSince1970 - self.WHCEventTime) < self.WHCEventInterval 
    { 
     return 
    } 
    if self.WHCEventInterval > 0 
    { 
     self.WHCEventTime = NSDate().timeIntervalSince1970 
    } 
    self.WHCSendAction(action, to: target, for: event) 
} 

private override init(frame: CGRect) 
{ 
    super.init(frame: frame) 
    _ = WHCButton.methodExchange 
} 

Теперь он работает. 1. Самое важное - добавить «динамический» к функции, которую вы хотите обменять. 2. «+ load» и «+ initialize» не могут быть унаследованы сейчас. И «dispatch_once» нельзя использовать сейчас. Вместо этих методов я предлагаю новую альтернативу.

Надеюсь, это поможет вам немного.

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