executeSelector от swift до obj c с параметром селектора не работает - PullRequest
0 голосов
/ 26 марта 2020

o c код

@implementation TestSelector

+ (void)test:(SEL)sel {
    NSString *selName = NSStringFromSelector(sel);
    NSLog(@"%@", selName);
}

@end

код swift

let sel = #selector(UICollectionViewDelegateFlowLayout.collectionView(_:layout:insetForSectionAt:))
TestSelector.perform(#selector(TestSelector.test(_:)), with: sel)

test: метод из TestSelector log nil

2020-03-26 16:41:08.764739+0800 TestSelector[30954:774345] (null)

lldb для sel

(lldb) po sel
collectionView:layout:insetForSectionAtIndex:

(lldb) p sel
(SEL) $1 = "\xffffffe8\xffffff96\xffffffbf\xffffff89\xffffffff\x7f"

(lldb) po NSStringFromSelector(sel);
 nil

1 Ответ

1 голос
/ 28 марта 2020

Из Apple

func perform(_ aSelector: Selector!, with object: Any!) -> Unmanaged<AnyObject>!

do c https://developer.apple.com/documentation/objectivec/nsobjectprotocol/1418764-perform

Отправляет получателю сообщение с объектом в качестве аргумента.

Ваш аргумент SEL sel не является объектом . Внутренне это на самом деле char* указатель. Таким образом, вы не можете использовать

TestSelector.perform(#selector(TestSelector.test(_:)), with: sel)

таким образом.

Если вы хотите продолжать использовать perform(_:with:), вам придется внести некоторые изменения в ваш код. Пример обходного пути может выглядеть следующим образом:

В части Objective- C *

@implementation TestSelector
+ (void)test:(NSString*)selectorName {
    NSLog(@"%@", selectorName);
}
@end

и в части Swift:

let sel = #selector(UICollectionViewDelegateFlowLayout.collectionView(_:layout:insetForSectionAt:))
TestSelector.perform(#selector(TestSelector.test(_:)), with: NSStringFromSelector(sel))  

Однако Если вы хотите сохранить свой исходный код Objective- C с SEL, вы можете вызвать селектор в Swift с помощью @convention(c). Я подробно рассказал об этом в своем ответе здесь

Для вашего конкретного случая вызов Swift будет выглядеть так:

let selArg = #selector(UICollectionViewDelegateFlowLayout.collectionView(_:layout:insetForSectionAt:))
let selector = #selector(TestSelector.test(_:))
let methodIMP: IMP! = method_getImplementation(class_getClassMethod(TestSelector.self, selector))
unsafeBitCast(methodIMP,to:(@convention(c)(AnyClass?,Selector,Selector)->Void).self)(TestSelector.self,selector, selArg)
...