31

I am stuck with objective-c properties. What I need is to assign a write-only property for a variable, exactly the opposite of readonly, i.e the variable can have setMethod, but it should not have getMethod. I don't know how to do it. answers with some code snippets are appreciated.

nevan king
  • 112,709
  • 45
  • 203
  • 241
KingofHeaven
  • 1,195
  • 3
  • 14
  • 27
  • 2
    What's the use of write-only property? IMHO it's only a waste of memory. – Eimantas Nov 24 '10 at 11:25
  • 21
    Lots of uses; typically when you want something to be publicly write-only and internally-to-the-class it is readwrite. – bbum Nov 24 '10 at 19:36
  • When an outside class knows a variable that needs to be passed in but has no reason to know what it's currently set to. – ArtOfWarfare Oct 20 '13 at 19:28

3 Answers3

54

Another valid approach is to declare the normal property and make the getter unavailable

@interface MyClass
@property NSString * var;
- (NSString *)var UNAVAILABLE_ATTRIBUTE;
@end

This will raise a compile-time error in case someone tries to access the getter.


The main advantage of this approach is that you actually have a real propertyTM and not a surrogate faked by a instance variable and a setter, which implies that:

  • you'll get auto-completion when using dot-notation in Xcode
  • all the runtime functions such as class_getProperty and class_copyPropertyList will work as expected.

That said, the getter implementation is synthesized anyway and it could be invoked using something like

NSString * string = [myObj performSelector:@selector(var)];

or using NSInvocation (in case of a non-id property)

If you are paranoid and you really want to prevent the client to invoke the getter, you can explicitly throw an exception by providing your own implementation.

@implementation MyClass
- (int)var {
    [NSException raise:NSInternalInconsistencyException
                format:@"property is write-only"];
}
@end

Anyway, if someone seriously wants to tamper with your instance variable, they can use the runtime to access it, so the last precaution is probably useless given the use case. A compile-time error is what you are really looking for.

Gabriele Petronella
  • 106,943
  • 21
  • 217
  • 235
12

You can do something like:

@interface MyClass {
@private
int _var;
}

- (void)setVar:(int)newVar;
@end

@implementation MyClass
- (void)setVar:(int)newVar {
_var = newVar;
}
@end

Now you can access the variable var like a property that is write-only:

@implementation SomeOtherClass
...
MyClass c = [[MyClass alloc] init];
c.var = 3;
...
@end

And if you try to read the fake property the compiler will warning you.

Mark Amery
  • 143,130
  • 81
  • 406
  • 459
Bruno Berisso
  • 1,091
  • 11
  • 33
  • 1
    Need to define a method `-(void)setVar:(int)newVar` in the implementation as well as the interface. – JeremyP Nov 24 '10 at 11:42
  • Be aware that this does not completely hide the value. Unless you override (BOOL)accessInstanceVariablesDirectly with NO, you can get the value with valueForKey:@"var". And even if you override this, you can still get the value with a objC-runtime method like object_getInstanceVariable. – w-m Nov 24 '10 at 11:49
  • 4
    @kubbing Technically it is a property. A property in Obj-C is just a fancy name for two methods, getter & setter. You can declare a getter without using `@property` and the behavior will be exactly the same as with `@property`. The same applies for setter. You can even use the dot notation. – Sulthan Feb 18 '13 at 15:39
  • 2
    @Sulthan That is almost correct, a part from the fact that the runtime makes this distinction. A *fake* property like this one, won't be for instance listed when using `class_copyPropertyList`. See my answer for a different approach. – Gabriele Petronella Sep 05 '13 at 13:29
  • @GabrielePetronella That's true but in 99% of cases the difference doesn't matter. Giving you a +1 anyway cause it's a nice solution :) – Sulthan Sep 05 '13 at 13:31
  • 1
    @Sulthan Agreed. Probably the greatest advantage of my solution is autocompletion (and it's shorter too ;) ). – Gabriele Petronella Sep 05 '13 at 13:33
  • 2
    Having it be a real property makes a difference if you use the class with Swift. If it is not a property you can't use dot-notation in Swift. – ThomasW Jul 07 '14 at 05:02
5

Is there any reason this needs to be a property? I'd just declare the setter as a method and use the normal [foo setVar:bar] syntax.

grahamparks
  • 16,130
  • 5
  • 49
  • 43