How do I manually retain in Swift with ARC?

5.9k views Asked by At

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.

2

There are 2 answers

1
Kartick Vaddadi On BEST ANSWER

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
  }
}
1
Rudolf Adamkovič On

This is easily done with the withExtendedLifetime(_:_:) function. From the documentation:

Evaluates a closure while ensuring that the given instance is not destroyed before the closure returns.