无法将 Swift 4 字符串传递给 Obj-C++ -[_SwiftValue dataUsingEncoding:]: 无法识别的选择器发送到实例
Trouble passing Swift 4 String to Obj-C++ -[_SwiftValue dataUsingEncoding:]: unrecognized selector sent to instance
我有一些像这样的 Objective-C++ 代码:
// 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
到目前为止很简单;对我来说似乎很好。从 Objective-C 和 Objective-C++ 代码调用时效果很好!但是,当 Swift 参与进来时...
func mySwiftFunc(text: String) {
myObjcClassInstance.myMethod(text)
}
这看起来也很简单。编译器的翻译层自动桥接 Swift 的 String
到 Objective-C++ 的 NSString *
。不幸的是,这是错误的……它似乎将它与一个叫做 _SwiftValue
的东西联系起来。然后它被传入,我尝试调用 dataUsingEncoding:
,但显然 _SwiftValue
没有这样的选择器,所以我遇到了这个崩溃:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[_SwiftValue dataUsingEncoding:]: unrecognized selector sent to instance 0x7f9ca7d63ee0'
我不知道如何解决这个问题。我不能在 Swift 中使用 NSString
并将其传递下去,因为编译器 要求 我传递 Swift String
。
有什么办法可以解决吗?
这些解决方案中的任何一个都可以:
- 强制生成 Swift header 接受
NSString *
而不是 String
- 一种将
_SwiftValue
转换为 Objective-C++ 中的数据的方法
- 让编译器或运行时知道将
_SwiftValue
转换为 NSString *
在 尝试向其发送消息之前的任何标志
- 等等
环境
- ObjC++ 代码位于 Swift 代码引用的模块化框架内;它们不是一起编译的。
- ObjC++ 模块使用 Xcode 8.3.3 编译,Swift 代码使用 9.2。
- 可能还有其他差异;这些项目中有很多活动部件。
我会试试
func mySwiftFunc(text: String) {
myObjcClassInstance.perform(#selector(NSSelectorFromString("myMethod:"), with: text as NSString)
}
如果不行试试:
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)
}
可能没有选择器名称 "myMethod:"
字符串依赖,但我跳过了铸造体操,因为这不是问题的本质。
我有一些像这样的 Objective-C++ 代码:
// 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
到目前为止很简单;对我来说似乎很好。从 Objective-C 和 Objective-C++ 代码调用时效果很好!但是,当 Swift 参与进来时...
func mySwiftFunc(text: String) {
myObjcClassInstance.myMethod(text)
}
这看起来也很简单。编译器的翻译层自动桥接 Swift 的 String
到 Objective-C++ 的 NSString *
。不幸的是,这是错误的……它似乎将它与一个叫做 _SwiftValue
的东西联系起来。然后它被传入,我尝试调用 dataUsingEncoding:
,但显然 _SwiftValue
没有这样的选择器,所以我遇到了这个崩溃:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[_SwiftValue dataUsingEncoding:]: unrecognized selector sent to instance 0x7f9ca7d63ee0'
我不知道如何解决这个问题。我不能在 Swift 中使用 NSString
并将其传递下去,因为编译器 要求 我传递 Swift String
。
有什么办法可以解决吗?
这些解决方案中的任何一个都可以:
- 强制生成 Swift header 接受
NSString *
而不是String
- 一种将
_SwiftValue
转换为 Objective-C++ 中的数据的方法
- 让编译器或运行时知道将
_SwiftValue
转换为NSString *
在 尝试向其发送消息之前的任何标志 - 等等
环境
- ObjC++ 代码位于 Swift 代码引用的模块化框架内;它们不是一起编译的。
- ObjC++ 模块使用 Xcode 8.3.3 编译,Swift 代码使用 9.2。
- 可能还有其他差异;这些项目中有很多活动部件。
我会试试
func mySwiftFunc(text: String) {
myObjcClassInstance.perform(#selector(NSSelectorFromString("myMethod:"), with: text as NSString)
}
如果不行试试:
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)
}
可能没有选择器名称 "myMethod:"
字符串依赖,但我跳过了铸造体操,因为这不是问题的本质。