tags:

views:

406

answers:

8

When is self needed for class properties? For example:

self.MyProperty = @"hi there";

vs

MyProperty = @"hi there";

MyProperty is an NSString set as (nonatomic, copy). Is there any difference in memory management for the above two?

What about when there is no property and the variable MyProperty is declared in the header file? Is a property needed if it is never referenced outside of the class? Does it make a difference to memory management?

+1  A: 

For the second part of the question, property definition is not needed, it is a help to us . The @synthesize directive on property generates accessor methods for properties so we don't have to do it manually, and because:

This code instructs the compiler to generate, or synthesize, the accessor methods. The compiler will generate the accessor methods using well-tested, fast algorithms that are ready for multi-core and multi-threaded environments, including locking variables in setter methods. Not only does using properties reduce the amount of code that you have to write, it replaces that code with the best possible accessors for today's modern multi-core systems. Later, if you need to provide an alternative implementation for a property accessor, you can simply add the appropriate code to your class.

http://developer.apple.com/leopard/overview/objectivec2.html

The nonatomic will avoid use of locking when accessing variables, if you don't specify anything then default is atomic. Locking is useful on multithreaded systems. The copy specifies what code should be generated for accessors, copy will copy the object, retain will retain new object and release old one, assign is good for simple variables like int to just plain assign values. So when you define your property as you did above (nonatomic,copy) and then use self.MyProperty = @"Hey" you're actually calling generated accessor that will make a copy of the new variable as opposed to just assigning it. You can override accessor and add checking to it.

Because of the above I would say that defining property has benefits even when the variable is not used outside of the class.

I believe to access properties you should use self.MyProperty instead of just MyProperty but I can't point you to explanation why. Might be something to do with the fact that compiler will generate from

self.MyProperty = @"Hey";

this:

[self setMyProperty: @"Hey"];

But I'm only speculating here.

Whether you call self.MyProperty or MyProperty it should not affect memory management (I would still prefer the first - self.MyProperty).

See Objective-C 2.0 Overview for some high level description from Apple.

stefanB
It seems there is some relation to memory management. If you have a class with a custom init, which assigns strings to string properties, when you do PropertyA = @"hi there; instead of self.PropertyA = @"hi there"; and so on with all properties, the caller might have those properties unsuspectingly reallocated at some point (not of the caller's actions). Instead of type NSString on the properties, it might be NSArray, NSDictionary or NSNumber with valid "invalid". For whatever reason, something claims that particular address space
4thSpace
+4  A: 

The difference is that

self.MyProperty = @"hi there"

is dot-notation call that will call the generated accessor, which will handle the retain counts correctly (equivalent to [self setMyProperty:@"hi there"]), whereas

MyProperty = @"hi there"

is a direct assignment to your member variable, which doesn't release the old value, retain the new one, or do anything else your accessor does (e.g., if you have a custom setter that does extra work).

So yes, there is a big difference in memory management and in behavior in general between the two. The latter form is almost always wrong, unless you know specifically why you are doing it and that you are handling the retain counts correctly yourself.

smorgan
+1  A: 

As a supplement to the other answers, try to think of it this way:

self.MyProperty = @"hi there";

or

[self setMyProperty:@"hi there"];

(which are equivalent) both call a method, whereas

MyProperty = @"hi there";

Simply sets a variable.

e.James
+2  A: 

If you use automatic Key-Value Observing (or any Cocoa technology that builds on it - like bindings, ...), it is also important use the setter. The observer would not receive any notification if you assign to the ivar. If you bind "MyProperty" to a NSTextfield and you change your "MyProperty" ivar via code, the bound textfield would still display the old value as it did not receive any change notification.

weichsel
What do you mean by "... assign to the ivar"?
4thSpace
setting a value to an instance variable instead of using the set accessor.
weichsel
+3  A: 

Yes, there is a difference for both memory and performance.

MyProperty = @"hi there";

This is considered a direct assignment. There is practically no memory or performance impact. Of course, that's not to say it's best practice - that's a different question :)

@property(nonatomic, copy) NSString *MyProperty;
// ...
self.MyProperty = @"hi there";

This statement has a significant impact on memory and performance. This is essentially equivalent to:

-(void)setMyProperty(NSString *)newValue {
    if (MyProperty != newValue) {
        [MyProperty release];
        MyProperty = [newValue copy];
    }
}

The old value is released and the new value is copied into MyProperty. This is acceptable and especially typical when dealing with strings when the string your assigning is mutable (ie, it could change later).

If, as in your example, you're simply assigning a static string (@"hi there"), there is nothing wrong with directly assigning the string value; it's more efficient however the difference in performance is trivial.

You can declare a property with @property as retain, copy, or assign (default is assign). You can then generate "accessor" (getter/setter) methods by using @synthesize. Here is what the setter methods look like that are generated when you do so:

// @property(nonatomic, assign)
-(void)setMyProperty(NSString *)newValue {
    MyProperty = newValue;
}

// @property(nonatomic, retain)
-(void)setMyProperty(NSString *)newValue {
    if (property != newValue) {
        [property release];
        property = [newValue retain];
    }

// @property(nonatomic, copy)
-(void)setMyProperty(NSString *)newValue {
    if (property != newValue) {
        [property release];
        property = [newValue copy];
    }
}

More information on ObjectiveC Declared Properties.

"You can use the @synthesize and @dynamic directives in @implementation blocks to trigger specific compiler actions. Note that neither is required for any given @property declaration.

Important: If you do not specify either @synthesize or @dynamic for a particular property, you must provide a getter and setter (or just a getter in the case of a readonly property) method implementation for that property."

In other words, if you declare a property but don't synthesize the property, you won't be able to use [self MyProperty] or self.MyProperty unless you define 'MyProperty' and 'setMyProperty' methods. If you don't declare a property then you simply have an instance variable.

Note: @dynamic doesn't generate the accessors. It's really used if you're dynamically (ie, magically) resolving accessor methods via loading code or dynamic method resolution.

nessence
"There is practically no memory...impact." This is definitely incorrect. If you assign directly, don't be surprised if the value is replaced with something strange. Using a property, even for a variable used only within the class, solves the problem of something else being assigned to your variable's address space and retains the property value's integrity.
4thSpace
The "impact" you describe has nothing to do with memory or performance. Bad practice, which I noted accordingly, is a different question ;)Your comment is incorrect. In the question, the property is NSString and all assignments are constants - @"hi there" is an NSString constant, not an object. If you write an application which sets a value to @"a string", whether by assign, copy, or retain, the variable will always point to the same address space in memory.Properties are used for exposing instance variables, not memory management or addressing.
nessence
A: 

Still not clear on when to use the accessors and when to do direct assignment on ivars ? I have seen lot of Apple examples which directly access the ivars. So using properties for all ivars seems pedantic overkill.

It seems only significant ivars which need to be around longer and are accessed outside tend to use the properties.

Would appreciate some Cocoa gurus to step in and clarify.

For the reasons I've commented on the third post, properties are very necessary.
4thSpace
It's not a violation for objects to directly access their own ivars. It's still cleaner to use accessors/properties in that case, but it's generally a big design mistake for an object to access *other* objects' ivars.
Chuck
+1  A: 

To access a variable, there is often no need to use the dot notation. Thus, in code generated by the XCode templates, you will see things like:

[flipsideViewController viewWillAppear:YES];

There is no need to write self.flipsideViewController here, because the accessor method typically does nothing except handing you the variable.

So a good rule of thumb is to use dot notation when you are setting a variable (absolutely necessary unless you want to do your own retaining and releasing), but not when you're accessing it:

self.aString = @"Text text text";
NSLog (aString);   // No need for self.aString here
NSString* tmpString = aString; // Here neither

When you're using non-object types, like int or float or many others, you can get away with not using the dot notation/setter method. In these cases, there is nothing to retain, so the setter method will do little apart from just assigning the value.

However, synthesized getters and setters do more than just retaining and releasing. As others have mentioned, they are also the engine that keeps the KVO system running. Thus, you should use the proper setters even on ints, floats and the rest.

What about the accessors then? In more advanced contexts, a class might respond to a request for a variable's value even when the variable doesn't exist. To quote the exalted Objective-C manual, classes might provide "method implementations directly or at runtime using other mechanisms [than simple accessor methods] such as dynamic loading of code or dynamic method resolution."

(One way of implementing this sort of on-the-fly response to messages is by overriding NSObject methods like methodSignatureForSelector: and forwardInvocation: .)

For this reason, using properly declared interfaces (whether synthesized or not) is always a good idea when you're working on something big. But it's completely ok to access ivars directly, as long as you set them using the proper API.

(Note: I'm not a Cocoa guru, so corrections are more than welcome.)

Felixyz
Thanks. What exactly is an ivar vs. property/self?
4thSpace
"ivar" = Instance Variable: a memory slot reserved when a class is instantiated to hold a value or a pointer. Property declaration is just protocol, through which classes can set, access, or observe vlaues in a standardized way. Property methods are *usually* synthesized and based on an ivar, but don't *have* to be. You can write your own methods (@dynamic instead of @synthesize) to handle a property, and calculate values on the fly (using cashing when appropriate). Example, UIView's frame/bounds/center properties could share an ivar, and have specialized getters and setters to maintain it.
Felixyz
Further clarification: when you use self.aVariable you are accessing the ivar through methods on the object self. (if you use @synthesize, you won't see them in the source code, since they are generated at compile time.) When you use aVariable, you simply access the value of the ivar directly, without any method dispatching.
Felixyz
+1  A: 

This is an old question, though it used to be "When do I write [self setMyProperty:@"hi there"]?" (Note that self.MyProperty = @"hi there" is exactly equivalent to this.)

The answer I've always heard (and which makes good sense) is always use the accessor; never write MyProperty = @"hi there". There are several reasons:

  1. Memory management is handled for you; you don't have to worry about proper retaining/releasing/copying.
  2. It's easier to modify your code in the future; if at some point you realize that changing MyProperty needs to have a particular side effect, you can add to the setter method without finding every time you set MyProperty.
  3. If you ever have problems with MyProperty, it's easy to add logging code to the setter (or even getter) to find out every time it's changed (or even accessed).

Summary: it's safest and most flexible to always use [self setMyProperty:@"hi there"] or self.MyProperty = @"hi there", and never use MyProperty = @"hi there".

andyvn22