When should I use @synthesize explicitly?
Asked Answered
L

7

92

As far as I know, since XCode 4.4 the @synthesize will auto-generate the property accessors. But just now I have read a sample of code about NSUndoManager, and in the code it noticed that the @synthesize is added explicitly. Like:

@interface RootViewController  ()

@property (nonatomic, strong) NSDateFormatter *dateFormatter;
@property (nonatomic, strong) NSUndoManager *undoManager;

@end

@implementation RootViewController
//Must explicitly synthesize this
@synthesize undoManager;

I am feeling puzzled now... When should I add @synthesize explicitly to my code?

Lunar answered 5/11, 2013 at 8:19 Comment(2)
The sample code might be old. Basically, use it unless it turns into a problem (for example, properties in delegates will not be auto-synthesized)Price
Try commenting out the @sythesize. If the code still works, then it isn't necessary.Virginiavirginie
O
198

There's a lot of answers, but also a big confusion. I'll try to put some order (or increase the mess, we'll see...)

  1. Let's stop talking about Xcode. Xcode is an IDE. clang is a compiler. This feature we are discussing is called autosynthesis of properties and it's an Objective-C language extension supported by clang, which is the default compiler used by Xcode.
    Just to make it clear, if you switch to gcc in Xcode, you won't benefit from this feature (regardless from the Xcode version.) In the same way if you use a text editor and compile using clang from the command line, you will.

  2. Thank to autosynthesis you don't need to explicitly synthesize the property as it will be automatically synthesized by the compiler as

    @synthesize propertyName = _propertyName
    

    However, a few exceptions exist:

    • readwrite property with custom getter and setter

      when providing both a getter and setter custom implementation, the property won't be automatically synthesized

    • readonly property with custom getter

      when providing a custom getter implementation for a readonly property, this won't be automatically synthesized

    • @dynamic

      when using @dynamic propertyName, the property won't be automatically synthesized (pretty obvious, since @dynamic and @synthesize are mutually exclusive)

    • properties declared in a @protocol

      when conforming to a protocol, any property the protocol defines won't be automatically synthesized

    • properties declared in a category

      this is a case in which the @synthesize directive is not automatically inserted by the compiler, but this properties cannot be manually synthesized either. While categories can declare properties, they cannot be synthesized at all, since categories cannot create ivars. For the sake of completeness, I'll add that's it's still possible to fake the property synthesis using the Objective-C runtime.

    • overridden properties (new since clang-600.0.51, shipping with Xcode 6, thanks Marc Schlüpmann)

      when you override a property of a superclass, you must explicitly synthesize it

It's worth noting that synthesizing a property automatically synthesize the backing ivar, so if the property synthesis is missing, the ivar will be missing too, unless explicitly declared.

Except for the last three cases, the general philosophy is that whenever you manually specify all the information about a property (by implementing all the accessor methods or using @dynamic) the compiler will assume you want full control over the property and it will disable the autosynthesis on it.

Apart from the cases that are listed above, the only other use of an explicit @synthesize would be to specify a different ivar name. However conventions are important, so my advice is to always use the default naming.

Opinicus answered 6/11, 2013 at 20:10 Comment(4)
If the original asker is still here, I think this answer should be accepted. It's the most complete.Mucoprotein
Properties specified in a category are also not synthesized automatically, as far as I remember. (The underlying reason is that you cannot add an instance variable in a category.)Diphenylamine
@MartinR, good point. They are not automatically synthesized, but they also cannot be manually synthesized as @synthesize in a category is forbidden (no ivar in categories, as you already noted). I'll add a note.Opinicus
But this answer does not address the specific question: WHEN should @synthesize be used? Always, never, only when certain conditions are met?Logogriph
B
24

If you do not explicitly use @synthesize the compiler will understand your property the same way if you had written

@synthesize undoManager=_undoManager;

then you will be able to write in your code things like :

[_undoManager doSomething]; // iVar
[self.undoManager doSomethingElse]; // Use generated getter

This is the common convention.

if you write

@synthesize undoManager;

you will have :

[undoManager doSomething]; // iVar
[self.undoManager doSomethingElse]; // Use generated getter

Personally I stop using @synthesize, since it's not mandatory any more. For me the only reason to use @synthesize is to link an iVar to a @property. If you want to generate specific getter and setter for it. But in the given piece of code there is no iVar, I think that this @synthesize is useless. But now I think the new question is "When to use iVar ?", and I've no other response than "never" for this one !

Bekha answered 5/11, 2013 at 8:33 Comment(9)
Agreed, I stopped using @synthesize as there is no reason to do it any more. Also the leading underscore serves as a nice visual flag to let you know you are working around the memory management and threading safety net that properties provide (which you should be skipping in init and dealloc methods).Verbality
The question was, when do you need to explicitly need to synthesize. You haven't answered that at all.Stalingrad
Exact :), for me the only reason to use @synthesize is to link an iVar to a @property. But in the given piece of code there is no iVar, I think that this @synthesize is useless. But know I think the new question is "When to use iVar ?", and I've no other response than "never" for this one :x !Bekha
I discovered today that this isn't quite true. Without the @synthesize, you're responsible for creating the backing instance variable. With it, the compiler will do it for you.Mucoprotein
And I didn't down vote anyone for this discovery. :)Mucoprotein
-1 you are completely missing the cases in which you need an explicit synthesize. Also this is a compiler feature, not an Xcode one.Opinicus
@Bekha ah, didn't know you could see that. Thanks.Stalingrad
How would I go about overriding the setter method if I used synthesize?Denbrook
@Denbrook From my understanding, synthesyze only affect the generated iVar. getter and setter should remain unchanged. In this exemple you will have - (NSUndoManager)undoManager with or without the synthesizeBekha
M
16

When should I add @synthesize explicitly to my code?

Generally, if it's required: You will probably never hit a case where it's needed.

There's one case you might find it useful, though.

Say you're writing both a custom getter and setter, but want an instance variable to back it. (For an atomic property, this is as simple as wanting a custom setter: the compiler will write a getter if you specify a setter for a monatomic property, but not an atomic property.)

Consider this:

@interface MyObject:NSObject
@property (copy) NSString *title;
@end

@implementation MyObject

- (NSString *)title {
    return _title;
}
- (void)setTitle:(NSString *)title {
    _title = [title copy];
}

@end

This will not work, because _title doesn't exist. You've specified both a getter or setter, so Xcode (correctly) doesn't create a backing instance variable for it.

enter image description here

You have two choices for making it exist. You can either change the @implementation to this:

@implementation MyObject {
    NSString *_title;
}

- (NSString *)title {
    return _title;
}
- (void)setTitle:(NSString *)title {
    _title = [title copy];
}

@end

Or change it to this:

@implementation MyObject

@synthesize title = _title;

- (NSString *)title {
    return _title;
}
- (void)setTitle:(NSString *)title {
    _title = [title copy];
}

@end

In other words, although synthesize is for practical purposes never necessary*, it can be used to define property-backing instance variables when you're providing a getter/setter. You can decide which form here you want to use.

In the past, I've favoured specifying the instance variable in the @implementation {}, but I now think the @synthesize route is a better choice as it removes the redundant type and explicitly ties the backing variable to the property:

  1. Change the property's type, and the instance variable's type changes.
  2. Change its storage qualifier (for instance, make it weak instead of strong or strong instead of weak) and the storage qualifier changes.
  3. Remove or rename the property, and the @synthesize will generate a compiler error. You won't end up with stray instance variables.

*-I know one case where it was necessary, relating to splitting functionality across categories in multiple files. And I wouldn't be surprised if Apple fixes this, or even already has.

Mucoprotein answered 5/11, 2013 at 17:42 Comment(15)
Are you sure? Did you even try? I wrote many custom setters and getters and NEVER synthesized my properties. (And I used your first example, which you said does not work)Brody
Yes, I'm sure. Code was copy-pasted from a new project. It won't work on recent versions of Xcode unless you specify nonatomic on the property.Mucoprotein
yes thats true.. but 99% of time your properties are nonatomic. So only in the rare case that your property is atomic and you want a custom getter/setter you actually need to synthesize.Brody
If you provide a custom implementation for both setter and getter, then the compiler will assume that you are taking control of the property and it won't synthesize it for you.Opinicus
I know. That's what I'm saying here. I'm not saying this is a common case, but it is a case. :)Mucoprotein
I've updated the answer to make it more clear. Thanks for the feedback, guys.Mucoprotein
The "99% of your properties are atomic" assertion is silly, btw. atomic is the default. Unless you only use properties for UI or are otherwise only used on a single thread, you're going to be using atomic properties.Mucoprotein
@StevenFished, actually I think 100% of all the properties I've ever written are nonatomic. atomic is a terrible default, since it doesn't really add much value.Opinicus
12% of my properties are atomic.Mucoprotein
Can I ask why? I never found an actual use case for an atomic property.Opinicus
Sure. :) Stuff done across different threads via GCD, primarily. That said, I think atomic properties are usually mistakes; you usually want a @synhcornized block, to wrap an entire chunk of the operation as atomic. Hopefully, a small, seldom-used chunk. :)Mucoprotein
And, looking it over, I think only about 6% of my properties SHOULD be atomic. Stupid default!Mucoprotein
Since atomic doesn't accomplish thread-safety, but has a huge impact on performance, I generally prefer avoiding atomic properties altogether and guaranteeing data integrity using application design. I guess it's a personal decision. Surely atomic as default is a bad design choice.Opinicus
I agree with you there, though I can understand why Apple initially thought it was a good idea. The real pain is that atomic was not added as a property specifier until later. Now that it's there, you might find the warning flag CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES interesting.Mucoprotein
@StevenFished real nice, I wasn't aware of it! Thanks youOpinicus
S
10

OK, when you create a property...

@property NSString *name;

Xcode will auto synthesise an iVar as if you had written...

@synthesize name = _name;

This means you can access the property with...

self.name;
// or
_name;

Either will work but only self.name actually uses the accessor methods.

There is only one time that auto synthesise does not work: If you overwrite but the setter AND the getter method then you will need to synthesise the iVar.

You are fine if you just override the setter or if you just override the getter. But if you do both then the compiler won't understand it and you will need to synthesise it manually.

As a rule of thumb though.

Don't make iVars. Just use the property. Don't synthesise it.

Stalingrad answered 5/11, 2013 at 17:47 Comment(7)
There are more cases in which the autosynthesis won't be performed. Check out my answer.Opinicus
@GabrielePetronella can you list those cases succinctly for average reader?Cadmium
@DanRosenstark this is irrelevant to anyone programming now. You really should be using Swift. And TBH I think the whole synthesis thing isn’t even a thing in ObjC anymore. Unless you’re working on a code base that is 5+ years old.Stalingrad
@Stalingrad yes, it's still a thing in the case you mention in your answer (where you override both the setter and the getter). And as to Objective-C not being "relevant to anyone programming now" please call my day job and tell them. Also tell Facebook, Google and Apple, who are using Objective-C internally to great effect.Cadmium
I'm sure this is true without Quora, but anyway: quora.com/…Cadmium
@DanRosenstark which is why I said “unless you’re working on a codebase that’s over 5 years old”. Also, to use Facebook as an example is a bit misguided. They do everything custom and in house (even their source control and IDE).Stalingrad
Agreed on all counts. Thanks again for putting this answer here, as it's correct.Cadmium
Z
1

Property synthesis is required when a property is declared in a protocol. It will not be automatically synthesized in an implementing interface.

Zajac answered 6/11, 2013 at 20:20 Comment(2)
true, but it's just one case. You might want to elaborate more.Opinicus
@GabrielePetronella It's the only one I can think of in this late hour. =]Blanketyblank
G
0

Thanks for clarifying that. I had a similar problem.

@synthesize firstAsset, secondAsset, audioAsset;
@synthesize activityView;

So now, having commented them out, I went through and replaced each occurrence with, for example

self.firstAsset It seems I could also use firstAsset, but I find I miss seeing the "" too often.

Garneau answered 6/5, 2014 at 15:41 Comment(0)
T
-1

Xcode doesn't require an explicit @synthesize declaration.

If you don't write @synthesize its the same as doing :

@synthesize manager = _manager;

The sample code might've been old. They'll update it soon.

You can access your properties like :

[self.manager function];

This is Apple's recommended convention. I follow it, and I recommend that you do too!

Treasurehouse answered 5/11, 2013 at 8:38 Comment(3)
Statement [_manager function] will NOT access the property, instead it will access the underlying ivar directly.Oddfellow
@Oddfellow If you are to nitpicking, you should be precise. The property consists of a couple of things, including the ivar. So it's better to say that [_manager function] does not use accessors of the property.Madsen
@NikolaiRuhe You are right Nikolai, I should have been more precise. ;)Oddfellow

© 2022 - 2024 — McMap. All rights reserved.