Memory Management in UI delegates
Transient Objects
Callbacks from AppKit, e.g. to your NSApplicationDelegate are contained within autorelease pools.
For transient objects, that are only referenced during the callback, there are two simple rules:
- for objects you own, call
autorelease()before you loose the reference to the object - objects you don’t own need no special consideration.
The same applies to objects created during initialization of the delegate.
Example:
@ScalaObjC
class AppDelegate(self: NSObject) extends NSApplicationDelegate {
// IBAction callback
def action(sender: id): Unit = {
// objects without ownership interest -> automatically released
val int = @@(42)
val string = ns"The String"
val date = NSDate.date()
val array = NSArray(@@(1),@@(2),@@(3))
// call autorelease() on objects you own
val ownedDate = NSDate.alloc().init().autorelease()
}
}
Objects stored in instance vars
Objective-C objects created in callbacks and stored in instance vars must be released explicitly when they are no longer
referenced by the class by calling release(). Furthermore, if you don’t own the object, you also must call retain()
on it, to avoid its autorelease after the callback has completed.
Furthermore, if your delegate has a property that is an Objective-C object, you must ensure that an object assigned to it
is not deallocated while you’re using it. You must also make sure you relinquish ownership of any currently-held value
when a new value is assigned. To accomplish this, you must call release() on the currently-held, and retain()
on the new value within the setter of the property.
An exception to this rule are usually IBOutlet properties, since those are auto-released when appropriate.
Example:
@ScalaObjC
class AppDelegate(self: NSObject) extends NSApplicationDelegate {
private var _int: NSNumber = @@(0).retain() // we need to retain since we call release() in action()_
private var _date: NSDate = NSDate.alloc().init()
private var _count: NSNumber = _
// retain/ release usually not required for IBOutlets
var window: NSWindow = _
def count: NSNumber = _count
// release currently-held and retain new value in setters for Objective-C objects
def count_=(n: NSNumber): Unit = {
n.retain()
_count.release()
_count = n
}
// IBAction callback
def action(sender: id): Unit = {
// release old objects
_int.release()
_date.release()
// objects without ownership interest must be retained when they are stored
_int = @@(42).retain()
// owned object
_date = NSDate.alloc().init()
}
}
Simplify memory management using setters
Manually retaining/ releasing objects whenever the old value of a variable is replaced is cumbersome and error-prone. Hence, you should use also setters for private vars that hold Objective-C objects instead of directly accessing the var.