Trouble passing Swift 4 String to Obj-C++ -[_SwiftValue dataUsingEncoding:]: unrecognized selector sent to instance

ぐ巨炮叔叔 提交于 2019-12-10 10:16:28

问题


I have some Objective-C++ code like this:

// header

@interface MyObjcClass

- (void) myMethod: (NSString *) text;

@end


// implementation

@implementation MyObjcClass

- (void) myMethod: (NSString *) text
{
    someInternalObject->useWstring(nsStringToWstring(text))
}

std::wstring nsStringToWstring(const NSString * text)
{
    NSData * data = [text dataUsingEncoding: NSUTF32LittleEndianStringEncoding];

    // and then some other stuff irrelevant to this question

    return std::wstring(pointerToNewString, pointerToNewString + stringLength);
}

@end

Straightforward so far; seems fine to me. And works great when called from Objective-C and Objective-C++ code! However, when Swift gets involved...

func mySwiftFunc(text: String) {
    myObjcClassInstance.myMethod(text)
}

This also seems straightforward. The compiler's translation layer automatically bridge's Swift's String to Objective-C++'s NSString *. Unfortunately, that's false... it seems to bridge it to something called _SwiftValue. And then that's passed in and I try to call dataUsingEncoding: on it, but apparently _SwiftValue doesn't have such a selector, so I get this crash:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[_SwiftValue dataUsingEncoding:]: unrecognized selector sent to instance 0x7f9ca7d63ee0'

I'm at a loss for how to resolve this. I can't use NSString in Swift and just pass that down because the compiler requires that I pass a Swift String.

Is there any way to resolve this?

Any of these solutions will do:

  • Force generated Swift header to accept a NSString * instead of a String
  • A way to turn a _SwiftValue into data from within Objective-C++
  • Any flags that let the compiler or runtime know to translate that _SwiftValue to a NSString * before trying to message it
  • etc.

Environment

  • The ObjC++ code is within a modular framework that is referenced by the Swift code; they're not compiled together.
  • The ObjC++ module is compiled with Xcode 8.3.3 and the Swift code with 9.2.
  • There may be other discrepancies; there are lots of moving parts in these projects.

回答1:


I'd try

func mySwiftFunc(text: String) {
     myObjcClassInstance.perform(#selector(NSSelectorFromString("myMethod:"), with: text as NSString)
}

If that won't work try:

func mySwiftFunc(text: String) {
    let selector : Selector = NSSelectorFromString("myMethod:")
    let methodIMP : IMP! = myObjcClassInstance.method(for: selector)
    unsafeBitCast(methodIMP,to:(@convention(c)(Any?,Selector,NSString)->Void).self)(myObjcClassInstance,selector,text as NSString)
}

Probably possible without selector name "myMethod:" String dependence, but I skipped the casting gymnastics as it's not the essence of the problem.



来源:https://stackoverflow.com/questions/53488911/trouble-passing-swift-4-string-to-obj-c-swiftvalue-datausingencoding-unr

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!