iOS Setters and Getters and Underscored Property Names - ios

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.

Related

Difference when declare variable

I have a class below:
#interface Person : NSObject {
NSString *_firstname;
}
#property NSString *firstName;
#end
#implementation Person
#synthesize firstname;
#end
This will declare three variables: firstname, self.firstname and _firstname
What is the difference between the three variables and how do you using with each case?
In modern Objective-C you don't need to create instance variable if you already synthesizing properties.
From what you write it appears that you are confusing properties and ivar.
Properties create getters and setters to your ivars, but they are not ivars, they are methods that access you ivars to set or get their values.
Your class can be sum up like that:
#interface Person : NSObject
#property NSString *firstName;
#end
#implementation Person
#end
At compile time this will ensure that you can access your ivar using methods and name your ivar as _firstName.
Dot notation create access to properties so self.firstName (using ARC and default property option -nonatomic,strong-)calls that method
- (NSString*)firstName
{
return _firstName;
}
While calling self.firstName = #"foo"; calls:
- (void) setFirstName:(NSString*)name
{
if (_firstName == name) {
return;
}
_firstName = name;
}
Underlining implementation could be a little different.
The first one NSString *_firstname; is an instance variable. The #property is a property which is syntesized (you don't have to manually synthesize properties in modern Objective-C). When you declare a property you can access its instance variable with _propertyName or with self.propertyName.
It is up to you whether you declare your variables as instance variables or as properties but it is more common and suggested to declare them as properties (using properties you can have access to getters and setters, which means that you can run code before the value of the property will be set or will be read).
You can chain instance with property using
#interface Person : NSObject {
NSString *_firstname;
}
#property NSString *firstName;
#end
#implementation Person
#synthesize firstName = _firstname;
#end
Both pointers are pointing same instance now.

Calling setter method of a property on its instance varaible

I have 3 properties id_1, id_2, id_3
id_2 and id_3 are derived from id_1
id_1 can have public getter/setter
id_2 and id_3 only have readonly access.
So I need to override the setter for id_1 to set id_2 and id_3 for valid id_1
id_1 could come from NSUserDefaults which means in init, I need to set id_2 and id_3
So, I wanted to call setter of id_1 from init as if I was calling from outside of the class using ivar _id_1
That would give me a single implementation to set all the ids both during init phase or if called externally
My question is on following two lines that I have in my code as I am calling the setter for id_1 with argument as ivar _id_1
_id_1 = id_from_ns_user_defaults
[self setid_1:_id_1];
In few other SO articles I saw concerns around recursive loops
Custom Getter & Setter iOS 5
.h file
#interface UserCredentials : NSObject
#property (strong, nonatomic) NSString *id_1;
#property (readonly) NSString *id_2;
#property (readonly) NSString *id_3;
#end
.m file
#interface UserCredentials ()
#property (readwrite) NSString *id_2;
#property (readwrite) NSString *id_3;
#end
#implementation UserCredentials
- (id)init
{
self = [super init];
if (self) {
/* Is this valid in Objective-C */
_id_1 = id_from_ns_user_defaults
[self setid_1:_id_1];
}
return self;
}
- (void)setid_1:(NSString *)id
{
if (id && ![id isEqualToString:#""]) {
_id_1 = id;
_id_2 = convert2(_id_1);
_id_3 = convert3(_id_1);
}
}
#end
Your highlighted concern is around creating an assignment cycle. Because you are assigning to the ivar itself, you will not be creating a cycle. Remember that manipulating the ivar will not cause your getter/setter to be called -- it's just a pointer like any other pointer.
Setting an ivar to itself is not an issue unless you have done something in your setter implementation to make it an issue. In non-ARC systems, you could easily create a bad access error by implementing your setter with the wrong order:
- (void)setVal:(NSObject *)val {
[_val release];
_val = [val retain];
}
This is countered by using autorelease instead (or assigning to a temporary variable and releasing after the retain).
Most of the time, though, your setter won't be doing anything destructive when passed a new (or same) value. Your implementation does not do this.

Is it recommended to define ivars for readonly synthesized properties?

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.

Regarding #synthesize in iOS6+

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.

iOS Setter Getter

I tried to assign a value to recordingStatus -
ie recordingStatus = 1
But it doesn't go into the setter which i want some custom code.. what's wrong with my code?
Thanks.
Pier.
In file.h
#property (strong, nonatomic) IBOutlet UILabel *recordingStatusText;
#property (nonatomic)int recordingStatus;
....
In file.m
/* -------------------- Property Setter and Getters ----------------------*/
#synthesize recordingStatus;
- (int) getRecordingStatus {
return recordingStatus;
}
- (void) setRecordingStatus:(int)status
{
[_recordingStatusText setText: #"Just testing!"];
recordingStatus = status;
}
To set and get your property, you should use self.property = newValue;.
OVERRIDING SETTERS AND GETTERS
For getters you don't need to write 'get' in the method signature. So, your getter method uses the wrong name. If you want to override it, the method should be
-(int) recordingStatus {
// Custom Getter Method
return _recordingStatus;
}
In the case of ints, Objective-c wants to see your setter and getter methods in the format of
-(void)setValue:(int)newValue;
-(int)value;
Can you show the code where you call the setter? I'm assuming you're accessing the ivar directly by doing something like this (assuming your ivar is named recordingStatus):
recordingStatus = 1
Instead try this:
self.recordingStatus = 1

Resources