How to Dereference an Unsafe Mutable Pointer in Swift

Last updated: Jan 17, 2020

It can be frustrating if you are coming to Swift as an Objective-C developer. Do you ever find yourself thinking:

“I knew how to do this in Objective-C but I have no clue how to do it in Swift!”

Here is an example from when I was looking at the UIPopoverPresentationControllerDelegate protocol last week. When the system needs to reposition a popover, perhaps due to rotation, it calls a delegate method with the proposed view and CGRect. Here it is first in Objective-C:

- (void)popoverPresentationController:
  (UIPopoverPresentationController *)popoverPresentationController
  willRepositionPopoverToRect:(inout CGRect *)rect 
  inView:(inout UIView * _Nonnull __autoreleasing *)view {
  *view = self.someView;
  *rect = self.someView.bounds;
}

Both parameters are pointers allowing you to access the proposed values and pass back new values if you wish. Getting and setting new values is as easy as dereferencing a pointer.

Now take a look at the same function in Swift:

func popoverPresentationController(
  _ popoverPresentationController: UIPopoverPresentationController,
  willRepositionPopoverTo rect: UnsafeMutablePointer<CGRect>,
  in view: AutoreleasingUnsafeMutablePointer<UIView>) {
  // What to do here?
}

What is an UnsafeMutablePointer<CGRect> or an AutoreleasingUnsafeMutablePointer<UIView> and how do you pass back new values for those parameters?

When two worlds collide

The problem in this case is not the fault of Swift. The confusing new syntax is to allow Swift code to interoperate with Objective-C and plain old C frameworks common in Cocoa and UIKit. An UnsafeMutablePointer and its close relation UnsafePointer are both typed pointers:

struct UnsafePointer<Pointee>
struct UnsafeMutablePointer<Pointee>

You use them to access data of a specific type in memory. The type of data is the pointer's Pointee type. So looking again at our Swift signature:

  • UnsafeMutablePointer<CGRect> is a pointer to a CGRect value.
  • AutoreleasingUnsafeMutablePointer<UIView> is a pointer to a UIView.

The only difference between the two types of mutable pointer is the memory management used by the referenced storage. Either way to access the memory you use the pointee instance property:

/// Access the underlying data, getting and setting values.
public var pointee: Pointee { get nonmutating set }

Note the use of a nonmutating setter which is enough to make your head spin. This property allows us to dereference the pointer to retrieve or set the value but does not change the pointer.

Some examples:

// Objective-C assuming CGRect *rect;
CGRect oldRect = *rect;
*rect = newRect;
// Swift assuming rect: UnsafeMutablePointer<CGRect>
oldRect = rect.pointee
rect.pointee = newRect

In brief, use rect.pointee in Swift where you would have used *rect in Objective-C.

Knowing this we can easily translate our popover function to Swift:

func popoverPresentationController(
  _ popoverPresentationController: UIPopoverPresentationController,
  willRepositionPopoverTo rect: UnsafeMutablePointer<CGRect>,
  in view: AutoreleasingUnsafeMutablePointer<UIView>) {
    view.pointee = someView
    rect.pointee = someView.bounds
}

All part of the Swift learning curve.

Further Reading