In my implementation I have getters and setters like below. I want to use properties and synthesize the getters and setters but have a few questions.
- (NSString *)title {
return title;
}
- (void)setTitle:(NSString *)value {
if(title != value) {
[title release];
title = [value retain];
}
}
If I was to convert that to a property, what attributes would I use? Am I right in thinking:
readwrite so both getters and setters are present
retain so that it increase the retain value of the value string so the object don't lose it.
Am I right with the above?
One final thing. I have the method below ...
- (void)setReleaseDate:(NSString *)value {
// YYYY-MM-DD HH:MM:SS +HHMM
if([releaseDate description] != value) {
[releaseDate release];
releaseDate = [[NSDate alloc] initWithString:value];
}
}
Am I right in thinking I still have to include that method because it contains code that the synthesized getter would not include?
Thanks.
For your title property, you can declare it in your class interface as follows:
#property (nonatomic, retain) NSString* title;
Which is the same as the following:
#property (readwrite, nonatomic) NSString* title;
readwrite is a default setting. Most of the time you will want setters for your properties, so for the times when you don't you would use the non-default readonly to specify this.
The nonatomic part basically means that the accessors will be faster, and is typically used. You can find out more information about this here: What does the property "Nonatomic" mean?.
For your second question, you can implement your own accessors if you wish. If you do this then it kind of 'overrides' the accessor that would be generated by Objective-C. Remember that you have to keep to the naming conventions. So in your example, the "setReleaseDate:" method you've defined would be used for the setter method for the property "releaseDate" - which is completely correct! :) The problem you have though is that you're passing an *NSString** to set the date, which means that this method won't override the default setter that would be used if you synthesized the property. You have to pass a value of the same type as the one you're setting as the single argument, so for this case you would have to pass an *NSDate**.
You must also ensure that if you provide your own implementation of an accessor that it does what is declared in the interface. I presume your releaseDate property should be declared as retain.
Your assertion about using readwrite as well as retain is correct as it would create semantically equivalent code to what you have posted.
The releasedate property setter can't be synthesized as you're transforming a NSString into a NSDate to store it, that also avoids common issues with NSString properties, for which you'd better use copy to avoid problems with NSMutableString.
Other than that, your code is fine, except that for string comparison you may want to replace the simple pointer check != with isEqualToString, see Comparing Strings in Cocoa.
It is common, though not always required, to use copy semantics for NSString properties, to avoid issues with NSMutableString objects being changed behind your back.
Otherwise, you seem to be pretty much on top of it.
Related
I have written a setter that is not working as expected. I am reading in statistics from a file and populating the properties of my SVTeam object with these stats. However some of the properties need to be calculated (as they are not supplied in the files). One of these properties holds the home winning percentage for a given team. I do not need to supply an argument for the setter. Two questions:
Since I'm NOT supplying an argument in my setter is it still truly a setter in an objective-c sense?
Even it if is not a true setter why does the code below still leave the properties as null?
SVTeam.h
#interface SVTeam : NSObject
#property (weak, nonatomic) NSNumber *homePercentage;
...
...
SVTeam.m
#import "SVTeam.h"
#implementation SVTeam
#synthesize homePercentage = _homePercentage;
...
...
-(void) setHomePercentage
{
float wins = [_homeWins floatValue];
float losses = [_homeLosses floatValue];
float ties = [_homeTies floatValue];
float winPercentage = wins / (wins+losses+ties);
self.homePercentage = [NSNumber numberWithFloat:winPercentage];
}
Since homePercentage is a calculated value based on other properties you could make it a readonly property and you would have your calculation logic in the getter instead. If you leave it as a setter then your consumers would have to make sure to call the setter first and call the getter to retrieve the value.
#property(nonatomic,readonly) NSNumber *homePercentage;
And your getter definition would be
- (NSNumber *)homePercentage
{
...
return [NSNumber numberWithFloat:winPercentage];
}
To expand on Garfield81's answer:
If you want to override the setter synthesized by clang for you homePercentage property, you need to implement -(void)setHomePercentage:(NSNumber *)homePercentage; in your class.
Apple documentation on properties.
To answer your two questions:
1) since I'm NOT supplying an argument in my setter is it still truly a setter in an objective-c sense?
No. The synthesized setters takes an unique argument of the same type of the propery and are named set<CapitalizedPropertyName>. What you did is declare a new method.
2) even it if is not a true setter why does the code below still leave the properties as null
There is not apparent reason for homePercentage to stay nil (not null) from the code you provided. Are you sure your custom method gets called? (remember that when using the dot notation (self.homePercentage), this is -(void)setHomePercentage:(NSNumber *)homePercentage; which is called, not your -(void)setHomePercentage;).
Note also that you don't need to add #synthesize homePercentage = _homePercentage; unless you override both the getter and the setter.
If all i have is a list of keys, is there an elegant way to test an object for read-only vs. read/write properties? I realize I could string-bang the key:
NSString *setterString = [#"set" stringByAppendingString:[someKeyString capitalizedString]];
BOOL isReadWrite = [myObject respondsToSelector:NSSelectorFromString(setterString)];
Or better yet try to set a value for the key and check for an NSUndefinedKeyException - but using exceptions for non-exceptional behavior seems like poor form.
To be clear, i'd like to programmatically audit an object's properties and tell the difference between, for instance,
#property (readonly) NSString *someReadOnlyKey
#property NSString *someReadWriteProperty
edit: To be more clear, it shouldn't matter if the keys are implemented as #propertys or manual getter/setter. Only concerned about public interface. And thanks for asking what I'm trying to accomplish - that's probably more important to get right in the first place.
I'm trying to sketch out some code that generates graphic representations of an object's keys. All the keys are known beforehand - but I won't always know which keys will be sett-able (it's up to the particular subclass to implement)
You have two valid approaches:
the respondsToSelector: method
the runtime "trick" as exposed in Tommy's answer
I'll try to summarize the implication of both approaches, along with their drawbacks. You can then choose the approach more suitable to your needs.
Case 1
//MyClass.h
#property (readonly) NSString *someReadOnlyKey;
runtime => readonly
respondsToSelector => NO
Ok, everything works as expected.
Case 2
//MyClass.h
#property (readonly) NSString *someReadOnlyKey;
///////////////////////////////////////////////////////////////////////////
//MyClass.m
#property (readwrite) NSString *someReadOnlyKey;
runtime => readwrite
respondsToSelector => YES
If the property definition has been overridden, you'll get the actual property attribute being used. It doesn't matter whether you query about it from where the setter is visible, i.e. inside the class definition, or from outside. You will get the actual definition that has been used to synthesize the accessor methods.
Case 3
//MyClass.h
#property (setter=myCoolSetter) NSString *someReadOnlyKey;
runtime => readwrite
respondsToSelector => NO
With a custom setter name, the respondsToSelector trick won't work anymore, whereas the runtime is still providing the correct information.
Case 4
//MyClass.h
#property (readonly) NSString *someReadOnlyKey;
///////////////////////////////////////////////////////////////////////////
//MyClass.m
- (void)setSomeReadOnlyKey:(NSString *)someReadOnlyKey {
_someReadOnlyKey = someReadOnlyKey;
}
runtime => readonly
respondsToSelector => YES
This time the runtime is failing, since the setter is there, but the property definition "doesn't know" about it.
Assuming you're fine with asking the metaclass (ie, you don't want to allow for potential instance-specific patches to the dispatch table), you can get property attributes from the runtime. Specifically:
// get the property; yes: that's a C string. This can see only things
// declared as #property
objc_property_t property =
class_getProperty([instance class], "propertyName");
/* check property for NULL here */
// get the property attributes.
const char *propertyAttributes = property_getAttributes(property);
You can then check those attributes for read-only:
NSArray *attributes =
[[NSString stringWithUTF8String:propertyAttributes]
componentsSeparatedByString:#","];
return [attributes containsObject:#"R"];
If you want to be completely thorough, you should also check protocols via class_copyProtocolList and protocol_getProperty, in order to catch any #propertys that are incorporated into the class that way and — as noted below by Gabriele — some caveats apply around class extensions.
This might be one of the few times I might consider the exception route - that is of course if you need handle KVC.
The reason being that just checking for a set<key>: style method name is not really enough to determine if something is really settable, especially when you bring KVC into it.
KVC has well defined search patterns for when you try to set values, which can be seen in the Key Value Coding Programming Guide. This search path has many stops and even allows objects a last chance "are you sure you don't want to handle this setter" method with setValue:forUndefinedKey:, which can be used to prevent the NSUndefinedKeyException exception being thrown
You can use the following:
if ([obj respondsToSelector:#selector(setSomeReadOnlyKey:someReadOnlyKey:)]) {
// Not a readonly property
}
else
// Readonly property
This should work. Essentially, I am checking if the setter method exists.
This simple question is bugging me. Are getters the same for
#property (nonatomic, retain) NSString *name
#property (nonatomic, copy) NSString *name
- (NSString*) name{
return name;
}
According to the documentation
A property declaration, however, provides additional information about
how the accessor methods are implemented (as described in “Property
Declaration Attributes”).
Both the getter and the setter behavior are defined by property declarations. In your example that is correct since it is defined nonatomic but if nonatomic were missing from the declaration it would would be implemented similar to this
- (NSString*) name{
[_internal lock]; // lock using an object-level lock
id result = [[name retain] autorelease];
[_internal unlock];
return result;
}
This of course is only true if you use #synthesize and do not override or change the getter and setter methods.
Yes, as the other answers state, the getters are the same. The options retain, copy, and assign determine how to generate setters, but not the names even of those.
If you want to use a different getter name, for instance if you have a BOOL such as the UIApplication property idleTimerDisabled, then you do this by specifically assigned the getter name:
#property(nonatomic, getter=isIdleTimerDisabled) BOOL idleTimerDisabled
Without an override such as this, the getter name is always the property name.
Yes, they are the same. retain, copy, and assign only give the compiler instructions on how to generate setters, not getters.
Yes, copy and retain only affect the setter and not the getter. On a side note, you should chose copy instead of retain for immutable objects like NSString.
If you're using ARC (Automated Reference Counting), then the getters should all look like what you have above. However, the new standard with ARC is to use strong and weak instead of retain and assign, respectively. retain and assign will still work and are synonymous with the strong and weak, but any newly generated files will use those words instead, so it's important to understand what they mean.
If you aren't using ARC (still an option, even in iOS 5 and Lion) getters can be different depending on retain, copy, or assign.
retain and copy both look like:
- (NSString *)name {
return [[name retain] autorelease];
}
assign is pretty basic, but is usually used more for weak references (like delegates):
- (id)delegate {
return delegate;
}
I went into some detail on this because it's important to understand when using ARC, the code for all 3 look the same, but the behavior is still very much like what's written above. If you're using atomic instead of nonatomic then you need to add some locking/unlocking lines to make the method thread-safe. In any case, it's generally better to use the default accessors generated with #synthesize unless you want to do something really tricky.
Yes, they are. The getter name dependce only of properties name.
In the following common sample,
////
#interface MyObject : NSObject
{
#public
NSString * myString_;
}
#property (assign) NSString * myString;
#end
#implementation MyObject
#synthesize myString = myString_;
#end
////
why declare myString_ in the interface at all?
I ask because we can still get and set myString in the implementation using self.myString, [self myString], self.myString = ... and [self setMyString:...] and in fact we must if instead it's being retained.
This is a matter of preference/convention for some. By default, doing:
#property (assign) NSString * myString;
...followed by:
#synthesize myString;
...will give you three things. You get a setter method that can be accessed as self.myString = #"newValue" or [self setMyString:#"newValue"], a getter method that can be accessed as NSString* temp = self.myString or NSString* temp = [self myString], and an instance variable named myString that be be accessed directly inside of your class (i.e. without going through the getter and setter) and used to set and get the property value, and which is used internally to back the property.
If you like you can do #synthesize myString = someOtherVarName, and then you still get the setters and getters just as before, but instead of the myString instance variable the someOtherVarName instance variable is used to back the property, and no myString variable is created.
So why ever use the more verbose syntax? There is never any case that requires that you do so, but some people prefer to do so when dealing with properties that are declared retain or copy. The reason for this being that setting a property declared retain or copy via its generated setter method will affect the retain-count of the object being set/unset. Doing the same thing by accessing the instance variable directly will not.
So by aliasing the instance variable to something else, you can make a distinction in the code along the lines of "anything that does xxx.myString = Y is modifying the retain count, while anything that does someOtherVarName = Y is not". Again, it's not necessary to do this, but some people prefer to.
You should be able to skip it. Modern compilers allow that.
When you define a property, you are actually declaring how the getter and setter methods are constructed for a particular instance variable. Earlier it needed the instance variable to be defined so you declared it. It also allowed the property name to differ from the instance variable name via #synthesize myProperty = myIVar;. Now you don't need to do this as the modern compilers generate the instance variable for you.
The dot syntax is actually a convenience thing as you would've noticed. It doesn't directly refer to the instance variable but the methods myProperty and setMyProperty:. You can even call myArray.count where count isn't a property (I wouldn't recommend it even though lot of people seem to like it).
While there is a difference between the two, the gap seems to be slowly closing.
That's just a problem about point of view. If you access ivar directly, it's you're accessing it internally. If you're using property, you're not accessing ivar (semantically). You're using accessing method of the object. So you're handling the self as like external object which the internal is unknown.
This is encapsulation problem of Object-Oriented paradigm.
And I recommend some tricks when using properties.
The ivar declaration is optional, not required. Compiler will generate it automatically.
You should set the ivar as #protected or #private to encapsulate it correctly. (at least there is no reasonable reason)
I recommend to use nonatomic if you don't need threading lock when accessing the property. Threading lock will decrease performance greatly, and may cause strange behavior in concurrent execution code.
You can use this code to do same thing.
#interface MyObject : NSObject
#property (assign,nonatomic) NSString * myString;
#end
#implementation MyObject
#synthesize myString;
#end
And this will be transformed roughly something like this.
#interface MyObject : NSObject
{
#private
NSString* myString; // Ivar generated automatically by compiler
}
#end
#implementation MyObject
// Methods with thread synchronization locking generated automatically by compiler.
- (NSString*)myString { #synchronized(self) { return myString; } }
- (void)setMyString:(NSString*)newMyString { #synchronized(self){ myString = newMyString; } }
#end
In fact, I'm not sure about synchronization lock with assign behavior directive, but it's always better setting it nonatomic explicitly. Compiler may optimize it with atomic operation instruction instead of locking.
Here is reference document about the properties: http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocProperties.html%23//apple_ref/doc/uid/TP30001163-CH17
With the modern Obj-C runtime, declaring the ivar is more of a formality than anything else. However, there are some memory management things to keep in mind.
First, the property declaration for an object type is usually retain, or for strings it may be copy. In either case, the new object is retained.
Given the following code:
NSString *string = [[NSString alloc] init];
myString_ = string;
self.myString = string; // If the property was retain or copy
The second assignment would leak; the first would not. This is because the property would retain something that already has a retain count of 1—it is now at 2. When you release the property in dealloc, the count goes to 1, not 0, so it won't be released. With the first option, however, the retain count stays at 1, so dealloc brings it down to 0.
In your example, leaving the property as assign will make the ivar declaration a formality.
Is there a difference between an "instance variable" and a "property" in Objective-c?
I'm not very sure about this. I think that an "property" is an instance variable that has accessor methods, but I might think wrong.
A property is a more abstract concept. An instance variable is literally just a storage slot, like a slot in a struct. Normally other objects are never supposed to access them directly. A property, on the other hand, is an attribute of your object that can be accessed (it sounds vague and it's supposed to). Usually a property will return or set an instance variable, but it could use data from several or none at all. For example:
#interface Person : NSObject {
NSString *name;
}
#property(copy) NSString *name;
#property(copy) NSString *firstName;
#property(copy) NSString *lastName;
#end
#implementation Person
#synthesize name;
- (NSString *)firstName {
[[name componentsSeparatedByString:#" "] objectAtIndex:0];
}
- (NSString *)lastName {
[[name componentsSeparatedByString:#" "] lastObject];
}
- (NSString *)setFirstName:(NSString *)newName {
NSArray *nameArray = [name componentsSeparatedByString:#" "];
NSArray *newNameArray [[NSArray arrayWithObjects:newName, nil] arrayByAddingObjectsFromArray:[nameArray subarrayWithRange:NSMakeRange(1, [nameArray size]-1)]];
self.name = [newNameArray componentsJoinedByString:#" "];
}
- (NSString *)setLastName:(NSString *)newName {
NSArray *nameArray = [name componentsSeparatedByString:#" "];
NSArray *newNameArray [[nameArray subarrayWithRange:NSMakeRange(0, [nameArray size]-2)] arrayByAddingObjectsFromArray:[NSArray arrayWithObjects:newName, nil]];
self.name = [newNameArray componentsJoinedByString:#" "];
}
#end
(Note: The above code is buggy in that it assumes the name already exists and has at least two components (e.g. "Bill Gates" rather than just "Gates"). I felt that fixing those assumptions would make the actual point of the code less clear, so I'm just pointing it out here so nobody innocently repeats those mistakes.)
A property is a friendly way of implementing a getter/setter for some value, with additional useful features and syntax. A property can be backed by an instance variable, but you can also define the getter/setter to do something a bit more dynamic, e.g. you might define a lowerCase property on a string which dynamically creates the result rather than returning the value of some member variable.
Here's an example:
// === In your .h ===
#interface MyObject {
NSString *propertyName;
}
// ...
#property (nonatomic, retain) NSString *propertyName;
// === In your .m #implementation ===
#synthesize propertyName /* = otherVarName */;
The #property line defines a property called propertyName of type NSString *. This can be get/set using the following syntax:
myObject.propertyName = #"Hello World!";
NSLog("Value: %#", myObject.propertyName);
When you assign to or read from myObject.propertyName you are really calling setter/getter methods on the object.
The #synthesize line tells the compiler to generate these getter/setters for you, using the member variable with the same name of the property to store the value (or otherVarName if you use the syntax in comments).
Along with #synthesize you can still override one of the getter/setters by defining your own. The naming convention for these methods is setPropertyName: for the setter and propertyName (or getPropertyName, not standard) for the getter. The other will still be generated for you.
In your #property line you can define a number of attributes in parens for the property that can automate things like thread-safety and memory management. By default a property is atomic meaning the compiler will wrap #synthesized get/set calls with appropriate locks to prevent concurrency issues. You can specify the nonatomic attribute to disable this (for example on the iPhone you want to default most properties to nonatomic).
There are 3 attribute values that control memory management for any #synthesized setters. The first is retain which will automatically send release to old values of the property, and retain to the new values. This is very useful.
The second is copy which will make a copy of any values passed in rather than retaining them. It is good practice to use copy for NSString because a caller could pass in an NSMutableString and change it out from under you. copy will make a new copy of the input which only you have access to.
The third is assign which does a straight pointer assign without calling retain/release on the old or new object.
Lastly you can also use the readonly attribute to disable the setter for the property.
I use properties for the interface part - where the object interfaces with other objects
and instance variables are stuff that you need inside your class - nobody but you is supposed to see and manipulate those.
By default, a readwrite property will be backed by an instance variable, which will again be synthesized automatically by the compiler.
An instance variable is a variable that exists and holds its value for the life of the object. The memory used for instance variables is allocated when the object is first created (through alloc), and freed when the object is deallocated.
Unless you specify otherwise, the synthesized instance variable has the same name as the property, but with an underscore prefix. For a property called firstName, for example, the synthesized instance variable will be called _firstName.
Previously people use properties publicly and ivars for private usage, but since several years ago, you can also define properties in #implementation to use them privately. But I'd still use ivars when possible, since there are less letters to type, and it runs faster according to this article. It makes sense since properties are mean to be "heavy": they are supposed to be accessed from either generated getters/setters or the ones manually written.
However, in recent codes from Apple, ivars are not used anymore. I guess because it's more like objc rather than C/C++, plus it's easier to use properties with assign, nullable, etc.
Objective-C Property vs Instance variable (iVar)
[Swift variable, property...]
Instance variable
#interface SomeClass: NSObject
NSString *someVariable;
#end
Property
#interface SomeClass: NSObject
#property (nonatomic, strong) NSString *someVariable;
#end
Property uses Instance variable inside. property = variable + bounded getter/setter. It is a method call with variable syntax and access
#property generates getter and setter methods(accessor methods) which uses backing ivar(aka backing field) which you can use via underscore _<var_name> (_someVariable).
Since it calls a method - method dispatch mechanism is used that is why KVO[About] can be applied
When you override accessor methods backing iVar is not generated that is why you can declare a new property explicitly or use #synthesize[About] to generate a new one or link with existing
#import "SomeClass.h"
#interface SomeClass()
#property (nonatomic, strong) NSString *someVariable;
#end
#implementation SomeClass
- (void) foo {
//property getter method
NSString *a1 = self.someVariable; //NSString *a1 = [self someVariable];
//property setter method
self.someVariable = #"set someVariable"; //[self setSomeVariable:#"set someVariable"];
//iVar read
NSString *a2 = _someVariable;
//iVar write
_someVariable = #"set iVar";
}
//if you overriding someVariable getter and setter the iVar(_someVariable) is not generated, that is why you can:
//1. create some variable explicitly
NSString *_someVariable;
//or
//2. use #synthesize
#synthesize someVariable = _someVariable;
//overriding
- (NSString*) someVariable {
return _someVariable;
}
- (void)setSomeVariable: (NSString*) updatedSomeVariable {
_someVariable = updatedSomeVariable;
}
#end
[property attributes]