2017-05-19 35 views
1

那將是描述的問題涉及到我剛纔的問題: string.withCString and UnsafeMutablePointer(mutating: cstring) wrapped into a function這是我的第一個方法來處理零字符串(通過將withCString成一個函數) 和問題,其Mecki問: Why can't I pass an optional Swift String to C function that allows NULL pointers?String.withCString零

想象有一個C函數,如:

unsigned long randomSign(char *pin, char *tag_signature, char *tag_data, char *xyz); 

我知道功能正常工作,如果我環繞相應的快捷功能4 string.withCString關閉:

// pin, tag_signature, tag_data and xyz are optional Strings so they may be nil which is a problem for my result. 
// corresponding swift function: 
// randomSign(pin: UnsafeMutablePointer<Int8>!, tag_signature: UnsafeMutablePointer<Int8>!, tag_data: UnsafeMutablePointer<Int8>!, xyz: UnsafeMutablePointer<Int8>!) 
let result = pin.withCString { s1 in return 
    tag_signature.withCString {s2 in return 
     tag_data.withCString {s3 in return 
      xyz.withCString { s4 in return 
       randomSign(UnsafeMutablePointer(mutating: s1), UnsafeMutablePointer(mutating: s2), UnsafeMutablePointer(mutating: s3), UnsafeMutablePointer(mutating: s4)) 
    }}}} 

And so Martin R replied to an easier example,它不需要環繞randomSign(參數)和UnsafeMutablePointer封蓋(變異:...),因爲它也可以採取的字符串,並將其轉換。 但是當我放棄關閉並使用它作爲Martin R described時,它在啓動mac之後直接在模擬器上首次啓動,但在randomSign-Function的連續調用中,返回會告訴我,例如tag_signature或pin將是無效的(但它實際上是有效的,我不知道爲什麼?!)。

這導致了我需要withCString關閉的問題(目前),但我必須處理nil-Strings,這會導致應用程序在應返回結果時崩潰,因爲它無法評估randomSign-功能。

所以我試圖讓the approach below (also suggested by @Martin R)適應Swift 3,但我沒有做出適應它的方法。

//Swift-2 written by Martin R 
protocol CStringConvertible { 
    func withCString<Result>(@noescape f: UnsafePointer<Int8> throws -> Result) rethrows -> Result 
} 

extension String: CStringConvertible { } 

extension Optional where Wrapped: CStringConvertible { 
    func withOptionalCString<Result>(@noescape f: UnsafePointer<Int8> -> Result) -> Result { 
     if let string = self { 
      return string.withCString(f) 
     } else { 
      return f(nil) 
     } 
    } 
} 

//Swift 3: ??? 

如果有人能告訴我,爲什麼我的功能僅在我使用withCString但不是當我關閉它,我將非常感激 並且如果有人知道如何解決這個問題,即正確翻譯swift-2代碼運行swift-3代碼。

回答

0

let result = randomSign(UnsafeMutablePointer(mutating: pin), 
        UnsafeMutablePointer(mutating: tag_signature), 
        UnsafeMutablePointer(mutating: tag_data), 
        UnsafeMutablePointer(mutating: xyz)) 

的問題是,從斯威夫特 字符串創建的臨時UTF-8表示僅僅在UnsafeMutablePointer(), 每次通話是有效的但randomSign()在通話過程中不一定仍然有效。 (所以我的最終建議https://stackoverflow.com/a/44027397/1187415 實際上是不正確的,我已經更新了那部分)。

https://stackoverflow.com/a/39363769/1187415一種可能迅捷3版包裝物是

extension Optional where Wrapped == String { 
    func withOptionalCString<Result>(_ f: (UnsafeMutablePointer<Int8>?) -> Result) -> Result { 
     if let string = self { 
      return string.withCString { f(UnsafeMutablePointer(mutating: $0)) } 
     } else { 
      return f(nil) 
     } 
    } 
} 

這同時處理的可選性注塑C字符串指針 到一個可變的指針(所要求的randomSign())。這可以 稱爲

let result = pin.withOptionalCString { s1 in 
    tag_signature.withOptionalCString { s2 in 
     tag_data.withOptionalCString { s3 in 
      xyz.withOptionalCString { s4 in 
       randomSign(s1, s2, s3, s4) 
      } 
     } 
    } 
} 

注:從理論上講,可以如果randomSign()簽名改爲採取const char *參數來避免這個問題:

unsigned long randomSign(const char *pin, const char *tag_signature, const char *tag_data, const char *xyz); 

哪一個能那麼簡單地稱爲

let result = randomSign(pin, tag_signature, tag_data, xyz) 

帶有可選或非可選的Swift字符串。 但是,這目前不起作用,如在 SR-2814 Swift does not correctly pass in multiple optional strings to C function中報告的那樣。

+0

奧凱首先我真的很感謝所有的努力和工作,你投入你的答案通過鏈接,實例和解釋備份。所以實際上這隻意味着你提到的理論方法(將其改爲const char *)由於這個錯誤而不起作用?但是上述擴展會起作用嗎?擴展被標紅爲:「同類型的要求使得‘裹’非通用泛型參數」:/ –

+0

@ n.eesemann:它編譯在我的Xcode 8.3.2(雨燕3.1)。 - 是的,最後一種方法*應該可以工作,但是目前並沒有多於一個可選字符串,就像該錯誤報告的那樣。 –

+0

剛剛更新了Xcode和Swift,現在你的推薦的擴展代碼也在我的機器上運行:)。萬分感謝,我會贊成你的回答,但我缺乏4點聲望點! –