#synthesized properties and KVC - objective-c

Should setter generated with #synthesize be KVC compilant or not? I found statement that getters and setters generated are KVC-compliant, shouldn't it call one of this methods?
#interface testing : NSObject
#property (nonatomic, retain) NSString *phone;
#end
implementation:
#implementation testing
#synthesize phone;
- (id)init {
self = [super init];
return self;
}
// none of these is called with dot syntax, or setter setPhone
- (void)setValue:(id)value forKey:(NSString *)key
{
NSLog(#"%#",key);
[super setValue:value forKey:key];
}
-(void)setValue:(id)value forKeyPath:(NSString *)keyPath
{
NSLog(#"%#",keyPath);
[super setValue:value forKeyPath:keyPath];
}
#end
and test it with:
testing *t = [[testing alloc] init];
[t setPhone:#"55555555"];

I think you've got it the wrong way round.. KVC compliant doesn't mean that an accessor will call -setValue:forKey: Being KVC compliant means that calling -setValue:forKey: will call the accessor.
Expanding a bit: KVC compliant only means 'follows naming conventions'. Why is this important? I can call my accessor methods anything i like. For a property 'Foo':
- (void)weakSetFoo:(id)f;
- (id)autoreleasedFoo;
This is fine. But a mechanism like Bindings will try to set Foo by calling
[ob setValue:newVal forKey:#"foo"];
-setValue:forKey: will try to do the right thing and use the accessor method (if we wrote a setter method, it's because we want it to be used, right?). But unless we named our setter method the standard -setFoo: there's no way it will be found.
So -weakSetFoo: is a setter method, but the property Foo isn't KVC compliant.
If i change the setter name to -setFoo: the property Foo is now KVC compliant.
Synthesized accessor methods will by default be named correctly.

You don't need to implement setValueForKey: for KVO. It is implemented for you within the framework. By making your properties KVO compliant (which you have done using #property and #synthesize), everything just works 'magically'
----- update
Also, your testing code would not test KVO. To test it, do something like:
testing *t = [[testing alloc] init];
[t setValue:#"55555555" forKey:#"phone"];

It is actually the other way round.
These are setValue:forKey and getValueforKey which look up the KVC-compliant properties, not properties synthesized through them.
When you write #synthesize property the compiler actually just stuffs - (type) property and - (void) setProperty: (type)value kind of methods which read/set corresponding instance variable.

Related

Should I dealloc a nonnull property; and if so, how?

I'm exposing a few properties from an Objective-C project to Swift (based on this repo), but have no experience in Objective-C, so I'm rather out of my depth here, so please bear with me.
I'm wondering how to correctly dealloc a nonnull property (or whether it's necessary at all!). I've provisionally dealloc'ed the nonnull property surface by setting it to null (in the same manner as is done for the nullable partOfSpeech). However, this prompts the following warning:
Null passed to a callee that requires a non-null argument
... so I wonder whether it's redundant. Is there anything I should do instead to handle my nonnull property, during the Node class's dealloc block?
Given the interface, node.h:
#interface Node : NSObject {
NSString *surface;
NSString *partOfSpeech;
}
#property (nonatomic, retain, nonnull) NSString *surface;
#property (nonatomic, retain, nullable) NSString *partOfSpeech;
- (nullable NSString *)partOfSpeech;
#end
... And the implementation, node.m:
#implementation Node
#synthesize surface;
#synthesize partOfSpeech;
// surface is assumed to be set post-initialisation.
- (void)setPartOfSpeech:(NSString *)value {
if (partOfSpeech) [partOfSpeech release];
partOfSpeech = value ? [value retain] : nil;
}
- (NSString *)partOfSpeech {
if (!features || [features count] < 1) return nil;
return [features objectAtIndex:0];
}
- (void)dealloc {
// WARNING: "Null passed to a callee that requires a non-null argument"
self.surface = nil;
self.partOfSpeech = nil;
[super dealloc];
}
#end
... And given that a Node's lifecycle is like this:
Node *newNode = [Node new];
newNode.surface = [[[NSString alloc] initWithBytes:node->surface length:node->length encoding:NSUTF8StringEncoding] autorelease];
// ... Do stuff with newNode (eg. add to array of Node)...
[newNode release];
First: The compiler can automatically synthesize instance variables and
setters/getters for your properties. So your interface should be just
// Node.h
#interface Node : NSObject
#property (nonatomic, retain, nonnull) NSString *surface;
#property (nonatomic, retain, nullable) NSString *partOfSpeech;
#end
and no #synthesize statements are needed in the implementation file.
The compiler will automatically create instance variables
_surface and _partOfSpeech, and also create accessor methods
- (NSString *) surface;
- (void)setSurface:(NSString *)value;
- (NSString *)partOfSpeech;
- (void)setPartOfSpeech:(NSString *)value;
which do "the right thing", with or without ARC. You can override
those methods if you want to implement some custom logic, but you don't have to implement a standard setter like your setPartOfSpeech.
If you use ARC (automatic reference counting) then that is all,
nothing more is needed. And
I would really recommend to do so. The compiler inserts the required retain/release calls at compile time, and is quite clever in avoiding
unnecessary calls. See for example
Confirmed: Objective-C ARC is slow. Don’t use it! (sarcasm off)
about some comparisons. With MRC (manual reference counting), your code might even be slower, or
have memory leaks.
But to answer your question: With MRC you have to release the
instance variables in dealloc
- (void)dealloc {
[_surface release];
[_partOfSpeech release];
[super dealloc];
}
as explained in Memory Management Policy in the "Advanced Memory Management Programming Guide".
You should not use the accessor methods in dealloc as in your
self.surface = nil;
self.partOfSpeech = nil;
see Don’t Use Accessor Methods in Initializer Methods and dealloc.
If you are using manual memory management you can just release the object stored in the properties backing variable. As you've named the backing variable the same as the property use the -> to clearly reference the backing variable:
[self->surface release];
Or if you want to do this with assignment just assign the empty string literal:
self.surface = #"";
The string literal is created at compile time, lives throughout the program execution, and takes up very little space. The assignment will caused the release (and deallocation if the reference count reaches zero) of the previous value in the property, just like assigning nil (or any other value).
HTH

Which one is initialized, property or its instance variable

Suppose I have a property called myPropertyName defined in my class MyClassName. Manual memory management is used throughout this post.
MyClassName.h
#import <UIKit/UIKit.h>
#interface MyClassName : NSObject {
#private
NSObject* myPropertyName;
#public
}
#property (nonatomic, retain) NSObject* myPropertyName;
// Some methods prototypes are here
#end
MyClassName.m
#import "MyClassName.h"
#implementation MyClassName
#synthesize myPropertyName;
// Some methods are here
#end
I'm confused with usages such as the place of myPropertyName declaration, its difference between instance variable. For example, what is the difference among these three statement of initialization code, for example, in the customized -(void)init method for my class myClassName.
self.myPropertyName = [[[NSObject alloc] init] autorelease];
This one is calling myPropertyName setter, but I'm not sure what is the name of the instance variable being used in the setter, myPropertyName (since I've declared a #private field named myPropertyName) or _myPropertyName (people say that this one with underbar is the default)?
myPropertyName = [[NSObject alloc] init];
Does this initialize the instance variable of the myPropertyName property? If I don't have #synthesize myPropertyName = _myPropertyName;, would it be wrong since the default instance variable for the property is said to be _myPropertyName.
_myPropertyName = [[NSObject alloc] init];
Is _myPropertyName still declared as the instance variable for my property myPropertyName even if I use #synthesize myPropertyName; and #private NSObject* myPropertyName;?
In my understanding, a property is just a name (such as myPropertyName), there should be some instance variable encapsulated to be used in actual operations in the code, such as assigning values.
First off, I highly recommend reading Apple's documentation on properties, also linked by nhgrif. However, I understand docs can be a bit dense reading material (though Apple's, I find, are not so bad), so I'll give a brief overview of properties here.
I like examples, so I'm going to rewrite your two classes in a bit more current form.
MyClassName.h
#import <UIKit/UIKit.h>
#interface MyClassName : NSObject
#property (nonatomic, strong) NSObject *myPropertyName;
// method prototypes here
#end
MyClassName.m
#import "MyClassName.h"
#implementation MyClassName
// some methods here
#end
The class MyClassName now has a property called myPropertyName of type NSObject *. The compiler will do a lot of work for you for "free" in this instance. Specifically, it will generate a backing variable, and also generate a setter and getter for myPropertyName. If I were to rewrite the two files, and pretend I'm the compiler, including that stuff, they would look like this:
MyClassName.h
#import <UIKit/UIKit.h>
#interface MyClassName : NSObject {
NSObject *_myPropertyName;
}
#property (nonatomic, strong) NSObject *myPropertyName;
- (void)setMyPropertyName:(NSObject *)obj;
- (NSObject *)myPropertyName;
#end
MyClassName.m
#import "MyClassName.h"
#implementation MyClassName
- (void)setMyPropertyName:(NSObject *)obj
{
_myPropertyName = obj;
}
- (NSObject *)myPropertyName
{
return _myPropertyName;
}
#end
Again, all of this is happening for "free": I'm just showing you what's happening under the hood. Now for your numbered questions.
self.myPropertyName = [[[NSObject alloc] init] autorelease];
First of all, you should probably be using Automatic Reference Counting, or ARC. If you are, you won't be allowed to call autorelease. Ignoring that part, this works fine. Excluding the autorelease, this is exactly equivalent to:
[self setMyPropertyName:[[NSObject alloc] init]];
Which, if you look at the second .m file I wrote out, above, will basically translate to:
`_myPropertyName = [[NSObject alloc] init];
myPropertyName = [[NSObject alloc] init];
As written, this code will give a compiler error, since there is no variable called myPropertyName in this class. If you really want to access the instance variable underlying (or, "backing") the myPropertyName property, you can, by using its real name:
_myPropertyName = [[NSObject alloc] init]; // note the underscore
But most of the time, it's better to use the setter, as in point 1., since that allows for side effects, and for Key-Value Coding, and other good stuff.
_myPropertyName = [[NSObject alloc] init];
Oh. Well you got it. See point 2.
You mentioned that:
I'm confused with usages such as the place of myPropertyName declaration, its difference between instance variable. For example, what is the difference among these three statement of initialization code, for example, in the customized -(void)init method for my class myClassName.
In case it hasn't been made clear, a property is something of an abstract concept; its data is stored in a normal instance variable, typically assigned by the compiler. Its access should usually be restricted to the setter and getter, with important exceptions. To keep this answer short, I won't go into more detail than that.
One more thing: as nhgrif mentioned, you don't need to use the #synthesize keyword anymore. That is implicitly understood by the compiler now.
If you're not sure about any of this, post a comment or, better yet, read the docs.
Let's take this example:
#property NSString *fullName;
If in the implementation, we override the setters and getters, and in these setters and getters, we don't use an instance variable fullName, it is never created. For example:
- (NSString *)fullName
{
return [NSString stringWithFormat:#"%# %#", self.firstName, self.lastName];
}
- (void)setFullName:(NSString *)fullName
{
//logic to split fullName into two strings
//self.firstName = etc
//self.lastName = etc.
}
In this example, there is no instance variable for fullName created.
This is according to Apple's Official Documentation
If, however, you don't override both the setter and getter, an instance variable is created.
As a sidenote, you can declare a property readonly, and then simply overriding the getter (without using the variable) will prevent an ivar being created. Likewise, you can declare a property writeonly and just override the setter.

I can use a declared property in implementation even without #synthesize it. Is this by design?

In the Hello World tutorial, I tried to comment out the '#synthesize userName = _userName;' in the HelloWorldViewController.m file. According to https://developer.apple.com/library/mac/#documentation/cocoa/conceptual/objectivec/Chapters/ocProperties.html#//apple_ref/doc/uid/TP30001163-CH17-SW1, "... You use the #synthesize directive to tell the compiler that it should synthesize the setter and/or getter methods for a property if you do not supply them within the #implementation block."
The strange thing to me is that even with '#synthesize userName = _userName;' commented out, the later appearance of statements in the HelloWorldViewController.m file, such as [self.userName length] and self.userName = [[self textField] text], is not considered to be an error or warning by Xcode (I am on V4.4.1). How is this possible?
As I understood, if #synthesize is missing for a declared property, the property is not even defined. What's more is no #synthesize means no getter or setter method for the property implemented. How come the Hello World app still compiles and runs perfect?
Part of code is here:
#import "HelloWorldViewController.h"
#implementation HelloWorldViewController
//#synthesize userName = _userName;
#synthesize label;
#synthesize textField;
...
- (IBAction)changeGreeting:(id)sender {
[self setUserName:[[self textField] text]];
if([self.userName length]==0){
[self setUserName: #"World"];
}
NSString *greeting=[[NSString alloc] initWithFormat:#"Hello, %#!", self.userName];
self.label.text=greeting;
- (IBAction)changeGreeting:(id)sender {
self.userName = [[self textField] text];
if([self.userName length]==0){
[self setUserName: #"World"];
}
NSString *greeting=[[NSString alloc] initWithFormat:#"Hello, %#!", self.userName];
self.label.text=greeting;
}
#end
Xcode gives no warning or error for the code above.
As of Xcode 4.4 properties are automatically synthesized. If you declare a property that is readwrite and you don't implement the getter and the setter method for that property, Xcode will insert #synthesize property = _property automatically for you. For readonly properties you mustn't implement the getter method to get this behavior.
If you implement the setter and/or getter method Xcode will not synthesize the property automatically and won't create an iVar for you, either. In that case you can still add the #synthesize yourself.
In Xcode 4.4 there was a change whereby properties are synthesized by default. Therefore by omitting the synthesize yourself, the compiler does it for you!
See Apple docs - specifically "The compiler automatically calls #synthesize by default for unimplemented #properties."

Objective-C Dot Syntax and Init

I have read a number of snippets that mention you should never use dot-notation within your init or dealloc methods. However, I can never seem to find out why. One post did mention in passing that it has to do with KVO, but no more.
#interface MyClass : NSObject {
SomeObject *object_;
}
#property (nonatomic, retain) SomeObject *object;
#end
This implementation is bad?
#implementation MyClass
#synthesize object = object_;
- (id)initWithObject:(SomeObject *)object {
if (self = [super init]) {
self.object = object;
}
return self;
}
#end
But this is good?
#implementation MyClass
#synthesize object = object_;
- (id)initWithObject:(SomeObject *)object {
if (self = [super init]) {
object_ = [object retain];
}
return self;
}
#end
What are the pitfalls of using dot-notation inside your init?
Firstly, it's not the dot notation specifically, it's the accessors that you shouldn't use.
self.foo = bar;
is identical to
[self setFoo: bar];
and they are both frowned upon within init/dealloc.
The main reason why is because a subclass might override your accessors and do something different. The subclass's accessors might assume a fully initialised object i.e. that all the code in the subclass's init method has run. In fact, none of it has when your init method is running. Similarly, the subclass's accessors may depend on the subclass's dealloc method not having run. This is clearly false when your dealloc method is running.
The reasons I've heard mainly crop up due to when you write your own setters/getters. When using the default #synthesized versions of the methods it won't cause much of an issue. When you write your own setter though, it is generally going to have a sideeffect on your class. This sideeffect is probably not wanted in the init, or even is going to cause issues if it references other ivars that haven't been created yet. Same issue in the dealloc, if you have a sideeffect, it has potential to blow up.

Extending properties generated using #synthesize in Objective-C

Suppose I have an #property declared like this:
#property (readwrite,retain) NSObject *someObject;
And I synthesize it like this:
#synthesize someObject = _someObject;
This generates getters/setters for me. Also, according to the docs, the setter will have built in thread safety code.
Now, suppose I want to add some code to the setSomeObject: method. Is there any way that I can extend the existing on from #synthesize? I want to be able to reuse the the thread safety code that it autogenerates.
You can define a synthesized "private" property, (put this in your .m file)
#interface ClassName ()
// Declared properties in order to use compiler-generated getters and setters
#property (nonatomic, strong <or whatever>) NSObject *privateSomeObject;
#end
and then manually define a getter and setter in the "public" part of ClassName (.h and #implementation part) like this,
- (void) setSomeObject:(NSObject *)someObject {
self.privateSomeObject = someObject;
// ... Additional custom code ...
}
- (NSArray *) someObject {
return self.privateSomeObject;
}
You can now access the someObject "property" as usual, e.g. object.someObject. You also get the advantage of automatically generated retain/release/copy, compatibility with ARC and almost lose no thread-safety.
What #synthesize does is equivalent to:
-(void)setSomeObject:(NSObject *)anObject {
[anObject retain];
[someObject release];
someObject = anObject;
}
or
-(void)setSomeObject:(NSObject *)anObject {
if(someObject != anObject) {
[someObject release];
someObject = [anObject retain];
}
}
so you can use this code and extend the method.
However, as you said, this code might not be thread-safe.
For thread safety, you might want to take a look at NSLock or #synchronized (thanks to unwesen for pointing this out).