21

I know now the new Objective-C compiler lets you not need to synthesize your properties anymore. I have one file that has two classes in it. My .h for a simple helper class looks like this:

@interface ViewFrameModel : NSObject

@property (nonatomic, strong) UIView *view;
@property (nonatomic, assign) CGRect frame;

- (id)initWithView:(UIView *)view frame:(CGRect)frame;

@end

In the same .h file, for my other class (class 2), I have:

@property (nonatomic, strong) ViewFrameModel *viewFrameModel;

In class 2.m, I can do this:

- (void)setViewFrameModel:(ViewFrameModel *)viewFrameModel {
    _viewFrameModel = viewFrameModel;        
    [self pushViewFrameModel:viewFrameModel];
}

This works fine with no complaints from the compiler, however, when I add this:

- (ViewFrameModel *)viewFrameModel {
    return _viewFrameModel;
}

I get two complaints, one on the first method setViewFrameModel:

"Use of undeclared identifier _viewFrameModel, did you mean viewFrameModel"

And the other on return _viewFrameModel:

"Use of undeclared identifier _viewFrameModel, did you mean viewFrameModel" "Reference to local variable viewFrameModel' declared in enclosing context"

Why do I get these errors when I add in the

- (ViewFrameModel *)viewFrameModel {
    return _viewFrameModel;
}

method? I want to override this method with some custom info, but it's complaining at me :-. Thoughts? TIA.

iDev
  • 23,310
  • 7
  • 60
  • 85
Crystal
  • 28,460
  • 62
  • 219
  • 393
  • 1
    "I know now the new Objective-C compiler lets you not need to synthesize your properties anymore" - **Thank you** for saying "compiler" and not "Xcode". Finally, somebody! –  Jan 08 '13 at 20:08

3 Answers3

35

If you override both the setter and the getter, the compiler will not automatically create the instance variable for you anymore. You can add it to your class implementation like so:

@implementation ClassName {
    ViewFrameModel *_viewFrameModel;
}
...
@end
Carl Veazey
  • 18,392
  • 8
  • 66
  • 81
5

Here is the results of some testing I did last year: iOS automatic @synthesize without creating an ivar.

In short, you need to use @synthesize or declare an iVar explicitly.

Community
  • 1
  • 1
Jeffery Thomas
  • 42,202
  • 8
  • 92
  • 117
  • 1
    You do not *need* to use @synthesize. You can declare your own ivar instead. – rmaddy Jan 08 '13 at 20:18
  • 1
    Huh, I would say you don't need to declare iVars, you can use @ synthesize. I guess it's what you prefer. – Jeffery Thomas Jan 08 '13 at 20:40
  • Before the latest compiler, `@synthesize` only synthesized the setter and getter methods, not the ivar. Since the OP is providing the methods, there is no need to use `@synthesize`. It is clearer, in this case, to add your own ivar. Why use `@synthesize` when the bulk of what it does isn't being used? But, in the end, with the latest compiler, `@synthesize` will work. My main objection was to your use of the word "need" since that is in fact not true. It's an option, not a need. – rmaddy Jan 08 '13 at 20:53
  • @rmaddy No, `@synthesize` has always generated an iVar if it was not present. I've written lots of `@synthesize prop = _prop;` lines without ever needing to explicitly declare an iVar. I understand your nit about the word 'need', I'll change the wording. – Jeffery Thomas Jan 08 '13 at 21:56
3

To summarize the answers:

If you override both the setter and the getter, the compiler will not create the instance variable for you.

Why? In that case, the compiler assumes that the property is dynamic: that it might be a property that relies on other properties for storage / computation, or that it will be created in other ways, for example, at runtime using Objective-C runtime functions.

To help the compiler understand the situation better there are two potential solutions:

@implementation Class
@synthesize property = _property;
...
@end

or

@implementation Class {
    PropertyClass *_property;
}
...
@end
Rob
  • 415,655
  • 72
  • 787
  • 1,044
kgaidis
  • 14,259
  • 4
  • 79
  • 93