Swift Regex Deep Dive
iOS MacOur introductory guide to Swift Regex. Learn regular expressions in Swift including RegexBuilder examples and strongly-typed captures.
This question came up in an IRC channel the other day: “What’s the best way to set up a property that’s read-only externally, but modifiable inside of the class, so I can use properties or KVC to change it?”
TL;DR: Make readonly in a public @property
, make readwrite
in a class extension.
Properties by default are read/write. This property:
@property (assign) NSInteger frobulationThreshold;
States that (semantically) frobulationThreshold
is a mutable property. You can query it. You can change it, with reasonable expectation that you’ll get the same value back next time you query it unless somebody else changes it.
What’s happening under the hood is the compiler is acting as if it had seen these declarations:
- (NSInteger) frobulationThreshold;
- (void) setFrobulationThreshold: (NSInteger) frobThresh;
You can declare a property to be read-only, say to get the number of elements in a collection.
@property (readonly) NSUInteger count;
All this does is have the compiler fantasize that it has seen this declaration:
- (NSUInteger) count;
Outside of that, nothing happens.
Things get more interesting when you @synthesize
one of these properties. The @property
just tells the compiler to pretend that it saw method declarations of a certain form. @synthesize
(whether explicitly written, or implicitly performed with newer Xcodes) takes the various attributes of the @property
declaration, and emits object code for any of the accessors that don’t otherwise exist. Given the frobulationThreshold
property declaration above, if there were no explicitly implemented setters or getters, the compiler would emit an implementation that used atomic access (the default), to retrieve and change an instance variable. Given the count
@property
, the compiler would emit a similar single method’s implementation.
So now the actual answer to the question. Say you wanted to make frobulationThreshold
a read-only property that was modifiable inside of the implementation.
In the header file, you’ll want a property that’ll make the compiler think it’s only seen
- (NSInteger) frobulationThreshold;
And not the setter:
@property (readonly) NSInteger frobulationThreshold;


Is sufficient. Because of the readonly
, only -frobulationThreshold
is considered to exist, but not -setFrobulationThreshold
: Now everyone who #imports
this header will see the readonly
property, and if they try to change it, the compiler will complain with a “I have not seen a declaration for a method called -setFrobulationThreshold:
. I shall now warn in your general direction.” (And you are on top of fixing your Warnings right?)
Inside of the implementation file, though, you can create a class extension that redeclares the property as readwrite
:
@interface Frobinizer ()
@property (assign, readwrite) NSInteger frobulationThreshold;
@end // extension
The readwrite
is actually optional in this case, but I like adding it to make it explicit that this is a property declaration that exists to turn a read-only property into a read/write one
When the compiler sees this, it adjusts its concept of method declarations it thinks it has seen. Before processing the @property
above, the compiler thought it only saw -frobulationThreshold
thanks to the readonly property in the header file. Now with this property redeclaration, the compiler thinks it has seen now seen both -frobulationThreshold
and -setFrobulationThreshold:
. Et voila, the property is now read/write, as far as any code after this class extension is concerned. Code can happily call self.frobulationThreshold = 23;
, or [self setFrobulationThreshold: 23];
to change that property.
Of course not, this is Objective-C. Because there will exist a setFrobulationThreshold:
(either explicitly written, or synthesized) as a method of the class, anyone who is aware of it can call it. That’s just the nature of Objective-C. There are no private methods.
Using read-only properties does help “keep honest people honest”. You have to do some work to call setFrobulationThreshold
from outside of its implementation file, and if you are jumping through those hoops, you should feel dirty enough to reconsider what you’re doing, or to lobby to have the property changed to be publicly read/write.
Our introductory guide to Swift Regex. Learn regular expressions in Swift including RegexBuilder examples and strongly-typed captures.
The Combine framework in Swift is a powerful declarative API for the asynchronous processing of values over time. It takes full advantage of Swift...
SwiftUI has changed a great many things about how developers create applications for iOS, and not just in the way we lay out our...