Yes, the easiest way is to rely on compiler magic for ObjC/C
interoperability, but it is also important to know what is really happening.
My preferred version of the compiler magic is this actually:
func allZerosUUID() -> String {
return NSUUID(uuidBytes: [UInt8](repeating: 0, count: 32)).uuidString
}
Which is effectively this:
func allZerosUUID() -> String {
let allZeros = [UInt8](repeating: 0, count: 32)
return NSUUID(uuidBytes: allZeros).uuidString
}
(Note the use of let and absence of &).
On Mar 2, 2017, at 1:33 PM, Russell Finn <rsfinn@gmail.com> wrote:
I agree that the use of `withUnsafeBufferPointer` to get to the contents
of an array makes more sense than `withUnsafePointer`, once you discover
the concept of a "buffer pointer" (which a new Swift programmer may not do
at first).
However, I note that the following code:
func allZerosUUID() -> String {
var allZeros = [UInt8](repeating: 0, count: 32)
return NSUUID(uuidBytes: &allZeros)
}
also compiles without error and returns the intended value. This appears
to be supported by the "Constant Pointers" section of the "Interacting with
C APIs" chapter of "Using Swift with Cocoa and Objective-C": "When a
function is declared as taking an `UnsafePointer<Type>` argument, it can
accept ... a `[Type]` value, which is passed as a pointer to the start of
the array."
I suspect the availability of `&array` in this context, coupled with an
awareness of the existence of `withUnsafePointer(to:)`, is what led my
co-worker down the wrong road (and to a puzzling error message); but since
we have now discovered two more appropriate ways to write the code in
question, perhaps it's not worth worrying about too much.
Thanks to everyone for the discussion.
On Wed, Mar 1, 2017 at 7:36 PM, Hooman Mehr <hooman@mac.com> wrote:
Your co-worker needs to get passed the learning curve of these “unsafe”
APIs and note that Swift arrays are complex data structures. &allZeros does
not give you a pointer to a bunch of zero bytes, but a pointer to a struct
that contains the private implementation details of allZeros array.
Here is the correct way to do it:
func allZerosUUID() -> String {
let allZeros = [UInt8](repeating: 0, count: 32)
return allZeros.withUnsafeBufferPointer { NSUUID(uuidBytes: $0.
baseAddress).uuidString }
}
On Mar 1, 2017, at 2:35 PM, Russell Finn via swift-users < >> swift-users@swift.org> wrote:
Thanks to Joe and Quinn for their answers. I have a related followup — a
co-worker learning Swift wrote the following function:
func allZerosUUID() -> String {
var allZeros = [UInt8](repeating: 0, count: 32)
return withUnsafePointer(to: &allZeros) { zerosPtr in
return NSUUID(uuidBytes: zerosPtr).uuidString
}
}
but was puzzled that Xcode 8.2.1 gave an error "Cannot convert value of
type 'UnsafePointer<_>' to expected argument type 'UnsafePointer<UInt8>!'"
on the line with the NSUUID initializer. Their expectation was that
`zerosPtr` would be of type `UnsafePointer<UInt8>` because `allZeros` is of
type `[UInt8]`.
They discovered that they could work around this by adding a call to
`withMemoryRebound`:
func allZerosUUID() -> String {
var allZeros = [UInt8](repeating: 0, count: 32)
return withUnsafePointer(to: &allZeros) { zerosPtr in
zerosPtr.withMemoryRebound(to: UInt8.self, capacity:
allZeros.count) { zerosPtr in
return NSUUID(uuidBytes: zerosPtr).uuidString
}
}
}
but felt that this should be unnecessary. Perhaps I'm missing something
simple, but I was unable to explain this compiler behavior; can anyone on
the list do so?
(Yes, I did point out that they could pass `&allZeros` directly to
`NSUUID(uuidBytes:)`.)
Thanks — Russell
_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users