ios initialize an instance inside a function to use outside - objective-c

the xcode analyzer tell me that a method returns an Objective-C object with a +1 retain count:
but the self.athletes is an object that I need also outside my function... how can I solve this 'warning?
thanks again
the athletes is declared like this:
NSMutableArray *athletes;
#property (nonatomic, retain) IBOutlet NSMutableArray *athletes;

Replace that line with this one:
self.athletes = [NSMutableArray array];
I wrote full explanation here : Memory Management for properties with retain attribute

Since your property is defined with "retain", using the dot notation will result in an extra retain. The return from the [[NSMutableArray alloc] init] has a retain count of 1, and then when you set the property using the setter function generated by the property declaration it will have a retain count of 2.
To fix, either:
self.athletes = [NSMutableArray array]; // Returns an autoreleased object
Or, you could also do this:
athletes = [[NSMutableArray alloc] init]; // Doesn't use the setter generated by the property declaration, so doesn't retain again.

There is a nice way to handle this (and you have already used this pattern while creating UI ).
NSMutableArray *athletesTemp = [[NSMutableArray alloc] init];
self.athletes = athletesTemp;
[athletesTemp release];
Here you don't need to carry the load of an auto release object.

Related

Problems using NSMutableArray

I have created an object of type NSMutableArray
#import <Foundation/Foundation.h>
#interface MyCustomObject : NSMutableArray
{
}
#end
in one of my classes, I delcare an instance:
MyCustomObject *myObj = [[NSMutableArray alloc] init];
But xcode is giving a warning on this line:
Incompatible pointer types initializing 'MyCustomObject *' with an expression of type 'NSMutableArray *'
Any idea what is wrong? It works fine, but just wondering why it is throwing a warning and how to resolve it?
You can assign a child class to a variable typed as its super-class, but you cannot assign a super-class to a child class variable.
So, you'd want to:
MyCustomObject *myObj = [[MyCustomObject alloc] init];
Firstly, as everyone else has said, you need to instantiate your class if you want an instance of your class. Evidently the reason you're not doing this is because you tried instantiating your class and it didn't work. That's the deeper problem: You can't simply subclass NSArray or NSMutableArray. As noted in the documentation, NSArray is a class cluster, which is basically a short way of saying "NSArray doesn't actually implement most of its methods."
In order to subclass NSArray, you essentially have to provide all of its functionality yourself. It is generally much easier to either create a category on NSArray or create a custom class that has an array as a member.
I think you've got things backwards. MyCustomObject is a NSMutableArray, but NSMutableArray isn't a MyCustomObject. Your variable myObj should be a NSMutableArray if it needs to be able to hold both NSMutableArrays and MyCustomObjects.
You should be instantiating the object as:
MyCustomObject *myObj = [[MyCustomObject alloc] init];
Otherwise, all you're doing is making an NSMutableArray and don't need your custom object (since none of its functionality would work.)
It should be:
MyCustomObject *myObj = [[MyCustomObject alloc] init];
if you do:
NSMutableArray *myObj = [[MyCustomObject alloc] init];
It will create an istance of MyCustomObject, but you will have a NSMutableArray pointer, so your new instance will just be seen as a NSMutableArray.
In this case:
MyCustomObject *myObj = [[NSMutableArray alloc] init];
It is an error. In previows a MyCustomObject can ben seen as a simple NSMutableArray. but a NSMutableArray cannot ever be seen as a MyCustomObject. It is a simple inheritance property.
Maybe this can help
http://en.wikipedia.org/wiki/Polymorphism_in_object-oriented_programming
Try allocating a MyCustomObject instead:
MyCustomObject *myObj = [[MyCustomObject alloc] init];

Objective-c simple memory question

If I have a variable in my view controler
viewcontroller.m
#interface MemoryTestViewController : UIViewController
{
NSMutableArray *array;
}
#end
in my implementation
- (void)viewDidLoad
{
[super viewDidLoad];
NSMutableArray *aux = [[NSMutableArray alloc] initWithCapacity:1];
array = aux;
[aux release];
// Do i have to do array release?
}
Do i have to release my variable array somewhere? Theoricaly i havent allocated that variable...
I testes the memory leaks and even if i dont release anything the instruments doesn't detect any leak.
No, you don't need to release. All you do is assign the pointer of aux to your array variable.
array is invalid at the moment where you release aux.
This is probably not as intended. If you want to work with array, you'll have to retain it.
You've already released the array with [aux release]; -- you in fact have the opposite problem to a leak: an over-release.
Assignments in Objective-C are just assignments of pointers; there's no copying or automatic memory management. When you say array = aux;, array now points to the exact same object as aux. If you then get rid of aux by releasing it (and therefore letting it be deallocated), array doesn't point to anything anymore.*
You have a couple of options for fixing this:
(Simplest) Assign the newly-created array directly to array:
array = [[NSMutableArray alloc] initWithCapacity:1];
This gives you ownership of the new array, under the name array. Don't release it until you are done with it (possibly in dealloc; certainly not in this method).
(Best) Create a declared property for array and let that mechanism handle the memory management for you:
#interface MemoryTestViewController : UIViewController
{
NSMutableArray *array;
}
#property (copy, nonatomic, setter=setArrayByMutableCopy) NSMutableArray * array;
#end
#implementation MemoryTestViewController
#synthesize array;
// Properties can't automatically make mutable copies, so you need to create
// your own setter method.
- (void) setArrayByMutableCopy: (NSMutableArray *)newArray {
NSMutableArray * tmp = [newArray mutableCopy];
[array release];
array = tmp;
}
...
*Or, rather, it points to a place where there used to be a valid object, which is a great way to make your program crash.
No. Assigning an object to a variable does not retain it. However if you plan to use that variable for a while, you should retain it and release it when you are done with it.
alloc raised the retain counter to 1 and [aux release] set it to 0
You should add a property:
#property (nonatomic, retain) NSMutableArray *array;
and later in your viewDidLoad:
// wrong, leaks: self.array = [[NSMutableArray alloc] initWithCapacity:1];
array = [[NSMutableArray alloc] initWithCapacity:1];
and yes, somewhat later release it, probably in dealloc..

Clarification on when to release pointers after allocating

In my last question (here), I had an issue where I was getting an EXC_BAD_ACCESS because I was releasing the variable I had just allocated:
NSMutableArray* s = [[NSMutableArray alloc] init];
stack = s;
[s release];
should have been
NSMutableArray* s = [[NSMutableArray alloc] init];
stack = s;
However, stack is a retained property of my class. It's declared like so:
#interface StateStack ()
#property (nonatomic, retain) NSMutableArray* stack;
#end
I was under the impression that when you assign a 'retain' variable, it automatically increments the retainCount of the object. So you are supposed to start by releasing your pointer (as here).
Why are these two cases different? Thanks!
Because you had to assign the property, not the instance variable. When you assign to the property it's going to retain the variable again and then you're not going to have the issue. Here's how your code should have been:
NSMutableArray* s = [[NSMutableArray alloc] init];
self.stack = s;
[s release];
This way you're not assigning to the variable, but using the property (that's, in fact, a method). If you did not release in this case then you'd have a memory leak in your code.
When you did stack = s you assigned directly to the instance variable and the array was never retained.
There is no such thing as a "retain variable". It's a retain property — meaning the setter method behind the property retains the new value and releases the old one. But assigning to a variable just assigns. In fact, the reason people generally recommend assigning directly to the instance variable in init is specifically so that it doesn't go through the setter, because the setter could conceivably have side effects you don't want in init (when your object isn't fully constructed yet).
Note: I'm talking about normal memory-management rules here. This is all different if you're using ARC. But I assume you would have mentioned if you were.
self.stack and stack are two completely different things. When you use stack, you are accessing an instance variable, not a property. This means that your accessor methods aren't called, which means automatic memory management isn't used. This is why you shouldn't release s in your example.
If you used self.stack instead, then you would be using a property. The compiler will treat self.stack = value exactly the same as [self setStack:value], and self.stack the same as [self stack]. Since accessors are being used, memory management will be taken care of to match the way you defined your property, and you should release a value after assigning it.
Maurício has the right answer: be sure to assign to the property to gain the benefits of #property. To clarify the point somewhat, try using code like this:
#interface StateStack : NSObject {
NSArray *_stack;
}
#property (nonatomic,retain) NSMutableArray *stack;
#end
#implementation StateStack
#synthesize stack=_stack;
#end
Now, if you try:
NSMutableArray* s = [[NSMutableArray alloc] init];
stack = s;
[s release];
You'll get an error, which will mean you tried to set the ivar rather than the property as intended. This mismatch between ivar name and property name is against Apple's recommendations, but it's a fine way to help you develop the habit of using property assignment when you intend to do so.

Question about release the object

I have a class which contain a NSArray object.
like this
#import <Foundation/Foundation.h>
#interface myClass : NSObject {
NSArray *myArray;
}
#property (nonatomic, retain) NSArray *myArray;
#end
In .m file, I init myArray in init method,and release myArray in dealloc method.
in a method, I create its object and add it to a NSMutableArray.
myClass *my = [[myClass alloc] init];
NSLog(#"init finish %d",[my retainCount]);
NSMutableArray *a = [[NSMutableArray alloc] init];
[a addObject:my];
NSLog(#"array added finish %d",[my retainCount]);
NSLog(#"array added finish %d",[my.myArray retainCount]);
[my release];
When i add object "my" to NSMutableArray, the retainCount of "my" was added.
but myArray wasn't. Did it mean that I must retain myArray by my self?
or something other I can do.
Can this code work normal after I release "my" object?
[a objectAtIndex:0];
Thanks!
Another great example of exactly why you should...
NEVER call -retainCount!
retainCount is useless, misleading and a waste of your time.
In this case, the reason why the retain count happens to be zero "unexpectedly" is because my.myArray returns nil. That happens because you never assign the created mutable array to myArray.
You need something like this (Class name capitalized to follow convention):
MyClass *my = [[MyClass alloc] init];
NSMutableArray *a = [[NSMutableArray alloc] init];
my.myArray = a;
[a addObject:my];
Note that this creates a retain cycle between my and the array. I.e. you will need to remove my from the array manually (or remove the array from my manually) whenever you release myArray and, of course, you can't do that in dealloc because dealloc will never be called until my has been removed from myArray.
I am not sure if that is the full source code above but for my.myArray to be retained you have to actually assign something to it.
So in your above example you created an NSMutableArray:
NSMutableArray *a = [[NSMutableArray alloc] init];
And then you added your class to it:
[a addObject:my];
But no where have you created an array and assigned it to myClass as in:
NSArray *anArray = [[NSArray alloc] init.....];
my.myArray = anArray;
At that point, myArray will get a reference to an object and will retain it (since you specified retain in your myArray prop declaration).
Perhaps if you clarified what it is you are trying to do or posted some more full source code?

Why or why not call an object with a "self." prefix?

#interface{
NSArray *array;
}
#property (nonatomic, retain) NSArray *array;
#end
#implementation
#synthesize array;
self.array = [[NSArray alloc] init];
array = [[NSArray alloc] init];
[self.array objectAtIndex:2]; [array objectAtIndex:2];
#end
Is there a difference between them? Why should I use one over the other?
self.array = foo is shorthand for [self setArray:foo] (i.e. you access the synthesized property methods), while just array = foo directly accesses the instance variable.
In exactly this case, you would create a memory leak with self.array = [[NSArray alloc] init]; since the property will retain it and the reference count would thus be 2 instead of 1. So better would be: self.array = [NSArray array];.
Which one to prefer is almost a matter of taste, but using the properties gives you a few advantages like automatic key-value coding support. It's also an advantage if you someday chose to do implement setArray: yourself so it can do additional stuff when the array is assigned (like reloading a UITableView). On the other hand, it's a little bit slower as it's an additional method call (only matters if called in a loop a lot). But for almost all applications it's better to be correct than as fast as possible. Using properties can make memory management easier for you.
The property "array" is declared to retain on assignment (the retain in the brackets after #property signifies this). Because it has the same name as the "array" instance variable it uses that instance variable as it's backing store.
Effectively calling self.array = [[NSArray alloc] init]; is the same as calling array = [[[NSArray alloc] init] retain];
When you assign to the instance variable directly, not using the property, no action is taken on it, so array simply points to a new instance of NSArray without retaining it.