[swift-users] Bridging [String] to const char * const *
Kenny Leung
kenny_leung at pobox.com
Thu Aug 18 16:46:44 CDT 2016
Thanks! At least it’s good to know there wasn’t something trivial I was missing.
-Kenny
> On Aug 18, 2016, at 2:33 PM, Jordan Rose <jordan_rose at apple.com> wrote:
>
> Here's how we do it for internal testing purposes: withArrayOfCStrings. 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
>
More information about the swift-users
mailing list