NSMutableArray in Singleton object - iphone

I want to build a shared object that all the classes will be able to access to it.
i want that in this object will be NSMutableArray .
this is how i call this object
+(id)sharedManager{
#synchronized(self) {
if (sharedManager == nil){
sharedManager = [[self alloc] init];
array = [[NSMutableArray alloc] init];
}
}
return sharedManager;
}
and this is how i define the NSMutableArray :
#property (nonatomic,retain) NSMutableArray *array;
the problem is that after i create this NSMutableArray in the sharedManager method, every time i try to access the array is equal to Nil.

You're attempting to set an instance variable from a class method. Instead, you should create array in your -init method in the singleton. That way when you message, sharedManager = [[self alloc] init];, the array will be configured for that shared instance.
- (id)init
{
self = [super init];
if (!self)
return nil;
array = [[NSMutableArray alloc] init];
return self;
}

Related

#properties - Memory Management

would this code be ok concerning memory management?
#property (nonatomic, retain) id object;
...
id anObject = [[Object alloc] init];
self.object = anObject;
id otherObject = [[Object alloc] init];
self.object = otherObject;
Thanks for your answers,
Christian
No. As the property descriptor indicates, it will retain the object when it's assigned. So, as you're allocating it, you'll have two retains in your object at the moment of assign it to self.object. So, you have to release it:
#property (nonatomic, retain) id object;
...
id anObject = [[Object alloc] init];
self.object = anObject;
[anObject release];
id otherObject = [[Object alloc] init];
self.object = otherObject;
[otherObject release];
...
at dealloc:
self.object = nil;
Good luck!

Autoreleased NSMutableArray not populated

I want to populate an array like this:
NSMutableArray *array = [self methodThatReturnsAnArray];
In the "methodThatReturnsAnArray"-method I create an array like this:
NSMutableArray *arrayInMethod = [[NSMutableArray alloc] init];
When I'm finished populating "arrayInMethod" I'm returning the array and in order to prevent a memory leak I'm using:
return [arrayInMethod autorelease];
However the "array"-variable is never populated. When removing the "autorelease" it works fine though. What should I do in order to make sure that the returned object i released?
EDIT
+ (NSMutableArray *)buildInstants:(NSArray *)huntsArray {
NSMutableArray *goGetObjects = [[[NSMutableArray alloc] init] autorelease];
for (int i = 0; i < [huntsArray count]; i++) {
NSDictionary *huntDict = [huntsArray objectAtIndex:i];
PHGoGet *goGet = [[PHGoGet alloc] init];
goGet.title = [huntDict objectForKey:#"title"];
goGet.description = [huntDict objectForKey:#"description"];
goGet.start = [huntDict objectForKey:#"start"];
goGet.end = [huntDict objectForKey:#"end"];
goGet.ident = [huntDict objectForKey:#"id"];
if ((CFNullRef)[huntDict objectForKey:#"image_url"] != kCFNull) {
goGet.imageURL = [huntDict objectForKey:#"image_url"];
} else {
goGet.imageURL = nil;
}
if ((CFNullRef)[huntDict objectForKey:#"icon_url"] != kCFNull) {
goGet.iconURL = [huntDict objectForKey:#"icon_url"];
} else {
goGet.iconURL = nil;
}
goGet.longitude = [huntDict objectForKey:#"lng"];
goGet.latitude = [huntDict objectForKey:#"lat"];
goGet.companyIdent = [huntDict objectForKey:#"company_id"];
[goGetObjects insertObject:goGet atIndex:i];
[goGet release];
}
return [[goGetObjects copy] autorelease];
}
Try using the convienence method for NSMutableArray... change:
NSMutableArray *arrayInMethod = [[NSMutableArray alloc] init];
To...
NSMutableArray *arrayInMethod = [NSMutableArray array];
array will return an autoreleased object.
First of all, I recommend you not to return a NSMutableArray from any method. It's better to use NSArray for that to avoid some very difficult to debug problems. My proposition is:
You declare the mutable array and populate it:
NSMutableArray *arrayInMethod = [[[NSMutableArray alloc] init] autorelease];
Then you return an autoreleased copy:
return [[arrayInMethod copy] autorelease];
And finally, when you take the returned array, you make it mutable again (only if you need to change it):
NSMutableArray *array = [[self methodThatReturnsAnArray] mutableCopy];
When you're done with the array, you release it:
[array release];

Problem with a NSMutableArray Leak

I thought I knew how to deal with memory leaks and arrays, but then this pops up. I can't figure pout why this is leaking:
// MyViewController.h
NSMutableArray *myMutableArray;
#property (nonatomic, retain) NSMutableArray *myMutableArray;
// MyViewController.m
#synthesize myMutableArray;
- (void) viewDidLoad {
if (self.myMutableArray == nil) {
self.myMutableArray = [[NSMutableArray alloc] init];
}
. . .
for (NSUInteger i = 0; i < someCount; ++i) {
[self.myMutableArray addObject:[NSString stringWithFormat: #"%#",myString]];
}
}
- (void)viewDidUnload {
self.myMutableArray = nil
}
- (void)dealloc {
[myMutableArray release];
}
Your problem is here:
if (self.myMutableArray == nil) {
self.myMutableArray = [[NSMutableArray alloc] init];
}
It should be:
if (myMutableArray == nil) {
self.myMutableArray = [[[NSMutableArray alloc] init] autorelease];
}
Or:
if (myMutableArray == nil) {
myMutableArray = [[NSMutableArray alloc] init];
}
Explanation:
Since you are using retain as a property mutator attribute, the object will be retained when it is passed to the property setter, therefore you have a leak when you retain an object you already have ownership of.
The solution to this is to either a) Pass an autorelease-d object to the property setter or b) Assign the ivar directly to the alloc-ed object.
You're allocating a new array, then setting it to a retain property. Change that line to
self.myMutableArray = [NSMutableArray array];
self.myMutableArray = [[NSMutableArray alloc] init];
should be
self.myMutableArray = [[[NSMutableArray alloc] init] autorelease];
because myMutableArray is a retained property.

How to properly release a NSMutableArray with objects that have a NSMutableArray member with NSNumber objects inside?

I'm puzzled about iOS memory management. I have a class that has a member of type NSMutableArray. When storing objects of this type in another array and removing them, Instruments shows that all those members leak memory. Here's the definition of my rogue class:
#interface Tester : NSObject {
int some;
NSMutableArray* others;
}
#property int some;
#property (nonatomic, retain) NSMutableArray* others;
-(id)init;
-(id)copy;
-(void)dealloc;
#end
Here's the implementation of the rogue class:
#implementation Tester
#synthesize some;
#synthesize others;
-(id)init {
self = [super init];
if(self) {
some = 0;
others = [[NSMutableArray alloc] initWithCapacity:5];
int i;
for(i = 0; i < 5; ++i) {
[others addObject:[NSNumber numberWithInt:i]];
}
}
return self;
}
-(id)copy {
Tester* cop = [[Tester alloc] init];
cop.some = some;
cop.others = [others mutableCopy]
return cop;
}
-(void)dealloc {
[others removeAllObjects];
[others release];
[super dealloc];
}
#end
And here's how I test it:
NSMutableArray* container = [[NSMutableArray alloc] init];
Tester* orig = [[Tester alloc] init];
int i;
for(i = 0; i < 10000; ++i) {
Tester* cop = [orig copy];
[container addObject:cop];
}
while([container count] > 0) {
[[container lastObject] release];
[container removeLastObject];
}
[container release];
Running this code leaks memory and Instruments shows that the leaked memory is allocated at line:
cop.others = [others mutableCopy];
What have I done wrong?
You are creating a copy: [others mutableCopy] which you own but forget to release. The line should be:
cop.others = [[others mutableCopy] autorelease];
You testing code would be clearer if you'd let the container array be the sole owner of the Tester objects:
NSMutableArray* container = [[NSMutableArray alloc] init];
Tester* orig = [[Tester alloc] init];
for (int i = 0; i < 10000; ++i)
[container addObject:[[orig copy] autorelease]];
while([container count] > 0)
[container removeLastObject];
[container release];
Now you could remove the loop that empties the container.
Or you could just skip the container:
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
Tester* orig = [[[Tester alloc] init] autorelease];
for (int i = 0; i < 10000; ++i)
[[orig copy] autorelease];
[pool drain]; // At this point all Tester objects are released
cop.others = [others mutableCopy]
Others is declared as a retained property, so assigning to it establishes an ownership claim on the new value. -mutableCopy is a method that implies ownership (because it contains the word "copy"). So you now have two claims of ownership, both of which must be released. The recommended way to do this is to assign the copy first to a temp variable, then assign that to your property and release it, like so:
NSMutableArray *tmpArray = [others mutableCopy];
cop.others = tmpArray;
[tmpArray release];
You could also do this in one step, avoiding the temp object, although doing so uses the autorelease pool and is slightly less efficient because of that:
cop.others = [[others mutableCopy] autorelease];

how to ask an array if an object is contained?

how can i ask an array if it contains an item and if it does it to [[NSArray alloc] initWithObjects:#"those objects" automatically.
this is my fav .h
#interface FavoriteViewController : UITableViewController {
NSMutableArray *favoritesArray;
NSMutableArray *didContain;
}
#property (nonatomic, retain) NSMutableArray *favoritesArray;
#property (nonatomic, retain) NSMutableArray *didContain;
this is the .m
favoritesArray = [[NSMutableArray alloc]init];
didContain = [[NSMutableArray alloc]init];
if
([favoritesArray containsObject:#"one"])
{
[didContain addObject:#"one"];
}
and in the detail view controller.m i have this code
[[NSMutableArray alloc] init];
[favoritesArray addObject: #"one"];
i get the table to work however nothing shows up....
NSArray *yourArray = [[NSArray alloc] initWithObjects:#"Hello", #"World", nil];
NSMutableArray *didContain = [[NSArray alloc] init];
if([yourArray contains: #"Hello"])
{
[didContain addObject:#"Hello"];
}
or
NSArray *yourArray = [[NSArray alloc] initWithObjects:#"Hello", #"World", nil];
NSMutableArray *didContain = [[NSArray alloc] init];
[didContain addObject: [yourArray objectAtIndex:[yourArray indexOfObject:#"Hello"]];
All of this and more is readily available in the apple docs. Please do some google searching first next time. Good luck hope this helps.
Use filteredArrayUsingPredicate:
See NSArray Class Reference and Predicate Programming Guide
It appears that you are trying to use an uninitialized property in your detail view controller.
Normally, you initialize properties in your init: or viewDidLoad method implementations then before presenting the view in your parent view controller, set the property using the property accessors
This line:
// DetailViewController.m initializer code
[[NSMutableArray alloc] init]; // returned object is not used
Should be:
favoritesArray = [[NSMutableArray alloc] init]; // view controller initialization code
Instead of calling this:
[favoritesArray addObject:#"one"];
After you create your detailViewController set the favoritesArray with the filtered array
// FavoriteViewController.m
MyDetailViewController *dvc = [[MyDetailViewController alloc] initWithNibName:#"MyDetailViewController" bundle:nil];
// populate the array
[dvc setFavoritesArray:didContain];
// Assuming you are using a navigation controller
[navigationController pushViewController:dvc animated:YES];
[dvc release];