简体   繁体   中英

performSelector from swift to objc with selector parameter not work

oc code

@implementation TestSelector

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

@end

swift code

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

test: method from TestSelector log nil

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

lldb for sel

(lldb) po sel
collectionView:layout:insetForSectionAtIndex:

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

(lldb) po NSStringFromSelector(sel);
 nil

From Apple

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

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

Sends a message to the receiver with an object as the argument.

Your SEL sel argument is not an object . Internally it's actually a char* pointer. So you can't use

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

this way.

If you'd like to keep using perform(_:with:) you'd have to do some changes in your code. An example workaround would look like this:

In the Objective-C part

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

and in the Swift part:

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

However if would like to keep your original Objective-C code with SEL arg you'd have invoke the selector in Swift using @convention(c) . I covered details of it in my answer here

For your particular case the Swift invocation would look like this:

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)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM