3

Are there any disadvantages, if I were to replace all my accessors (get-like const methods) with readonly properties in Objective-C? Are they interchangeable?

I prefer readonly properties for documentation/readability.

Coming from C++, I am thinking of replacing all my const methods (non-mutable methods) with readonly properties in ObjC.

If I adhere to this convention, then I can automatically assume that any regular methods will be changing state (non-const method in C++). Also from a functional-programming perspective, knowing that a readonly property won't change any state (having no side-effects) is useful.

kfmfe04
  • 14,936
  • 14
  • 74
  • 140
  • Are you talking about properties or methods? The question seems slightly confusing. Could you provide a code example of what you're trying to achieve? – Anurag Oct 25 '12 at 15:04
  • @Anurag - an accessor is a constant non-mutable get-like method in standard OOP terminology. It seems analogous to a readonly property to me - that's why I'm posting this question. – kfmfe04 Oct 25 '12 at 15:08

5 Answers5

3

Yes, of course -- it is fine to approach an implementation this way if you choose. Contextually, there are potentially many advantages in doing so.

The disadvantage to watch out for is the cost of the generated properties -- they can be more than twenty times slower. If (for example) your property is not reassignable, it is a huge waste to perform all that ref count cycling/autorelease activity.

Another (minor) disadvantage is that you would frequently find yourself implementing or declaring private setters.

Community
  • 1
  • 1
justin
  • 104,054
  • 14
  • 179
  • 226
2

They can be accessed in the same way (dot syntax, or method syntax). Do whatever feels best. Although I prefer to have methods as methods, when they do (some) logic. If it's only an accessor/getter giving back some data, than a property fits better.

calimarkus
  • 9,955
  • 2
  • 28
  • 48
  • +1 for a good point (dot syntax or method syntax). I prefer to hide implementation to the point that the consumer does not know if logic is necessary - but sometimes, it is useful to the consumer to know if a call will mutate the object. – kfmfe04 Oct 25 '12 at 15:11
  • An readonly property, that mutates the object would be really weird, no? Cannot think of a usecase. But I agree, that property access may have some logic involved sometimes. But that depends really on the usecase. So what do you want to have answered here? Do you have an explicit example? – calimarkus Oct 25 '12 at 15:25
  • @jaydee3 lazy initialization is an oft-used example. – justin Oct 25 '12 at 15:31
  • @justin: yes for sure.. that's no logic though. also it's not mutating the object itself, but just creating a member. – calimarkus Oct 25 '12 at 16:46
  • @jaydee3 lazy initialization in a readonly/getter which involves logic and mutation is as simple as: `- (UIImage *)image \n { \n if (nil == image) { image = [self renderOrLoadImage]; } \n return image; \n }`. – justin Oct 25 '12 at 18:06
  • 1
    ya theres logic. ok. but no real mutation of self. just adding image to it. ya.. you can count that as mutation. not so important now. :) – calimarkus Oct 25 '12 at 20:29
  • @jaydee3 ehm - I've no idea why you insist changing an object's member/variable does not qualify as 'real' mutation. So... Maybe you should explain why it is not a 'real' mutation. – justin Oct 25 '12 at 23:18
  • what I'm thinking of is e.g. a person object, with name, address, etc. and perhaps a dateFormatter with a lazy accessor (not good MVC, but i dont have a better example for now) >> changing the name changes the acutal object data, adding the dateFormatter just adds the dateformatter. that was my point. – calimarkus Oct 26 '12 at 08:39
  • @jaydee3 what you have in mind has been referred to as *logical* mutation (from the perspective of the client), while lazy initialization (new date formatter saved to ivar/property) would be *physical* mutation (e.g. a binary change of `self`). **both** are mutations. whether physical mutation is important to you depends on largely on the perspective (often whether you refer to the object as `self` or not). – justin Oct 31 '12 at 17:50
1

This relates to Key-Value Coding. Take the following:

@interface Boat : NSObject {
   NSString *name;
}
@property (nonatomic, retain) NSString *name;
@end

And...

@interface Boat
@synthesize name;
@end

What the synthesizer does (in this case) is to create two methods:

-(NSString *)name;
-(void)setName;

It names the selectors using so-called 'camel case', changing the first letter of the ivar to caps before adding 'set' to the front of the setter. The name of the getter is just the name of the ivar.

If your ivar names and existing methods follow this pattern, then replacing your hand-written accessors with properties will work flawlessly, whether you use dot syntax or explicit messages:

boat.name = @"Pequod" is compiled to [boat setName:@"Pequod"]. And boat.name is compiled to [boat name].

If your accessors aren't named as such, then you will need to rework the places in code where you use them to match this pattern. Coding according to this pattern is your best approach to all Objective-C / Cocoa programming.

QED
  • 9,803
  • 7
  • 50
  • 87
1

Yes, they are interchangable.

@interface MyClass : NSObject
@property (nonatomic, readonly) NSString *myStr;
@end

is the same as

@interface MyClass : NSObject
-(NSString *)myStr;
@end
@interface MyClass() { NSString *_myStr } 
@end
@implementation MyClass
-(NSString *)myStr { return _myStr; }
@end

Although you won't see it in your code, a property does create a myStr method that is accessible. In both cases, you could use self.myStr or [self myStr] to invoke the method.

Side note: if you are using iOS 6 you do not need to include the @synthesize statement. Otherwise you would write: @synthesize myStr = _myStr; in the implementation file.

J Shapiro
  • 3,861
  • 1
  • 19
  • 29
1

You'll still need some way to set 'em and having a proper setter is often quite handy for automating memory management purposes. Class extensions were created to fulfill exactly this purpose; publicly readonly, privately readwrite.

Foo.h:

@interface Foo : NSObject
@property(readonly, copy) NSString* bar;
@end

Foo.m: @interface Foo() @property(readwrite, copy) NSString* bar; @end

@implementation Foo
... no need to @synthesize ...
- randomMethod

{ [self setBar: @"bas"]; ... self.bar; _bar = [NSString stringWithFormat: @"%@ %@", [self bar], self.bar]]; }

Yes, you want the copy in the @interface declaration. The modifiers in the interface, even on a readonly property, can modify the codegen for the getter as well as the setter.

You'll likely find my answer to this question relevant, too.

Community
  • 1
  • 1
bbum
  • 162,346
  • 23
  • 271
  • 359