swift - Difference between unsafeBitCast and assumingMemoryBound - Stack Overflow

admin2025-04-17  5

When I using Apple Audio Unit v2 API in Swift, I face a bug related to using UnsafeMutableRawPointer, which is used in AURenderCallback. So I made a toy example to examine the situation as shown below:

import Foundation

class MyInfo {
  var i: Int = 3
}

class MyDelegate {
  var info: MyInfo?
}

func renderCallback(_ ref: UnsafeMutableRawPointer) {
  var d: MyDelegate = ref.assumingMemoryBound(to: MyDelegate.self).pointee
  // var d: MyDelegate = unsafeBitCast(ref, to: MyDelegate.self) // crash!
  guard var a = d.info else { return }
  a.i = 32
  print(d.info?.i)
}

var d = MyDelegate()
d.info = MyInfo()
renderCallback(&d) // in real application, this is called by audio toolbox framework
print(d.info?.i)

The code works as intended. But, if I use unsafeBitCast instead of assumingMemoryBound, as the comment in the code shows, the program crashes at runtime. Apparently, two code seems equivalent. What is the core difference?

When I using Apple Audio Unit v2 API in Swift, I face a bug related to using UnsafeMutableRawPointer, which is used in AURenderCallback. So I made a toy example to examine the situation as shown below:

import Foundation

class MyInfo {
  var i: Int = 3
}

class MyDelegate {
  var info: MyInfo?
}

func renderCallback(_ ref: UnsafeMutableRawPointer) {
  var d: MyDelegate = ref.assumingMemoryBound(to: MyDelegate.self).pointee
  // var d: MyDelegate = unsafeBitCast(ref, to: MyDelegate.self) // crash!
  guard var a = d.info else { return }
  a.i = 32
  print(d.info?.i)
}

var d = MyDelegate()
d.info = MyInfo()
renderCallback(&d) // in real application, this is called by audio toolbox framework
print(d.info?.i)

The code works as intended. But, if I use unsafeBitCast instead of assumingMemoryBound, as the comment in the code shows, the program crashes at runtime. Apparently, two code seems equivalent. What is the core difference?

Share Improve this question asked Feb 1 at 3:37 pocorallpocorall 1,3112 gold badges10 silver badges24 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 1

ref is a pointer pointing to some value of MyDelegate. It is not a MyDelegate itself.

unsafeBitCast re-interprets the bit pattern of the ref pointer itself as a MyDelegate. assumingMemoryRebound re-interprets the pointee of ref as a MyDelegate instead.

To make this simpler, let's suppose ref has the bit pattern 0x000000016b13b3d8. Suppose there is an Int value of 1 at the location 0x000000016b13b3d8. unsafeBitCast(ref, to: Int.self) would give you 0x000000016b13b3d8 as an Int, so 6091420632 in base 10. On the other hand, ref.assumingMemoryRebound(to: Int.self).pointee would give you 1.

To use C as an analogy, ref is a void *. ref.assumingMemoryRebound(to: MyDelegate.self) and then getting its point is analogous to *((MyDelegate *)ref) - casting to a MyDelegate pointer and then dereferencing it.

unsafeBitCast(ref, to: MyDelegate.self) would be analogous to (MyDelegate)ref, casting the pointer directly to a MyDelegate.

转载请注明原文地址:http://www.anycun.com/QandA/1744840346a88353.html