简体   繁体   中英

In Objective-C does it make sense to declare a readonly property in a category?

Let's say I have Tree.h and Tree+Extensions.h . I know that if I declare, in Tree+Extensions.h a @property (nonatomic) NSString *color and then access it, it will crash, and that I can get something similar to that functionality using objc_getAssociatedObject and objc_setAssociatedObject .

However, I've also seen this:

// Tree+Extensions.h
@interface Tree (Extensions)
@property (nonatomic, readonly) NSString *color;
@end

// Tree+Extensions.m
@implementation Tree (Extensions)
- (NSString *)color {
    return @"green";
}
@end

Notice that the property in the category is declared as readonly and that the accessor method is returning something that can be calculated.

I've seen this code working, but was wondering why would this be preferable than just declaring the accessor method in the header file.

Let's first disregard the fact that this is a category and just talk about this:

@interface Tree
@property (nonatomic, readonly) NSString *color;
@end
@implementation Tree
- (NSString *)color {
    return @"green";
}
@end

As I understand it, your question is: what's the difference between that and this:

@interface Tree
- (NSString *)color;
@end
@implementation Tree
- (NSString *)color {
    return @"green";
}
@end

From a completely practical point of view, there is no difference. People do get used to declaring properties, but in fact those two declarations have exactly the same effect - namely, in either case, a caller (anyone who has imported the interface) can say [aTree color] or aTree.color , indifferently. A property usage ( aTree.color ) is a method call [aTree color] , and vice versa. A caller can say aTree.color even if only the color method is declared (not a property). That is why, for example, it is legal (and common) to say myArray.count , even though NSArray's count is not declared as a property (it's just a method). And, vice versa , it is legal (and common) to say [myViewController navigationController] even though navigationController is declared as a property.

Now, in most cases, the reason for declaring a property is in order to get the compiler to synthesize the corresponding instance variable and the corresponding method implementation(s). But none of that is happening in this case ; there is no instance variable and there is no getter to synthesize (it has been written explicitly).

So, to conclude, let's now return to your original question and sum up: You cannot use a named category (like your Tree (Extensions) ) to add an instance variable to an existing class. As Apple says :

It's valid syntax to include a property declaration in a category interface, but it's not possible to declare an additional instance variable in a category. This means the compiler won't synthesize any instance variable, nor will it synthesize any property accessor methods.

Well, in this case, you are not adding an instance variable to an existing class, and you are not trying to synthesize the "getter": the readonly property declaration is backed by an existing "getter" method which, as you rightly say, calculates the result from whole cloth. Thus, the property declaration, while kind of pointless, is perfectly legal and effective: it just declares the "getter" method.

With the code that you wrote, even from within the class you can't call setColor: , which can make sense when you want to return something that is not backed by an ivar (calculated for example), and that you don't want to expose to the outside world.

Answer: This is preferred because you don't need access to this property from outside the class.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM