33

I want to override the getter and setter in my ObjC class using ARC.

.h File

@property (retain, nonatomic) Season *season;

.m File

@synthesize season;


- (void)setSeason:(Season *)s {
    self.season = s; 

    // do some more stuff
}

- (Season *)season {
    return self.season;
}

Am I missing something here?

alex
  • 4,922
  • 7
  • 37
  • 51
  • Note that this pattern leads to madness; in particular, it means that `setSeason:` must always be an atomic, integral, operation on your data model. If your code were to evolve such that there was another property whose value was dependent on `season`, then you are left with an ordering dependency ("I must set 'other' before I call `setSeason:` because `setSeason:` has business logic that depends on 'other'). Best to keep setter/getter stupid simple and keep the business logic separate. – bbum Jan 04 '12 at 18:55
  • Well in my case, I'll just update the view with new data from the `season`... – alex Jan 08 '12 at 12:20
  • 2
    But if you keep the setter/getter stupid simple and keep the business logic separate you've just moved the problem. Now you'd have to remember that every time you call `setSeason:` you also have to call `someBusinessLogicBasedOnSeason:` and you still have to wonder if you need to do all of that before or after you set other. – honus Jul 24 '12 at 04:19
  • A good pattern is using setter to invalidate data, e.g. there are two setters `setSeason:`, `setYear:` and they both do `_seasonalDataNeedsUpdate = YES;`. Real update happens later, if still necessary (e.g. if user did not cancel). This takes care of order and ensures we do not pull the same information several times. – ilya n. Sep 20 '13 at 13:06
  • Oh my god ilya, thank you so much! I was literally pulling my hair wondering why the _ notation sometimes work and sometimes doesn't. – Ben May 21 '14 at 11:44

3 Answers3

88

Yep, those are infinite recursive loops. That's because

self.season = s;

is translated by the compiler into

[self setSeason:s];

and

return self.season;

is translated into

return [self season];

Get rid of the dot-accessor self. and your code will be correct.

This syntax, however, can be confusing given that your property season and your variable season share the same name (although Xcode will somewhat lessen the confusion by coloring those entities differently). It is possible to explicitly change your variable name by writing

@synthesize season = _season;

or, better yet, omit the @synthesize directive altogether. The modern Objective-C compiler will automatically synthesize the accessor methods and the instance variable for you.

jlehr
  • 15,557
  • 5
  • 43
  • 45
  • I want to meet the genius who made `self.season = s` be translated to `[self setSeason:s]` – Renato Lochetti Aug 22 '13 at 15:23
  • 1
    @RenatoLochetti that's just how dot notation works. What would you rather the method be called? – aopsfan Aug 26 '13 at 00:08
  • 1
    It should be better if it just access the attribute. Two different things: access the attribute and call setter method. – Renato Lochetti Aug 26 '13 at 11:28
  • 5
    In Xcode 5, if you provide both custom getter and setter, system no longer synthesizes the member variable. You must use @synthesize to do this. It is no longer optional as you have suggested. – RajV Nov 12 '13 at 20:04
16

If you are going to implement your own getter and setter, you'll need to maintain an internal variable:

@synthesize season = _season;

- (void)setSeason:(Season *)s {
    // set _season
    //Note, if you want to retain (as opposed to assign or copy), it should look someting like this
    //[_season release];
    //_season = [s retain];
}

- (Season *)season {
    // return _season
}
Jeremy
  • 8,902
  • 2
  • 36
  • 44
  • Nice, thanks that did the job. Would you recommend using `_season` instead of `self.season` all the time then? – alex Jan 04 '12 at 17:13
  • The _ (underscore) is a matter of preference, but makes it clear that it's an internal variable. – Jeremy Jan 04 '12 at 17:18
  • 1
    Well the internal variable `season` is always there. The only thing `season = _season` does is renaming this variable. This is however not necessary. @jlehr explained how this works. – GorillaPatch Jan 04 '12 at 17:20
  • 1
    awesome you saved me 2 days of tweaking my code. especially this bit //Note, if you want to retain (as opposed to assign or copy), it should look someting like this //[_season release]; //_season = [s retain]; – user431791 Dec 03 '12 at 13:08
  • Note that the internal variable actually defaults to `_season`, `@synthesize season = _season` is unnecessary. – Soup Apr 04 '13 at 04:41
5

The thing you’re missing is that the Objective-C compiler basically turns the self.foo = bar syntax into [self setFoo:bar], and self.foo into [self foo]. Your methods, as currently implemented, are calling themselves. As Jeremy suggests, you need to implement them such that the setter actually assigns the value it’s called with to an instance variable on your class and the getter returns the value of that instance variable.

Noah Witherspoon
  • 57,021
  • 16
  • 130
  • 131