How to convert String to UnsafePointer and length

前端 未结 9 1062
萌比男神i
萌比男神i 2020-12-09 16:13

When I using NSOutputStream\'s write method

func write(_ buffer: UnsafePointer, maxLength length: Int) -> Int


        
相关标签:
9条回答
  • 2020-12-09 16:16

    Swift 4,

    Convert String to NSString, then use NSString's methods.

    let text = "Hello"
    let pointer: UnsafePointer<Int8>? = NSString(string: text).utf8String
    let length = NSString(string: text).length
    
    0 讨论(0)
  • 2020-12-09 16:21

    Here is a string extension for Swift 5 that you can convert a string to UnsafePointer<UInt8> and UnsafeMutablePointer<Int8>

    extension String {
        func toUnsafePointer() -> UnsafePointer<UInt8>? {
            guard let data = self.data(using: .utf8) else {
                return nil
            }
    
            let buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: data.count)
            let stream = OutputStream(toBuffer: buffer, capacity: data.count)
            stream.open()
            let value = data.withUnsafeBytes {
                $0.baseAddress?.assumingMemoryBound(to: UInt8.self)
            }
            guard let val = value else {
                return nil
            }
            stream.write(val, maxLength: data.count)
            stream.close()
    
            return UnsafePointer<UInt8>(buffer)
        }
    
        func toUnsafeMutablePointer() -> UnsafeMutablePointer<Int8>? {
            return strdup(self)
        }
    }
    

    To convert UnsafeMutablePointer<Int8> to String

    guard let mutablePointer = "test".toUnsafeMutablePointer() else {
        return
    }
    
    let str = String(cString: mutablePointer)
    
    0 讨论(0)
  • 2020-12-09 16:23

    You have to convert the string to UTF-8 data first

    let string = "foo bar"
    let data = string.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
    

    and then write it to the output stream

    let outputStream: NSOutputStream = ... // the stream that you want to write to
    let bytesWritten = outputStream.write(UnsafePointer(data.bytes), maxLength: data.length)
    

    The UnsafePointer() cast is necessary because data.bytes has the type UnsafePointer<Void>, and not UnsafePointer<UInt8> as expected by the write() method.


    Update for Swift 3:

    let string = "foo bar"
    // Conversion to UTF-8 data (cannot fail):
    let data = string.data(using: String.Encoding.utf8)! 
    
    // Write to output stream:
    let outputStream: NSOutputStream = ... // the stream that you want to write to
    let bytesWritten = data.withUnsafeBytes { outputStream.write($0, maxLength: data.count) }
    
    0 讨论(0)
  • 2020-12-09 16:25

    Here is how to do it in Swift 3. Run fine in Swift 4 too

    extension String {
    
      func toPointer() -> UnsafePointer<UInt8>? {
        guard let data = self.data(using: String.Encoding.utf8) else { return nil }
    
        let buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: data.count)
        let stream = OutputStream(toBuffer: buffer, capacity: data.count)
    
        stream.open()
        data.withUnsafeBytes({ (p: UnsafePointer<UInt8>) -> Void in
          stream.write(p, maxLength: data.count)
        })
    
        stream.close()
    
        return UnsafePointer<UInt8>(buffer)
      }
    }
    

    To convert from String to UnsafeMutablePointer<Int8>

    let cString = strdup("Hello") // UnsafeMutablePointer<Int8>
    

    To convert from UnsafeMutablePointer<Int8> to String

    let string = String(cString: cString!) // String
    
    0 讨论(0)
  • 2020-12-09 16:28

    I see there are other answers, and an accepted answer, so it seems you've gotten what you need. I came here because I noticed Swift 5's deprecation warnings for withUnsafeMutableBytes et al, and started testing @abdullahselek's answer, but I noticed in Swift 5 (haven't yet verified if it worked in previous versions) that String is convertible to UnsafePointer<UInt8> in-line, so you can use it in place where an UnsafePointer<UInt8> is expected. In case it helps to see another example, here's our old and updated function, posted here:

    OLD

    let derivationStatus = localDerivedKeyData.withUnsafeMutableBytes { derivedKeyBytes in
      salt.withUnsafeBytes { saltBytes in
    
        CCKeyDerivationPBKDF(
          CCPBKDFAlgorithm(kCCPBKDF2),
          password,
          passwordData.count,
          saltBytes,
          salt.count,
          algorithm,
          UInt32(rounds),
          derivedKeyBytes,
          derivedKeyData.count
        )
      }
    }
    

    NEW

    let derivationStatus = localDerivedKeyData.withUnsafeMutableBytes { (outputBytes: UnsafeMutableRawBufferPointer) -> Int32 in
      let status = CCKeyDerivationPBKDF(
        CCPBKDFAlgorithm(kCCPBKDF2),
        password, // a String
        passwordData.count, // just the password String converted to Data
        String(data: salt, encoding: .utf8),  // converts salt (Data) to String
        salt.count,
        algorithm,
        UInt32(rounds),
        outputBytes.baseAddress?.assumingMemoryBound(to: UInt8.self),
        derivedKeyData.count
      )
      return status
    }
    

    With that said, you could use a similar approach to get your stream as follows:

    let stream = OutputStream(toBuffer: UnsafeMutablePointer(mutating: someString), capacity: someString.data(using: .utf8)!.count)
    

    (the ! is used to silence the compiler error, but you should avoid force-unwrapping where possible).

    0 讨论(0)
  • 2020-12-09 16:29

    file.cString(using: String.Encoding.utf8)

    0 讨论(0)
提交回复
热议问题