Correct syntax for Objective-C init method - iphone

Why doesn't this common property initialization scheme risk failure when the synthesized setter tries to release the undefined myArray object? Or are property objects automatically initialized to nil and I don't need to be doing this at all?
#interface myClass : NSObject {
NSArray* myArray;
}
#property (nonatomic, retain) NSArray* myArray;
#end
#implementation myClass
#synthesize myArray;
-(id)init {
if ( self = [super init] ) {
self.myArray = nil;
}
return self;
}
...

Object instance variables in Objective-C are initialized to nil by default. Furthermore, messaging nil is allowed (unlike calling a method on null in function-calling languages like Java, C# or C++). The result of a message to nil is nil, this calling [nil release]; is just nil, not an exception.
On a side note, it's best practice to assign/call instance variables directly in -init and -dealloc methods:
-(id)init {
if ( self = [super init] ) {
myArray = nil;
}
return self;
}
- (void)dealloc {
[myArray release];
[super dealloc];
}

As others have stated, the instance variable is already initialised to nil.
Additionally, as per Apple's documentation, instance variables should be set directly in an init method, as the getter/setter methods of a class (or subclass thereof) may rely on a fully initialised instance.

It's already initialized to nil.

Related

Avoid Memory Leak When Property Assigning Twice

Let say i have an class named as MyTestClass.h.
Class structure is look like
#interface MyTestClass : NSObject {
NSString *testString;
}
#property (nonatomic, retain)NSString * testString;
#end
.m file
#implementation MyTestClass
#synthesize testString;
-(id) init{
[self setTestString:#""];
return self;
}
-(void)dealloc{
[self.testString release];
testString = nil;
[super dealloc];
}
#end
Now i created an object of MyTestClass and assigned testString twice
MyTestClass * myTestClass = [[MyTestClass alloc] init];
[myTestClass setTestString:#"Hi"];
[myTestClass setTestString:#"Hello"];
Now i think, two times my testStrings memory is leaked!! (one through init() and another one through my first setTestString method)
Am i correct? or will #property (nonatomic, retain) handle/release previous allocated memory?
or ,in this kind of cases ,will i need to override the setTestString() in MyTestClass.m like below code
-(void)setTestString:(NSString *)tempString{
[testString release];
testString = nil;
testString = [tempString retain];
}
Any help on this question is appreciated.
Thanks.
Any help on this question is appreciated.
I'll take this as a licence to make sone observations not necessarily directly related to your question.
Firstly, if you declare a retain property (as you have done) and synthesize it, the automatically generated getters and setters handle memory management correctly for you.
If you manually create setter (which you are allowed to do even with an #synthesize existing), you have to do the memory management yourself. Use either of trojanfoe's examples.
The setter in your question contains a bug in that if testString == tempString i.e. you assign the value of the property to itself, you could end up with assigning a dangling pointer to the property because you effectively release tempString and then retain it.
This is an implementation detail that you an safely ignore, but string literals e.g. #"blah" are compiled into the executable and will never be deallocated no matter how many times they are released. So, with your example, even if the setter did not do correct memory management, there will be no leak.
By the way, the normal pattern for an init method is
-(id) init
{
self = [super init];
if (self != nil)
{
// init stuff
}
return self;
}
or logical equivalent.
You should get into the habit of using it because you need to call the super class's init method and it is allowed to change the value of self, even to nil.
Also, while it is very good practice normally to set the object reference to nil after releasing it, in both cases when you do it, it is unnecessary. the first time, the variable is about to go out of scope and the second time you immediately assign it from some other object.
It's not a leak. Synthesized variable are correctly handled.
A synthesized method is implemented in this way (for a retain keyword)
#property (nonatomic, retain) NSString *string;
//backed by variable NSString *_string;
- (void)setString:(NSString*)newString
{
if (newString != _string) {
[_string release];
_string = [newString retain];
}
}
Of course this is a leak:
- (void)aMethod //of my class with string property
{
NSString *aString = [[NSString alloc] initWithString:#"hello"];
self.string = aString; //retain count of 2
self.string = #"hello2"; //retain count of 1 for aString
//now I don't release aString.... leak
}
If you use the auto-generated setter (in your case, setTestString:, which is also called by self.testString = ...;), the previous value of a retain property is released before being set. So no, there is no leak in the code you posted above.
The synthesized setter method should do the right thing. Here's an example of it's implementation:
- (void)setTestString:(NSString *)tempString
{
[tempString retain];
[testString release];
testString = tempString;
}
or:
- (void)setTestString:(NSString *)tempString
{
if (tempString != testString)
{
[testString release];
[tempString retain];
testString = tempString;
}
}
the dealloc is only called when the instance is destructed.
if you do :
[myTestClass setTestString:#"Hi"];
[myTestClass setTestString:#"Hello"];
in the same block, you're juste calling twice the setter. there is no memory leak.
When you use #synthesize on a property that specifies retain, the setter that's generated will handle the retain/release correctly for multiple assignments. As long as you use self. rather than going directly to the backing variable and do a final release in dealloc you should be fine.

Why does my class variable in my Application Delegate not get instantiated?

This issue has been bugging me for a while now and somehow I cannot find what I'm doing wrong. I must say I am new to Objective-C and Xcode.
So the issue is that I try to declare an instance variable (NSMutableArray) but for some reason the init function is NEVER reached. The variable is always NULL.
So I have a class named PropertyProvider which contains a NSMutableArray named "properties".
#interface PropertyProvider : NSObject {
NSMutableArray *properties;
}
#property (nonatomic, retain) NSMutableArray *properties;
..
#end
I then instantiate this NSMutableArray in the init method of this PropertyProvider class as the following:
#implementation PropertyProvider
#synthesize properties;
- (id) init {
self = [super init];
NSLog(#"Instantiating PropertyProvider");
if (self) {
properties = [[NSMutableArray alloc] init];
}
return self;
}
.. more code ..
#end
In my Application delegate I try to instantiate the PropertyProvider as "prp":
#implementation MyAppDelegate
#synthesize prp = _prp;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
[[_prp init] alloc];
[self.window makeKeyAndVisible];
return YES;
}
.. more code ..
- (void)dealloc
{
[_prp release];
[super dealloc];
}
But thus, for some reason it never reaches the init method of my PropertyProvider. Why o why?!
Thanks for your help!
The correct way of initializing _prp as an instance of PropertyProvider would be,
_prp = [[PropertyProvider alloc] init];
Since _prp is an instance variable, it is nil by default and hence messages to it don't do anything which is the reason why you're not getting any errors.

Memory Management in Objective-C

I wanna ask if I allocated an instance variable for private use in that class, should i release it immediately on site, or i can depend on dealloc function. (because maybe i will need it on other function) ?
//Player.h
#interface Player : NSObject
{
NSMutableArray * objectArray;
}
- (void)awake;
- (void)add;
#end
//Player.m
#implementation Player : NSObject
{
-(id) init {
self = [super init];
if (self != nil ){
[self awake];
[self add];
}
return self;
}
- (void) awake {
objectArray = [[NSMutableArray alloc] init]; //is it cause leakage?
[objectArray addObject:#"foobar"];
}
- (void) add {
[objectArray addObject:#"foobar2"];
}
- (void) dealloc {
[objectArray release];
[super dealloc];
}
}
#end
or should i using property to set the objectArray iVar?
//Player.h
#interface Player : NSObject
{
NSMutableArray * objectArray;
}
#property (nonatomic,retain)NSMutableArray* objectArray;
- (void)awake;
- (void)add;
#end
//Player.m
#implementation Player : NSObject
{
-(id) init {
self = [super init];
if (self != nil ){
[self awake];
[self add];
}
return self;
}
- (void) awake {
self.objectArray = [[NSMutableArray alloc] init autorelease]; //cause leakage?
[objectArray addObject:#"foobar"];
}
- (void) add {
[objectArray addObject:#"foobar2"];
}
- (void) dealloc {
[objectArray release];
[super dealloc];
}
}
#end
if both of them doesn't cause a leakage, what type should i use?
should i always set iVar property, and access iVar value with self even if i only want to use it in this class?
I like to take the stance that if the instance variable should not be visible outside of the class then it should not be implemented as a property. But it's a personal thing that other developers may not agree with.
Either way you would need to release the objectArray in your classes dealloc method - which is what you're currently doing.
However you need to be careful with your awake method - if it's invoked multiple times then objectArray is leaked. This is the downside of not using properties. A use of self.objectArray = [[NSMutableArray alloc] init] here would have released the previous object.
In my opinion, you should only declare properties in your header if other objects are allowed to use them. There is no good reason why you would provide an -add: method (as in your example) that adds something to your array while also providing a getter for your array so other objects can manipulate it directly. It's called encapsulation.
If you do want to have the benefits of generated getters/setters for your implementation file, you can always use a class continuation (a nameless category) inside your implementation file and include your property declarations there. That way you get real, auto-generated properties that are only visible to your class' implementation.
Personally, I wouldn't use any getter or setter methods in your example. Just allocate the NSArray in your -init and release it in -dealloc. If this -awake method of yours might be called multiple times, just add an [objectArray removeAllObjects] call and you're sure to have an empty array without worrying about memory management.
It is very likely that memory will leak in your first example because you are not sending release to the previously set instance variable (if it already existed).
This is why you should use property setters - they handle all of this stuff for you.
Also, since you are obtaining ownership of the instance variable through the property (which is defined with the retain keyword), you will definitely leak memory if you don't send the instance variable the -release message in your -dealloc method.
So the verdict is that you should use the second example, not the first.

iOS initWithCoder/decodeObjectForKey memory leak

The Leaks instrument tells me that I have a memory leak when I use decodeObjectForKey within initWithCoder. For example:
Class.h
{
MyObject *myObject;
}
#property (nonatomic, retain) MyObject *myObject;
Class.m
#synthesize myObject
-(void)dealloc{
[myObject release];
[super release];
}
-(id)initWithCoder:(NSCoder *)decoder{
if (self = [super init]{
self.myObject = [decoder decodeObjectForKey:#"MyObject"];
}
return self;
}
Per request in the comments:
-(void)encodeWithCoder:(NSCoder *)encoder{
[encoder encodeObject:myObject forKey:#"MyObject"];
}
Leaks reports a leak of type NSCFString on the line;
self.myObject = [decoder decodeObjectForKey:#"MyObject];
As I understand it, decodeObjectForKey returns an autoreleased object. Since I immediately assign that value to the myObject property, which is specified as (nontoxic, retain) in the property definition, I retain the autoreleased object through the setter method of the myObject property. The myObject is then released in the dealloc method. I don't understand where the leak is if I understand the sequence correctly. Also why is it reported as a NSCFString when the type is MYObject?
Any thoughts would be appreciated, including if my assumptions above are correct.
Look carefully at your -dealloc method. You are calling [super release]; when you should be calling [super dealloc];.
Calling [super release] in this case is the same thing as calling [self release], since you're not overriding the -release method. If your -dealloc method is called, your object has already been fully released, so this is unnecessary. Since you are overriding the -dealloc method, you must call [super dealloc] to also free any memory allocated by the superclass.
You can refer to the NSObject documentation to see how to override dealloc correctly.

Is the Object retained in this case

I have a simple question, that in a class I have a variable with property retain
//Classs ArrayClass has this array
#property(nonatomic, retain) NSMutableArray *array;
Now when I do
self.array = [SomeClass getArray];
I need to release the array...
Now If I have object of ArrayClass and when I do
arrayClassObj.array = [SomeClass getArray];
So in this case, Is the setter method is called? Do I need to release in this case.
The setter generated by #synthesize will (since you told it to retain) handle the retaining and releasing for you. If you override it, it's on you.
In your dealloc, don't forget to release it as well -- safe, don't forget, because messages to nil are not errors (and you should be setting a var to nil if you're through with it).
In both cases the object being assigned it's array property from [SomeClass getArray] will need to release it itself, unless you set the property to nil.
The following is required by the class owning the array property.
// ArrayClassObject dealloc (self in first example)
-(void)dealloc
{
[array release];
[super dealloc];
}
When you assign the property then assign it nil, the [array release] is still required in the dealloc method, but since you're assigning nil to it, it won't have any effect.
// someArrayObj must have [array release] in its dealloc method
someArrayObj.array = [SomeClass getArray];
// But you can do it manually by assigning nil
someArrayObj.array = nil;