可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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?
回答1:
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...)
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.
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.
回答2:
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 !
回答3:
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.
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:
- Change the property's type, and the instance variable's type changes.
- Change its storage qualifier (for instance, make it weak instead of strong or strong instead of weak) and the storage qualifier changes.
- 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.
回答4:
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.
回答5:
Property synthesis is required when a property is declared in a protocol. It will not be automatically synthesized in an implementing interface.
回答6:
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.
回答7:
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!