Why does Swift return an unexpected pointer when converting an optional String into an UnsafePointer?

后端 未结 3 890
无人共我
无人共我 2021-01-06 02:12

I noticed some unusual behaviour when working with a C library which took strings in as const char * (which is converted to Swift as UnsafePointer

3条回答
  •  轻奢々
    轻奢々 (楼主)
    2021-01-06 02:42

    As mentioned in the comments, this is a clear bug in Swift.

    Here's a workaround I'm using. If you can't trust Swift to convert the strings to pointers for you, then you've got to do it yourself.

    Assuming C function defined as:

    void multiString(const char *arg0, const char *arg1, const char *arg2);
    

    Swift code:

    func callCFunction(arg0: String?, arg1: String?, arg2: String?) {
        let dArg0 = arg0?.data(using: .utf8) as NSData?
        let pArg0 = dArg0?.bytes.assumingMemoryBound(to: Int8.self)
    
        let dArg1 = arg1?.data(using: .utf8) as NSData?
        let pArg1 = dArg1?.bytes.assumingMemoryBound(to: Int8.self)
    
        let dArg2 = arg2?.data(using: .utf8) as NSData?
        let pArg2 = dArg2?.bytes.assumingMemoryBound(to: Int8.self)
    
        multiString(pArg1, pArg2, pArg3)
    }
    

    Warning:

    Don't be tempted to put this in a function like:

    /* DO NOT USE -- BAD CODE */
    func ocstr(_ str: String?) -> UnsafePointer? {
        guard let str = str else {
            return nil
        }
    
        let nsd = str.data(using: .utf8)! as NSData
    
        //This pointer is invalid on return:
        return nsd.bytes.assumingMemoryBound(to: Int8.self)
    }
    

    which would remove repeated code. This doesn't work because the data object nsd gets deallocated at the end of the function. The pointer is therefore not valid on return.

提交回复
热议问题