Expose Mutable Properties as Immutable

It is often useful to expose mutable properties as immutable in API design. The canonical way to do it in Objective-C is to use the combination of:

  • a public read-only property of immutable type and,
  • a private ivar of mutable type to back the property.

For example:

// List.h
@interface List : NSObject
@property (nonatomic, readonly) NSArray *items;
@end

// List.m
@interface List () {
    NSMutableArray *_ items;
}
@end

You can not use this design pattern in Swift because Swift does not have ivars. However, Swift has calculated properties. Clever people figured out that we can use a private stored property to back a public calculated property:

class List: NSObject {
    public var items: [ListItem] {
        return _items
    }
    private var _items: [ListItem]
}

But I found a better way, using setter access control:

class List: NSObject {
    public private(set) var items: [ListItem]
}

Outside List class, items is not only read-only:

list.items = [item1, item2] // Compilation error: Cannot assign to the result of this expression.

but also immutable:

list.items.append(item1) // Compilation error: Immutable value of type '[ListItem]' only has mutating members named 'append’.

Now we can say Swift is more concise than Objective-C, as least for this API design.