views:

418

answers:

2

I'd like to use properties for my instance variables, but in many cases, I only want the class itself to have access to the setter. I was hoping I could do something like this:

Foo.h:

@interface Foo {
  NSString *bar;
}
@property (readonly) NSString *bar;
@end

Foo.m:

#import "Foo.h"

@interface Foo ()
@property (copy) NSString *bar;
@end

@implementation Foo
@synthesize bar;
@end

But this generates a warning:

Foo.m:4: warning: property ‘bar’ attribute in ‘Foo’ class continuation does not match class ‘Foo’ property

I can see what it's complaining about, but it still seems like a useful idiom. Is there some other way to accomplish this without writing my own setters?

+11  A: 

Your approach is correct, but the redeclaration of @property bar in the class extension must match the original declaration except for readwrite vs. readonly. So this will work:

Foo.h

@interface Foo {
  NSString *bar;
}
@property (copy,readonly) NSString *bar;
@end

Foo.m:

#import "Foo.h"

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

@implementation Foo
@synthesize bar;
@end

(recall that the default is retain for properties, not copy).

Barry Wark
Huh, that never occurred to me since 'copy' is otherwise irrelevant to the getter. Thanks!
Mark Smith
+1  A: 

When Barry says "the default is retain for properties" he means that retain should be specified like this:

@property (retain) NSDate *endDate;

If they are left like this:

@property NSDate *endDate;

assign is assumed by the compiler.

David Weiss
I'm pretty sure he meant exactly what he said, but you're right—`assign` is the default, not `retain`. http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/ObjectiveC/Articles/ocProperties.html#//apple_ref/doc/uid/TP30001163-CH17-SW27
Peter Hosey