Search code examples
swiftautomatic-ref-countingretainswift3

How do I manually retain in Swift with ARC?


I'm using Swift 3 with ARC in an iOS app, and I want to manually retain an object.

I tried object.retain() but Xcode says that it's unavailable in ARC mode. Is there an alternative way to do this, to tell Xcode I know what I'm doing?


Long Version:

I have a LocationTracker class that registers itself as the delegate of a CLLocationManager. When the user's location changes, it updates a static variable named location. Other parts of my code that need the location access this static variable, without having or needing a reference to the LocationTracker instance.

The problem with this design is that delegates aren't retained, so the LocationTracker is deallocated by the time the CLLocationManager sends a message to it, causing a crash.

I would like to manually increment the refcount of the LocationTracker before setting it as a delegate. The object will never be deallocated anyway, since the location should be monitored as long as the app is running.

I found a workaround, which is to have a static variable 'instance' that keeps a reference to the LocationTracker. I consider this design inelegant, since I'm never going to use the 'instance' variable. Can I get rid of it and explicitly increment the refcount?

This question is not a duplicate, as was claimed, since the other question is about Objective-C, while this one is about Swift.


Solution

  • The solution turned out to be to re-enable retain() and release():

    extension NSObjectProtocol {
      /// Same as retain(), which the compiler no longer lets us call:
      @discardableResult
      func retainMe() -> Self {
        _ = Unmanaged.passRetained(self)
        return self
      }
    
      /// Same as autorelease(), which the compiler no longer lets us call.
      ///
      /// This function does an autorelease() rather than release() to give you more flexibility.
      @discardableResult
      func releaseMe() -> Self {
        _ = Unmanaged.passUnretained(self).autorelease()
        return self
      }
    }