0

I'm trying to use this code from the Realm documentation:

var key = Data(count: 64)
_ = key.withUnsafeMutableBytes { bytes in
    SecRandomCopyBytes(kSecRandomDefault, 64, bytes)
}

On its own, this will compile. However as withUnsafeMutableBytes completes with a closure, instead of this type of code flow:

var key = Data(count: 64)
_ = key.withUnsafeMutableBytes { bytes in
    SecRandomCopyBytes(kSecRandomDefault, 64, bytes)
}
// do something using the encryption key

I want to change it to this:

var key = Data(count: 64)
_ = key.withUnsafeMutableBytes { bytes in
    SecRandomCopyBytes(kSecRandomDefault, 64, bytes)
    // do something using the encryption key
}

But I just cannot add anything else to the closure without starting to get errors, for example its not possible to simply add just a print statement:

    var key = Data(count: 64)
    _ = key.withUnsafeMutableBytes { bytes in
        SecRandomCopyBytes(kSecRandomDefault, 64, bytes)
        print("WTF!")
    }

Will give this error:

enter image description here

If I try to get rid of the _, then its this error:

enter image description here

I found this thread https://forums.developer.apple.com/thread/51439

But after trying what's in that thread, which doesn't compile actually compile, and so after applying XCode auto-corrections to, I just end up with one error after another after another after another and its driving me nuts.

Gruntcakes
  • 37,738
  • 44
  • 184
  • 378
  • There is a problem in that `SecRandomCopyBytes` may fail, that needs to be checked for. – zaph Feb 07 '17 at 17:27
  • Note: The question here seems to be how to add statements inside the closure. – zaph Feb 07 '17 at 17:29
  • @zaph And the duplicate I pointed to showed how. Now I have to repeat what that duplicate already says, which obviates the whole point of being able to mark as a duplicate. – matt Feb 07 '17 at 17:51

2 Answers2

1

Ignoring the SecRandomCopyBytes part, the overall full syntax is:

var key = Data(count: 64)
key.withUnsafeMutableBytes { (ptr:UnsafeMutablePointer<UInt8>) -> Void in
    print("here")
}

Putting SecRandomCopyBytes doesn't seem to make any serious difference:

var key = Data(count: 64)
key.withUnsafeMutableBytes { (ptr:UnsafeMutablePointer<UInt8>) -> Void in
    SecRandomCopyBytes(kSecRandomDefault, 64, ptr)
    print("here")
}

That might not be your final code, of course, but the point is that it compiles and permits you to proceed to develop the code further. — Actually, just for laughs, I tried the following, to see whether we really were populating the Data with random bytes, and it seems to be working fine:

    var key = Data(count: 64)
    key.withUnsafeMutableBytes { (ptr:UnsafeMutablePointer<UInt8>) -> Void in
        _ = SecRandomCopyBytes(kSecRandomDefault, 64, ptr)
    }
    for b in key {print(b)}

Note the use of _ = to suppress the warning about the unused result.

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • One point: Adding the `print` statement requires changing `ptr in` to `(ptr:UnsafeMutablePointer) -> Void in` which is unfortunate, surprising but understandable closure syntax. – zaph Feb 07 '17 at 18:26
  • @zaph I have to wonder whether the OP has found a bug in the Swift compiler. Why should adding a second line require you to say explicitly what is obviously the case, that a Data's bytes are UInt8? – matt Feb 07 '17 at 22:14
0

For me declarate a count constant before worked:

func generateRandomBytes() -> String? {
        var keyData = Data(count: 48)
        let count = keyData.count
        let result = keyData.withUnsafeMutableBytes {
            (mutableBytes: UnsafeMutablePointer<UInt8>) -> Int32 in
            SecRandomCopyBytes(kSecRandomDefault, count, mutableBytes)
        }
        if result == errSecSuccess {
            return keyData.base64EncodedString()
        } else {
            print("Problem generating random bytes")
            return nil
        }
    }
Dasoga
  • 5,489
  • 4
  • 33
  • 40