Ошибка передачи строки Swift 4 в Obj-C ++ - [_ SwiftValue dataUsingEncoding:]: нераспознанный селектор отправлен в экземпляр - PullRequest
0 голосов
/ 26 ноября 2018

У меня есть некоторый код 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 ++!Однако, когда Свифт вмешивается ...

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'

Я в растерянностикак решить эту проблему.Я не могу использовать NSString в Swift и просто передать его, потому что компилятор требует , чтобы я передал Swift String.

Есть ли способ решить эту проблему?

Любое из этих решений подойдет:

  • Заставить сгенерированный заголовок Swift принять NSString * вместо String
  • Способ поворота _SwiftValueв данные из Objective-C ++
  • Любые флаги, которые сообщают компилятору или среде выполнения, чтобы преобразовать это _SwiftValue в NSString * до , пытаясь отправить сообщение
  • и т. д.

Среда

  • Код ObjC ++ находится в модульной структуре, на которую ссылается код Swift;они не собраны вместе.
  • Модуль ObjC ++ скомпилирован с Xcode 8.3.3 и Swift с 9.2.
  • Могут быть и другие расхождения;В этих проектах много движущихся частей.

1 Ответ

0 голосов
/ 27 ноября 2018

Я бы попробовал

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:" Строковая зависимость, но я пропустил гимнастику кастингапоскольку это не суть проблемы.

...