Hello everyone, I have a question about Objective...
# multiplatform
s
Hello everyone, I have a question about Objective C interop (from Swift), how a protocol extension can be called from Kotlin (iosMain). I have this in Swift (and the generated Objective-C headers)
Copy code
@objc public protocol Parts {
    var parts: [Part] { get }
}

@objc extension NSString: Parts {
  @objc public var parts: [Part] {
      return [.init(self)]
  }
}
Objective-C equivalent:
Copy code
SWIFT_PROTOCOL("_TtP8GoogleAi5Parts_")
@protocol Parts
@property (nonatomic, readonly, copy) NSArray<Part *> * _Nonnull parts;
@end


@interface NSString (SWIFT_EXTENSION(GoogleAi)) <Parts>
@property (nonatomic, readonly, copy) NSArray<Part *> * _Nonnull parts;
@end
How can I created a
Parts
from a a
String
in Kotlin given these declarations (or translate a String to a Parts-Protocol)?
Thanks!
j
What do you exactly want to call from where? From the description it sounds as if you want to call something from 'shared' (ie. from the Kotlin part) in iosMain (ie. in the Swift part). This is tricky - because the iosMain is compiled after 'shared' - but there are solutions to that; but would be good to know what you actually want to achieve in a more detailed way.
s
Hi Jan, There's another api that uses the
Parts
protocol as input to one of its methods/functions. Eg.
func doSomething(parts: Parts)
. I'd like to be able to call this function with just a String (or NSString). In Swift, I can call this function with just an NSString (since it extends Parts):
doSomething("hello")
However, in Kotlin, in the iosMain module, I can't do that: It complains that
NSString
(or the Kotlin
String
) is not conforming to the interface
PartsProtocol
.
j
Thanks for further info! So given that you say that "in Kotlin, in the iosMain module ... it complains" - so if I understand that correctly, you have a Swift library that you include via cinterop into your KMP project; ie. the dependency goes that your shared (KMP iosMain) depends on a Swift library (that declares the Parts protocol). Is that correct? If yes - then you either need to extend the Swift library so that it also has func doSomething(parts: String), or you need to instantiate an object of type Parts in Kotlin, and then call the doSomething() with that object. I have no information about your use case, but I'm inclined to think that the 2nd is more correct. If the Parts is always just a protocol, and not implemented in the library, it is even easier for you - you should be able to do class KotlinParts : NSObject(), PartsProtocol { ... } in the iosMain and then you can use an instance of KotlinParts as param when calling the doSomething(). Does that help?
s
Thank you Jan, I was hoping there was a way to avoid the extra class definition of
KotlinParts
(or something similar) and that KMP's cinterop would 'seamlessly' accept objective-c type extensions I do have control over the cinterop and I'll add a(n overloaded) 'wrapper'/'adapter' method for this, that accepts a plain NSString (Kotlin String in iosMain) Thanks!
👍 1
j
Yeah, I'm afraid such a thing will not work out of the box, so I believe the wrapper/adapter method is really needed; but still, extensions are supposed to work to some extent according to https://kotlinlang.org/docs/native-objc-interop.html#extensions-and-category-members so maybe somebody else will know a trick that I don't 🙂