Consider a C++ API like const T* foo()
. This clearly documents the supported mutability and use of the API: OK, we'll let you look at T, but please don't change it. You can still mutate it, but you have to explicitly use const_cast
to indicate your intention to not follow the API.
A good portion of Objective-C API's are comprised of property declarations. How is a user of an API supposed to interpret: @property (readonly) T foo
? (Assume T isn't an immutable type)
- Since the setter isn't synthesized, clearly
foo
isn't mean to be replaced. - However, the getter still gives me a pointer to
foo
. Is it safe to mutate foo? (Clearly I can)
NOTE: I'm not asking about the language specs. I'm asking about what the conventional interpretation of an API like this is within the Objective-C community.
As matt said, the fact that you've got a pointer to the object does not mean that the object itself is mutable. Objective-C uses the behavior of the class, not the pointer, to enforce immutability. So in general you should be seeing read-only properties that return, e.g.,
NSString
rather thanNSMutableString
.I took a look through Apple's iOS framework headers to verify this:
(The pattern for class names in Cocoa is to call the mutable "version" of the class
$PREFIXMutable$CLASSNAME
:NSString
/NSMutableString
,NSDictionary
/NSMutableDictionary
.)Only seven results, and the one in
NSExpression
doesn't count because the "Mutable" that the search found is an argument to the Block that is actually the property's value.For the others, I think you'll find that the appropriate class reference doc tells you what you can and can't do with the values.
For example, the documentation for
threadDictionary
has this to say:A mutable dictionary is returned precisely so that you can mutate it. The thread object doesn't let you set it, however, so that it can also store things there.
The hit in NSAttributedString.h is actually in the
NSMutableAttributedString
class, and those docs note:Since
NSAttributedString
is pretty explicitly* just anNSString
packaged up with a bunch of attributes, the design of the class exposes the wrapped string directly; the mutable version follows suit.UIButton
was mentioned in the comments, because there you have a read-only label whose own properties are modifiable. And there again, the docs are explicit:and
In summary, there's no way in Objective-C at the language level to create or enforce mutability restrictions. As you've noted, a property marked
readonly
simply means there's no way for you to set the value to something else.** And there's no equivalent ofconst_cast
ing the value to be mutable so that you can change it: you will end up with a new value that the vendor object knows nothing about.The Cocoa convention, then, is to secondarily enforce the property's status by using immutable classes. (In some cases you might even be getting an immutable copy of data that the class internally retains as mutable.) If the API gives you a mutable object, you can assume that you may mutate it, but the documentation should tell you exactly how you can use it.
*Its class description says: "An
NSAttributedString
object manages character strings and associated sets of attributes (for example, font and kerning) that apply to individual characters or ranges of characters in the string."**There is KVC, but that's again at the framework level, and framework convention would indicate that you're asking for trouble doing that.