13

I have following code:

-(id) initWithCoordinate:(CLLocationCoordinate2D)c title:(NSString *)t
{
    self = [super init];

    if (self)
    {
        coordinate = c;
        self.title = t;
    }

    return self;
}

where coordinate is:

@property (nonatomic, readonly) CLLocationCoordinate2D coordinate;

I had two questions:

  • is it OK to assign to a property that is readonly?
  • should not coordinate have self before it? (e.g., self.coordinate = c).

ps. I don't get any errors using this code - and it is an example from a book.

  • 1
    if you have readonly property you can't assign any thing to it, compiler will give an error in that case. – Suryakant Sharma Jul 18 '13 at 11:09
  • You should get a compile issue when assigning to a readonly, is it set readwrite somewhere else? Are you synthesising? – Wain Jul 18 '13 at 11:09
  • @Wain: yes, I did synthesize. I don't get compiler issues –  Jul 18 '13 at 11:10
  • 1
    you should not use properties in init methods: http://qualitycoding.org/objective-c-init/ – vikingosegundo Jul 18 '13 at 11:11
  • 1
    and here: http://developer.apple.com/library/ios/#documentation/cocoa/conceptual/ProgrammingWithObjectiveC/EncapsulatingData/EncapsulatingData.html%23//apple_ref/doc/uid/TP40011210-CH5-SW11 – vikingosegundo Jul 18 '13 at 11:17
  • @H2CO3: I am not aware, why it is bullshit. can you elaborate? – vikingosegundo Jul 18 '13 at 11:20
  • If the property is readonly and it's synthesized, you can assign it from inside the class (but don't use dot notation, use synthesized accessors). Your code looks fine. – Ramy Al Zuhouri Jul 18 '13 at 11:22
  • @vikingosegundo I think I've already, well, ranted about this. In the case of PODs (where you don't need to manage memory), it is OK, but once memory management is added to the mixture, you'll be pretty much 1. not knowing the exact reference counts of the property's backing ivar because the exact implementation of auto-synthesized getters and setters is an implementation detail, 2. yet you will be guessing (and it's even a reasonable expectation to do so!) that it has however many refcounts you gave it. Because of the interference of these two behaviors, you can easily leak and crash the app. –  Jul 18 '13 at 11:26

8 Answers8

16

You should write: self.coordinate = c which is equal to [self setCoordinate:c] - calling setter method. But you can't do this because you will get Assignment to readonly property error. Read-only properties don't have setter methods.In your case you just set the ivar which backs the property directly and it is well documented behavior. The ivar name will be the property name prefixed with an underscore BUT as in your case you have an explicit @synthesize as you said, so the ivar will have the same name and that's why you haven't any compiler issues. It is possible for the property to be read-only publicly, but be writeable by the class - this involves either declaring a setter method in a class extension or redeclaring the property in the extension. For this you can refer this post: Objective-C property that is readonly publicly, but has a private setter

Community
  • 1
  • 1
Oleksandr Karaberov
  • 12,573
  • 10
  • 43
  • 70
3
  • is it OK to assign to a property that is readonly?

    Yes, its okay if you don't want a property to be mutated outside its containing instance.

    eg: count property of an array, here count is a property that is dependent on the number of objects retained by the array. So it shouldn't be modified from outside the Array object.

  • should not coordinate have self before it? (e.g., self.coordinate = c).

    If read only, you can't modify your property via a setter method.

    self.coordinate translates to [self setCoordinate:] which is not permitted as read only prevents setter methods from modifying the property.

So you should directly set the ivar, and this can be done only from inside the object for which readonly property is defined.

i.e

_coordinate = value; //or coordinate = value if you have synthesized it. 

If you are curious,

self.propertyName && self.property = indirectly calls getter and setter method.

And in implementation, setters and getter help the _ivars to be public-ally accessible is the property is public.

- (void)setProperty(value) //self.property = value
 {
    _property = value;
 }

- (id)property  //self.property
  {
     return _property;
  }
Community
  • 1
  • 1
egghese
  • 2,193
  • 16
  • 26
  • I see, so in Obj. C it is Ok to refer to instance variables directly too, right, e.g., `myVariable = 13;` (without self) –  Jul 18 '13 at 11:31
  • you can't unless you have @synthesized it. Otherwise you need to address it as _varName – egghese Jul 18 '13 at 11:35
1

you cannot assign value to variable with readonly property, but from iOS6, the @synthesize can be added automatically, so you can use ivar to replace it. Like _test = @"test" to replace self.test = @"test" if the property of test is readonly.

harryyan
  • 11
  • 2
0
  1. No that is not ok. Proper way to assign readonly is like this:

    - (CLLocationCoordinate2D)coordinate {
    
        //create the struct and return it.
    
        return value;
    
    }
    
  2. No it is the other way around. You should set title like this:

    _title = t;
    
Desdenova
  • 5,326
  • 8
  • 37
  • 45
0

The line coordinate = c; is not assigning the property, it's assigning the instance variable which has the same name. It is not possible to assign a readonly property, that's what “read only” means. If you change it to self.coordinate = c you will get an error, unless this property is redeclared as readwrite in class extension.

hamstergene
  • 24,039
  • 5
  • 57
  • 72
0

is it OK to assign to a property that is readonly?

If you use synthesized accessors like you're doing, it's perfectly fine.

should not coordinate have self before it? (e.g., self.coordinate = c).

self.coordinate is a shortcut for the non synthesized accessor. This setter is visible from outside the class, so since the property should be readonly for class users, you get a compiler error if you try to access readonly properties with the dot notation. Your code is correct.

Ramy Al Zuhouri
  • 21,580
  • 26
  • 105
  • 187
0

is it OK to assign to a property that is readonly?

If you @synthesize coordinate;, then the backing ivar will be named coordinate. If the property is auto-synthesized, it will be named _coordinate.

If your intent is to assign to the underlying instance variable within the initializer, that is fine (e.g. coordinate = c or _coordinate = c).

If you want to set it using the setter (e.g. [self setCoordinate:c] or self.coordinate = c; you would need to implement the setter yourself or synthesize its definition (e.g. by declaring the property readwrite in your class continuation).


should not coordinate have self before it? (e.g., self.coordinate = c).

No, it should not. Use direct access in a partially constructed state, such as an initializer or -dealloc.

Given the properties:

@property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
@property (nonatomic, copy, readwrite) NSString * title;

Your initializer should take the form:

- (id)initWithCoordinate:(CLLocationCoordinate2D)c title:(NSString *)t
{
 self = [super init];

 if (self)
 {
  _coordinate = c;
  _title = t.copy; // note: copy/ownership semantics match property declaration
 }

 return self;
}

@end
Community
  • 1
  • 1
justin
  • 104,054
  • 14
  • 179
  • 226
0

I've seen tricky people do this....

Source.h

@property (readonly) BOOL  isRunning;

Source.m

- (void) blahBlahBlah { ...
   self->_isRunning = YES; ...

There is very little documentation that I can find about these types of accessors... I'm pretty sure it is just a standard C construct... one which I am not very familiar... But this is a way to go if your mastery of the subject.. is better than mine...

Alex Gray
  • 16,007
  • 9
  • 96
  • 118