swiftsocketspointersbufferinout

Trying to update someone's socket programming code written in Swift 3 to Swift 5.2 (Inout expression creates a temporary pointer...)


The following code originally written in Swift 3, worked without warning in Swift 4.2, gave the warning "Inout expression creates a temporary pointer, but argument #1 should be a pointer that outlives the call to '+'" in Swift 5, now not compiling in Xcode 12 at all with an error saying "Generic parameter 'Element' could not be inferred".

func readNUInt8(_ n:UInt32) throws -> [UInt8] {
        var buffer = [UInt8](repeating: 0, count: Int(n))
        var read = 0
        
        while read < Int(n) {
            
            read += recv(s, &buffer + read, Int(n) - read, 0)
            
            if read <= 0 {
                throw SocketError.recvFailed(Socket.descriptionOfLastError())
            }
        }
        
        if bytesToRead >= UInt32(n) {
            bytesToRead -= UInt32(n)
        }
        
        return buffer
    }

I tried to solve this by converting read to UInt8 and appending to buffer before calling recv() function, but the app crashed elsewhere probably because I broke the socket reading by incorrectly storing read bytes like that.

Any suggestions how to correct the above code to read and store the buffer the right way?


Solution

  • I solved the problem by explicitly using .withUnsafeMutableBytes for the buffer, hence changing the function block to the following:

    func readNUInt8(_ n:UInt32) throws -> [UInt8] {
            var buffer = [UInt8](repeating: 0, count: Int(n))
            var read = 0
            
            while read < Int(n) {
                
                var recvResult : ssize_t = 0
                
                // let recvResult = recv(s, &buffer + read, Int(n) - read, 0)
    
                buffer.withUnsafeMutableBytes { goPointer in recvResult = recv(s, goPointer.baseAddress! + read, Int(n) - read, 0) }
                read += recvResult
                if read <= 0 {
                    throw SocketError.recvFailed(Socket.descriptionOfLastError())
                }
            }
            
            if bytesToRead >= UInt32(n) {
                bytesToRead -= UInt32(n)
            }
            
            return buffer
        }