[swift-users] Bridging [String] to const char * const *
Jordan Rose
jordan_rose at apple.com
Thu Aug 18 16:33:27 CDT 2016
Here's how we do it for internal testing purposes: withArrayOfCStrings <https://github.com/apple/swift/blob/dfc3933a05264c0c19f7cd43ea0dca351f53ed48/stdlib/private/SwiftPrivate/SwiftPrivate.swift#L68>. The callback is great because you don't have to worry about lifetimes.
Jordan
> On Aug 18, 2016, at 13:04, Kenny Leung via swift-users <swift-users at swift.org> wrote:
>
> Hi All.
>
> When interfacing with C, Swift does some magic to auto-convert Swift strings to char *. This is great, but passing an array of string pointers gets much more involved. The type translates to UnsafePointer<UnsafePointer<CChar>> in Swift.
>
> So I originally tried to get pointers to the individual strings by using cString(using:), and putting them into an Array, but then I found out that there is nothing holding on to the cStrings, so they go away before they can be used. I finally wound up with this hack:
>
> public extension Array {
> public func cStringArray() throws -> ArrayBridge<Element,CChar> {
> return try ArrayBridge<Element,CChar>(array:self) {
> guard let item = $0 as? String,
> let translated = item.cString(using: .utf8) else {
> throw hexdreamsCocoa.Errors.InvalidArgumentError
> }
> return translated
> }
> }
> }
>
> /*
> We need to have this intermediate object around to hold on to the translated objects, otherwise they will go away.
> The UnsafePointer won't hold on to the objects that it's pointing to.
> */
> public struct ArrayBridge<SwiftType,CType> {
>
> let originals :[SwiftType]
> let translated :[[CType]]
> let pointers :[UnsafePointer<CType>?]
> public let pointer :UnsafePointer<UnsafePointer<CType>?>
>
> init(array :[SwiftType], transform: (SwiftType) throws -> [CType]) throws {
> self.originals = array
> self.translated = try array.map(transform)
>
> var pointers = [UnsafePointer<CType>?]()
> for item in translated {
> pointers.append(UnsafePointer<CType>(item))
> }
> pointers.append(nil)
> self.pointers = pointers
> self.pointer = UnsafePointer(self.pointers)
> }
> }
>
> And then to use it you would do something like
>
> try stringArray.cStringArray().pointer
>
> This all seems pretty ugly. So my question is: Is this the right way to handle this problem? Is there a simpler way? It would be awesome if Swift auto-converted arrays of Strings to const char * const *, since it’s a construct used so much in C.
>
> Thanks!
>
> -Kenny
>
>
>
> _______________________________________________
> swift-users mailing list
> swift-users at swift.org
> https://lists.swift.org/mailman/listinfo/swift-users
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-users/attachments/20160818/3dbf3c71/attachment.html>
More information about the swift-users
mailing list