swiftobjective-ccocoaprintingnsvalue

How to print NSValue bytes


How does one print NSValue bytes? When using print it doesn't print all the bytes and puts '...'. E.g. {length = 128, bytes = 0x00000000 0000f03f 00000000 00000000 ... 00000000 0000f03f }

import Cocoa
import SceneKit

var identityMatrix = SCNMatrix4()

identityMatrix.m11 = 1
identityMatrix.m12 = 0
identityMatrix.m13 = 0
identityMatrix.m14 = 0
identityMatrix.m21 = 0
identityMatrix.m22 = 1
identityMatrix.m23 = 0
identityMatrix.m24 = 0
identityMatrix.m31 = 0
identityMatrix.m32 = 0
identityMatrix.m33 = 1
identityMatrix.m34 = 0
identityMatrix.m41 = 0
identityMatrix.m42 = 0
identityMatrix.m43 = 0
identityMatrix.m44 = 1

var a = [NSValue]()

a.append(NSValue(scnMatrix4:identityMatrix))

identityMatrix.m11 = 1
identityMatrix.m12 = 0
identityMatrix.m13 = 0
identityMatrix.m14 = 0
identityMatrix.m21 = 0
identityMatrix.m22 = 1
identityMatrix.m23 = 0
identityMatrix.m24 = 0
identityMatrix.m31 = 0
identityMatrix.m32 = 0
identityMatrix.m33 = 1
identityMatrix.m34 = 0
identityMatrix.m41 = 0
identityMatrix.m42 = -1.0
identityMatrix.m43 = 0
identityMatrix.m44 = 1

a.append(NSValue(scnMatrix4:identityMatrix))

print(a[0])

Solution

  • First of all, we can tidy this up by using an array literal, and the SCNMatrix4 initializer to get rid of all the mutability:

    import Cocoa
    import SceneKit
    
    let a = [
        SCNMatrix4(
            m11: 1, m12: 0, m13: 0, m14: 0,
            m21: 0, m22: 0, m23: 0, m24: 0,
            m31: 0, m32: 0, m33: 1, m34: 0,
            m41: 0, m42: 0, m43: 0, m44: 1
        ),
        SCNMatrix4(
            m11: 1, m12:  0, m13: 0, m14: 0,
            m21: 0, m22:  1, m23: 0, m24: 0,
            m31: 0, m32:  0, m33: 1, m34: 0,
            m41: 0, m42: -1, m43: 0, m44: 1
        ),
    ].map(NSValue.init(scnMatrix4:))
    
    print(a[0])
    

    That makes the code much more sensible. We can also notice from the documentation that there's already a constant that we can use to get an identity matrix:

    import Cocoa
    import SceneKit
    
    let a = [
        SCNMatrix4Identity,
        SCNMatrix4(
            m11: 1, m12:  0, m13: 0, m14: 0,
            m21: 0, m22:  1, m23: 0, m24: 0,
            m31: 0, m32:  0, m33: 1, m34: 0,
            m41: 0, m42: -1, m43: 0, m44: 1
        ),
    ].map(NSValue.init(scnMatrix4:))
    
    print(a[0])
    

    It's not clear why these matrices are wrapped in NSValue, but to display details about them (and call other methods on them), you'll need to fish the matrix back out of the NSValue box using the scnMatrix4Value API:

    let sampleMatrix = a[0].scnMatrix4Value
    print(sampleMatrix)
    

    If you want to print the byte layout of these, (although it's still really not clear why you would want this, since AFAICT, NSValue and SCNMatrix4 make no promises about their memory layout), you can use the usual pointer APIs, in combination with some hex printing logic such as this:

    withUnsafeBytes(of: &sampleMatrix) { sampleMatrixPointer in
        print(sampleMatrixPointer.map { String(format: "%02x", $0) }.joined(separator: ""))
    }
    

    prints:

    000000000000f03f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f03f0000000000000000000000000000000000000000000000000000000000000000000000000000f03f