GLKMathUnproject Returning Unexpected Results

I am trying to get the world coordinates of where I touch on screen. I am trying to use GLKMathUnproject however I have yet to get satisfactory results from it and after days of Googling I have yet to make significant progress. I’ve attached a sample GLKViewController that draws a colored square on screen. I expect that when I tap on the bottom left corner I would get the coordinate (-0.5, -0.5) back out. Can someone help me out?
import GLKit

private struct VertexAttribute {
    let name: UnsafePointer<GLchar>!
    let index: GLuint
    let normalized: GLboolean
    let offset: UnsafeRawPointer!
    let size: GLint
    let type: GLenum
    
    func bindAttribLocation(_ programHandle: GLuint) {
        glBindAttribLocation(programHandle, index, name)
    }
    
    func enableVertexAttribArray() {
        glEnableVertexAttribArray(index)
    }
    
    func disableVertexAttribArray() {
        glDisableVertexAttribArray(index)
    }
    
    func vertexAttribPointer() {
        glVertexAttribPointer(index, size, type, normalized, GLsizei(MemoryLayout<Vertex>.stride), offset)
    }
}

private struct Vertex {
    var x: GLfloat
    var y: GLfloat
    var z: GLfloat
    
    var r: GLfloat
    var g: GLfloat
    var b: GLfloat
    var a: GLfloat
    
    struct Attributes {
        static let position = VertexAttribute(
            name: "a_Position",
            index: 0,
            normalized: GLboolean(GL_FALSE),
            offset: UnsafeRawPointer(bitPattern: 0),
            size: 3,
            type: GLenum(GL_FLOAT)
        )
        
        static let color = VertexAttribute(
            name: "a_Color",
            index: 1,
            normalized: GLboolean(GL_FALSE),
            offset: UnsafeRawPointer(bitPattern: 3 * MemoryLayout<GLfloat>.size),
            size: 4,
            type: GLenum(GL_FLOAT)
        )
    }
}

private func compileShader(shaderFilename: String, shaderType: GLenum) -> GLuint? {
    guard let shaderPath = Bundle.main.path(forResource: shaderFilename, ofType: nil) else { return nil }
    do {
        let shaderHandle = glCreateShader(shaderType)
        let shaderSource = try NSString(contentsOfFile: shaderPath, encoding: String.Encoding.utf8.rawValue)
        var shaderCString = shaderSource.utf8String
        var shaderSourceLength = GLint(shaderSource.length)
        glShaderSource(shaderHandle, 1, &shaderCString, &shaderSourceLength)
        glCompileShader(shaderHandle)
        
        var compileStatus = GL_FALSE
        glGetShaderiv(shaderHandle, GLenum(GL_COMPILE_STATUS), &compileStatus)
        if compileStatus == GL_FALSE {
            var infoLength = GLsizei()
            let bufferLength = GLsizei(1024)
            glGetShaderiv(shaderHandle, GLenum(GL_INFO_LOG_LENGTH), &infoLength)
            let info = Array<GLchar>(repeating: GLchar(0), count: Int(bufferLength))
            var actualLength = GLsizei()
            glGetShaderInfoLog(shaderHandle, bufferLength, &actualLength, UnsafeMutablePointer(mutating: info))
            print("error compiling shader: \(String(validatingUTF8: info) ?? "error getting info log")")
            return nil
        }
        
        return shaderHandle
    } catch {
        return nil
    }
}

private class ShaderProgram {
    private(set) var programHandle = glCreateProgram()
    private var modelViewMatrixUniform = GLint()
    private var projectionMatrixUniform = GLint()
    
    var modelViewMatrix = GLKMatrix4Identity
    var projectionMatrix = GLKMatrix4Identity
    
    init?(vertexShaderFilename: String, fragmentShaderFilename: String) {
        guard let vertexShaderHandle = compileShader(shaderFilename: vertexShaderFilename, shaderType: GLenum(GL_VERTEX_SHADER)) else { return nil }
        guard let fragmentShaderHandle = compileShader(shaderFilename: fragmentShaderFilename, shaderType: GLenum(GL_FRAGMENT_SHADER)) else { return nil }
        
        glAttachShader(programHandle, vertexShaderHandle)
        glAttachShader(programHandle, fragmentShaderHandle)
        Vertex.Attributes.position.bindAttribLocation(programHandle)
        Vertex.Attributes.color.bindAttribLocation(programHandle)
        glLinkProgram(programHandle)
        
        modelViewMatrixUniform = glGetUniformLocation(programHandle, "u_ModelViewMatrix")
        projectionMatrixUniform = glGetUniformLocation(programHandle, "u_ProjectionMatrix")
        
        var linkStatus = GL_FALSE
        glGetProgramiv(programHandle, GLenum(GL_LINK_STATUS), &linkStatus)
        if linkStatus == GL_FALSE {
            var infoLength = GLsizei()
            let bufferLength = GLsizei(1024)
            glGetProgramiv(programHandle, GLenum(GL_INFO_LOG_LENGTH), &infoLength)
            
            let info = Array<GLchar>(repeating: GLchar(), count: Int(bufferLength))
            var actualLength = GLsizei()
            glGetProgramInfoLog(programHandle, bufferLength, &actualLength, UnsafeMutablePointer(mutating: info))
            print("error linking shader program: \(String(validatingUTF8: info) ?? "error reading info log")")
            return nil
        }
    }
    
    func prepareToDraw() {
        glUseProgram(programHandle)
        glUniformMatrix4fv(modelViewMatrixUniform, 1, GLboolean(GL_FALSE), modelViewMatrix.array)
        glUniformMatrix4fv(projectionMatrixUniform, 1, GLboolean(GL_FALSE), projectionMatrix.array)
    }
}

private struct Model {
    let shaderProgram: ShaderProgram
    let numIndices: GLsizei
    private(set) var vao = GLuint()
    private var vertexBuffer = GLuint()
    private var indexBuffer = GLuint()
    
    var position = GLKVector3()
    var rotationX = Float()
    var rotationY = Float()
    var rotationZ = Float()
    var scale = Float(1)
    
    var modelMatrix: GLKMatrix4 {
        var modelMatrix = GLKMatrix4Identity
        modelMatrix = GLKMatrix4Translate(modelMatrix, position.x, position.y, position.z)
        modelMatrix = GLKMatrix4RotateX(modelMatrix, rotationX)
        modelMatrix = GLKMatrix4RotateY(modelMatrix, rotationY)
        modelMatrix = GLKMatrix4RotateZ(modelMatrix, rotationZ)
        modelMatrix = GLKMatrix4Scale(modelMatrix, scale, scale, scale)
        return modelMatrix
    }
    
    init(shaderProgram: ShaderProgram, vertices: [Vertex], indices: [GLubyte]) {
        self.shaderProgram = shaderProgram
        numIndices = GLsizei(indices.count)
        
        glGenVertexArraysOES(1, &vao)
        glBindVertexArrayOES(vao)
        
        glGenBuffers(1, &vertexBuffer)
        glBindBuffer(GLenum(GL_ARRAY_BUFFER), vertexBuffer)
        glBufferData(GLenum(GL_ARRAY_BUFFER), GLsizeiptr(vertices.count * MemoryLayout<Vertex>.stride), vertices, GLenum(GL_STATIC_DRAW))
        
        glGenBuffers(1, &indexBuffer)
        glBindBuffer(GLenum(GL_ELEMENT_ARRAY_BUFFER), indexBuffer)
        glBufferData(GLenum(GL_ELEMENT_ARRAY_BUFFER), GLsizeiptr(indices.count * MemoryLayout<GLubyte>.stride), indices, GLenum(GL_STATIC_DRAW))
        
        Vertex.Attributes.position.enableVertexAttribArray()
        Vertex.Attributes.position.vertexAttribPointer()
        
        Vertex.Attributes.color.enableVertexAttribArray()
        Vertex.Attributes.color.vertexAttribPointer()
        
        glBindVertexArrayOES(0)
        glBindBuffer(GLenum(GL_ARRAY_BUFFER), 0)
        glBindBuffer(GLenum(GL_ELEMENT_ARRAY_BUFFER), 0)
    }
    
    func render() {
        shaderProgram.modelViewMatrix = modelMatrix
        shaderProgram.prepareToDraw()
        glBindVertexArrayOES(vao)
        glDrawElements(GLenum(GL_TRIANGLES), numIndices, GLenum(GL_UNSIGNED_BYTE), nil)
        glBindVertexArrayOES(0)
    }
}

class UnprojectViewController: GLKViewController {
    @IBOutlet weak var glkView: GLKView!
    
    private var shader: ShaderProgram?
    private var renderable: Model?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        guard let context = EAGLContext(api: .openGLES2) else { return }
        glkView.context = context
        EAGLContext.setCurrent(glkView.context)
    }
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        guard let shader = ShaderProgram(vertexShaderFilename: "TransformableModelVertexShader.glsl", fragmentShaderFilename: "TransformableModelFragmentShader.glsl") else { return }
        self.shader = shader
        shader.projectionMatrix = GLKMatrix4MakePerspective(GLKMathDegreesToRadians(85), Float(view.bounds.width / view.bounds.height), 1, 101)
        renderable = Model(shaderProgram: shader, vertices: [
            Vertex(x: -0.5, y: 0.5, z: 0, r: 1, g: 0, b: 0, a: 1),
            Vertex(x: -0.5, y: -0.5, z: 0, r: 0, g: 0, b: 1, a: 1),
            Vertex(x: 0.5, y: -0.5, z: 0, r: 0, g: 1, b: 0, a: 1),
            Vertex(x: 0.5, y: 0.5, z: 0, r: 1, g: 1, b: 0, a: 1)
            ], indices: [0, 1, 2, 0, 2, 3])
        renderable?.position.z = -5
    }
    
    override func glkView(_ view: GLKView, drawIn rect: CGRect) {
        glClear(GLbitfield(GL_COLOR_BUFFER_BIT))
        renderable?.render()
    }
    
    @IBAction func tap(_ sender: UITapGestureRecognizer) {
        let touchInWindow = GLKVector3(v: (Float(sender.location(in: glkView).x), Float(sender.location(in: glkView).y), 0.05))
        var viewport = [Int32]([0, 0, 0, 0])
        glGetIntegerv(GLenum(GL_VIEWPORT), &viewport)
        guard let renderable = renderable, let shader = shader  else { return }
        print(GLKMathUnproject(touchInWindow, renderable.modelMatrix, shader.projectionMatrix, &viewport, nil).v)
    }
}

extension GLKMatrix2 {
    var array: [Float] {
        return (0..<4).map { i in
            self[i]
        }
    }
}

extension GLKMatrix3 {
    var array: [Float] {
        return (0..<9).map { i in
            self[i]
        }
    }
}

extension GLKMatrix4 {
    var array: [Float] {
        return (0..<16).map { i in
            self[i]
        }
    }
}