Eg:
//Myclass.h
#property(nonatomic, strong) NSString *name;
//MyClass.m
//#synthesize name = _name
So I know that we don't need to use #synthesize any more from iOS6+. The compiler automatically creates getters and setters for me.
But I don't understand is when to use self.name = #"Testing" and when to use _name = #"Testing"?
Should _name = #"Testing" be ever used?
If yes, when? When should an iVAR be used at all?
Also if i want to write my own getter and setter do i need to write #synthesize or can i just write my getter and setter?
Thanks for your help!
Normally, you only use instance variables in init methods, getters and setters, and dealloc. There are exceptions of course, but this is a good rule of thumb.
If you write both your own getter and setter (or in the case of a readonly property and you write the getter), you have to synthesize your property yourself. In all other cases, the property is auto-synthesized.
Related
I was doing some research on the differences #dynamic and #synthesize, so I make a small (simple) example:
#interface Classe : NSObject
#property (nonatomic) int value;
#end
#implementation Classe
#synthesize value;
#end
int main(int argc, const char * argv[]) {
#autoreleasepool {
Classe *cl = [[Classe alloc] init];
cl.value = 50;
NSLog(#"%d",cl.value);
}
return 0;
}
From what I understand with this my example, is that the 'synthesize' creates behind the scenes getters and setters methods, and as we have seen above I only do cl.value = 50;.
Now, let's talk about #dynamic, I hear that
is merely a way to inform the system not to generate getters/setters
for the thing, that you (or someone else) will provide them for you.
Okay, if in my example above I change the #synthesize to #dynamic the application will give error returning the following message:
unrecognized selector sent to instance 0x10010eeb0
This was because it was said that the compiler does not create the getters and setters methods, knowing this, how could I create the getters and setters methods manually?
Well, you simply do. If your property has a name
#property (nonatomic) int value;
Then in your implementation you just define methods:
-(int)value {
//your getter here
}
-(void)setValue:(int)newValue {
//Your setter here
}
#dynamic value; tells compiler that it should NOT make default accessors.
But you don't need #dynamic to do it. You can just write a getter and a setter. You might need #synthesize though. Because if you specify your own getter and setter, the compiler won't generate an instance variable (_value) for you. To make it do it (if you need it), you will need #synthesize.
More about it: SO: Getters, setters and underscore property names.
I have come to find that many of the times in which I want to have a synthesized readonly property, I merely implement the getter method of that property in terms of other variables with no need for an ivar, for example (Note: I am defining ivars in the interface because I am using OmniGraffle UML software and it does not recognize ivars auto-generated by synthesized properties):
#interface Editor : UIView {
BOOL _wordWrap;
BOOL _showLineNumbers;
NSDictionary *_options;
}
#property (nonatomic) BOOL wordWrap;
#property (nonatomic) BOOL showLineNumbers;
#property (nonatomic, copy, readonly) NSDictionary *options;
#end
#implementation Editor
#synthesize wordWrap = _wordWrap;
#synthesize showLineNumbers = _showLineNumbers;
#synthesize options = _options;
- (NSDictionary *)options {
return #{
#"WordWrap" : [NSNumber numberWithBool:self.wordWrap],
#"ShowLineNumbers" : [NSNumber numberWithBool:self.showLineNumbers],
};
}
#end
In the above Editor class, is it necessary for me to define the _options ivar in the header definition and more importantly does the auto-generated ivar take up memory or space in the symbol table? Also, would it be more efficient to use copy, retain, or no value in this case? Just curious.
First: stop putting your ivar declarations in your #interface. They belong in your #implementation. See this answer for a detailed explanation.
Anyway, given what you've written, your #synthesize options = _options has no effect.
That #synthesize has two possible effects:
It adds an instance variable named _options, if your class doesn't have one.
It generates a getter method, options, that returns the value of _options, if your class doesn't have a method named options.
Since you manually defined the instance variable and the getter, the #synthesize does nothing. You can remove it entirely without changing the meaning of your program.
Specifying copy on a readonly property has no effect. The copy and retain (or, more properly under ARC, strong) attributes only affect the generated setter method, and the compiler doesn't generate a setter for a readonly property. (If you change the property to readwrite in a class extension, then copy matters.)
Yes, the _options ivar takes up both memory (for each instance of Editor) and space in the symbol table.
Since you're not using the _options ivar, you should delete it entirely. You should also delete the #synthesize entirely, so the compiler doesn't generate the _options ivar for you.
What is the best practice?
Declare the property as nonatomic
Create custom getter too
Another possibility that I'm not aware of
and why prefer one of this solution rather another.
In most of the cases, you just need to provide implementation for setter and declare the property as nonatmoic. This will generate ivar with underscore prefix and you need to set the value in setter method.
You don't normally need to override getter unless you have special logic in getter or the property need to be atomic.
If you do want to provide getter (along with setter), you may need a backend ivar either by declare it in #implementation{ /*here*/ } or use #synthesize to generate one.
In case for atomic property:
#interface MyClass : NSObject
#property (atomic) id object; // atomic is default attribute
#end
#implementation MyClass
#synthesize object = _object; // to create ivar
- (id)object {
#synchronized(self) { // or use lock / atomic compare-and-swap
return _object;
}
}
- (void)setObject:(id)obj {
#synchronized(self) { // or use lock / atomic compare-and-swap
_object = obj;
}
}
#end
So I have a NSString property named description, defined as follows:
#property (strong, nonatomic) NSMutableString *description;
I'm able to refer to it as _description when I define the getter, as follows:
- (NSString *)description
{
return _description;
}
However, when I define a setter, as follows:
-(void)setDescription:(NSMutableString *)description
{
self.description = description;
}
It breaks _description from the aforementioned getter (undeclared identifier). I know I can probably just use self.description instead, but why does this happen?
#borrrden 's answer is very good. I just want to add some details.
Properties are actually just syntax sugar. So when you declare a property like you did:
#property (strong, nonatomic) NSMutableString *description;
It is automatically synthesized. What it means: if you don't provide your own getter + setter (see borrrden's answer), an instance variable is created (by default it has name "underscore + propertyName"). And getter + setter are synthesized according to the property description that you provide (strong, nonatomic).
So when you get/set the property, it is actually equal to calling the getter or the seter. So
self.description;
is equal to [self description].
And
self.description = myMutableString;
is equal to [self setDescription: myMutableString];
Therefore when you define a setter like you did:
-(void)setDescription:(NSMutableString *)description
{
self.description = description;
}
It causes an infinite loop, since self.description = description; calls [self setDescription:description];.
1) NSObject already has a method named description. Pick another name
2) Your setter is an infinite loop
But as to your actual question: The compiler will only autogenerate backing variables if you do not override both methods.
P.S. No, you can't just "use self.description instead" because then your getter would also be an infinite loop.
This question already has answers here:
Declaration/definition of variables locations in ObjectiveC?
(4 answers)
Closed 9 years ago.
What is the proper way to work with instance variables (declared on interface), their #property and #synthesize, when working in ARC project? What I now do is following:
SomeClass.h:
#interface SomeClass : NSObject {
NSString *someString;
}
#property(nonatomic, copy) NSString* someString;
and SomeClass.m:
#implementation SomeClass
#synthesize someString;
- (void)someMethod {
self.someString = #"Foobar";
}
The thing is that there are other approaches that works, like using just the #property:
SomeClass.h:
#interface SomeClass : NSObject
#property(nonatomic, copy) NSString* someString;
Accessing the someString without self:
SomeClass.m:
#implementation SomeClass
#synthesize someString;
- (void)someMethod {
someString = #"Foobar";
}
etc. I'm new to Objective-c, I'm used to Java. What is the proper way to work with attributes then? I understand that special cases will have special behavior, but what is the best approach in general? (by general I mean I want to access the variable from the class itself and from "outside" and I want ARC to still work correctly, eg. I don't have to worry about memory leaks)
For simple properties, you don't need the instance variable declaration or the #synthesize. The clang compiler will generate both for you by default. So you could write this in the header:
#interface SomeClass : NSObject
#property (nonatomic, copy) NSString *someString;
#end
And the implementation:
#implementation SomeClass
- (void)someMethod {
self.someString = #"Foobar";
}
#end
Avoid direct instance variable access unless you are in the -init method or overriding the setter. Everywhere else you should use the dot syntax (self.someString). If you do need access to the instance variable, the default synthesize will create an underscore-prefixed ivar, e.g. _someString.
Note that for classes with mutable versions like NSString/NSMutableString and NSArray/NSMutableArray the standard practice is to use a copy property. If you use strong on a string or array, the caller might pass in a mutable version and then mutate it from under you, causing hard-to-find bugs.
Check out this SO post for information about ARC.
(Edited) The "strong" attribute tells ARC to keep an object around until the object with the property is deallocated. You do need the "copy" attribute because an NSString property could have been passed in as an NSMutableString. The "copy" guarantees that the original object will be kept around. Again, I apologize for the incorrect/misleading information I originally had here.
The reason you can access the instance variable someString as well as the property self.someString is that the #synthesize someString line creates an instance variable for the property and creates methods for getting and setting the value of it. However, it is recommended that you use the property instead of directly using the instance variable because by using the instance variable, you cannot let the parent object know that you've changed one of its properties.