Swift readonly external, readwrite internal property

Objective CPropertiesSwift

Objective C Problem Overview


In Swift, what is the conventional way to define the common pattern where a property is to be externally readonly, but modifiable internally by the class (and subclasses) that own it.

In Objective-C, there are the following options:

  • Declare the property as readonly in the interface and use a class extension to access the property internally. This is message-based access, hence it works nicely with KVO, atomicity, etc.
  • Declare the property as readonly in the interface, but access the backing ivar internally. As the default access for an ivar is protected, this works nicely in a class hierarchy, where subclasses will also be able to modify the value, but the field is otherwise readonly.

In Java the convention is:

  • Declare a protected field, and implement a public, read-only getter (method).

What is the idiom for Swift?

Objective C Solutions


Solution 1 - Objective C

Given a class property, you can specify a different access level by prefixing the property declaration with the access modifier followed by get or set between parenthesis. For example, a class property with a public getter and a private setter will be declared as:

private(set) public var readonlyProperty: Int

Suggested reading: Getters and Setters

Martin's considerations about accessibility level are still valid - i.e. there's no protected modifier, internal restricts access to the module only, private to the current file only, and public with no restrictions.

Swift 3 notes

2 new access modifiers, fileprivate and open have been added to the language, while private and public have been slightly modified:

  • open applies to class and class members only: it's used to allow a class to be subclassed or a member to be overridden outside of the module where they are defined. public instead makes the class or the member publicly accessible, but not inheritable or overridable

  • private now makes a member visible and accessible from the enclosing declaration only, whereas fileprivate to the entire file where it is contained

More details here.

Solution 2 - Objective C

As per @Antonio, we can use a single property to access as the readOnly property value publicly and readWrite privately. Below is my illustration:

class MyClass {

    private(set) public var publicReadOnly: Int = 10

    //as below, we can modify the value within same class which is private access
    func increment() {
        publicReadOnly += 1
    }

    func decrement() {
        publicReadOnly -= 1
    }
}

let object = MyClass()
print("Initial  valule: \(object.publicReadOnly)")

//For below line we get the compile error saying : "Left side of mutating operator isn't mutable: 'publicReadOnly' setter is inaccessible"
//object.publicReadOnly += 1

object.increment()
print("After increment method call: \(object.publicReadOnly)")

object.decrement()
print("After decrement method call: \(object.publicReadOnly)")

And here is the output:

  Initial  valule: 10
  After increment method call: 11
  After decrement method call: 10

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJasper BluesView Question on Stackoverflow
Solution 1 - Objective CAntonioView Answer on Stackoverflow
Solution 2 - Objective CSantoshView Answer on Stackoverflow