Problem with memory manament in Objective-C - iphone

I have a method:
-(NSArray *)doSomething{
NSArray *array = [[NSArray alloc] initWithObjects:#"Huy 1",#"Huy 2",#"Huy 3",nil];
[array release];
return array;
}
and
- (void)viewDidLoad {
[super viewDidLoad];
NSArray *array = [self doSomething];
if(array&&array.count>0){
NSLog([NSString stringWithFormat:#"%#\n",[array objectAtIndex:1]]);
}
else{
NSLog(#"Null");
}
}
I thinks i released array on doSomething() so it won't return NSArray which i created on doSomething(). I don't know it still print "Huy 2"? Anybody can tell me why?

-(NSArray *)doSomething
{
NSArray *array = [[NSArray alloc] initWithObjects:#"Huy 1",#"Huy 2",#"Huy 3",nil];
return [array autorelease];
}
Memory Management Programming Guide
- (void)viewDidLoad
{
[super viewDidLoad];
NSArray *array = [self doSomething];
if([array count]) //if array is nil this will evaluate to false. If count is 0 this will evaluate to false too.
{
NSLog(#"%#\n", [array objectAtIndex:1]); //NSLog insert values for you
}
else
{
NSLog(#"Null");
}
}
If this works with release instead of autorelease it's probably because the memory that the array was using has yet to be used by anything else. This is just chance. I suspect that if you allocate an object after NSArray *array = [self doSomething]; you will get unexpected results.

Use the method in following way:
-(NSArray *)doSomething{
NSArray *array = [[NSArray alloc] initWithObjects:#"Huy 1",#"Huy 2",#"Huy 3",nil];
return [array autorelease];
}

Related

Memory-management in iOS Programming

I have a little problem with memory management in my iOS App. I load an XML and set all Values in this XML to Spezific Objects. Now my problem is when i reload the XML every 15 - 20 reloads of this XML my app Crash on Parsing here is a sample of my parser.
EDIT: Here ist the ERROR when NSZombie is Enabled if NSZombie is disabled I didn't get an ERROR message.
-[CFNumber retain]: message sent to deallocated instance
thanks for help.
EDIT:
the beginning of my Code:
- (id)init
{
self = [super init];
if (self) {
TheObjects *theObjects = [[TheObjects alloc] init];
[self parse];
}
return self;
}
- (void) reload{
reload = YES;
TheObjects *theTmpObjects = [[TheObjects alloc] init];
[self parse];
}
- (void)parse{
for (id xmlOBject in xmlObjects){
MyObject *object = [[MyObject alloc] init];
object.number1 = [NSNumber numberWithInt:1];
object.number2 = [NSNumber numberWithInt:2];
object.number3 = [NSNumber numberWithInt:3];
if (reload)
[theTmpObjects.objects addObject:object];
else
[theObjects.objects addObject:object];
[object release];
}
//later in my code
TheObjects *localTheTmpObjects = nil;
if (reload){
localTheTmpObjects = theObjects;
theObjects = theTmpObjects;
}
if ([delegate respondsToSelector:#selector(finished:)]){
[delegate performSelector:#selector(finished:) withObject:theObjects];
}
if(reload)
[localTheTmpObjects release];
}
remove the line [localTheTmpObjects release]
you don't own the object
at the end, call the `[localTheTmpObjects autorelease];`
this is because if you release array, all its objects are released and hence may cause crash, when your array may in use
- (id)init
{
self = [super init];
if (self) {
TheObjects *obbjects = [[TheObjects alloc] init];
theObjects = objects;
[objects releas];
[self parse];
}
return self;
}
- (void) reload{
reload = YES;
TheObjects *obbjects = [[TheObjects alloc] init];
thetmpObjects = objects;
[objects releas]; [self parse];
}
- (void)parse{
for (id xmlOBject in xmlObjects){
MyObject *object = [[MyObject alloc] init];
object.number1 = [NSNumber numberWithInt:1];
object.number2 = [NSNumber numberWithInt:2];
object.number3 = [NSNumber numberWithInt:3];
if (reload)
[theTmpObjects.objects addObject:object];
else
[theObjects.objects addObject:object];
[object release];
}
//later in my code
TheObjects *localTheTmpObjects = nil;
if (reload){
localTheTmpObjects = theObjects;
theObjects = theTmpObjects;
}
if ([delegate respondsToSelector:#selector(finished:)]){
[delegate performSelector:#selector(finished:) withObject:theObjects];
}
}

Obj-C, iOS, can someone explain this NSMutableArray code and suggest how I can sort on the name?

Can someone exlain this code in detail and suggest how I can sort on the name?
- (void)handleSearchForTerm:(NSString *)searchTerm {
selectButton.enabled = NO;
NSMutableArray *sectionsToRemove = [[NSMutableArray alloc] init];
[self resetSearch];
for (NSString *key in self.keys) {
NSMutableArray *array = [Categories valueForKey:key];
NSMutableArray *toRemove = [[NSMutableArray alloc] init];
for (NSString *name in array) {
if ([name rangeOfString:searchTerm
options:NSCaseInsensitiveSearch].location == NSNotFound)
[toRemove addObject:name];
}
if ([array count] == [toRemove count])
[sectionsToRemove addObject:key];
[array removeObjectsInArray:toRemove];
[toRemove release];
}
[self.keys removeObjectsInArray:sectionsToRemove];
[sectionsToRemove release];
[table reloadData];
}
- (void)handleSearchForTerm:(NSString *)searchTerm {
selectButton.enabled = NO;
NSMutableArray *sectionsToRemove = [[NSMutableArray alloc] init]; //creating an mutable array, which can be altered in progress.
[self resetSearch]; //calling some other method not displayed in the code here
for (NSString *key in self.keys) { //for each key,
NSMutableArray *array = [Categories valueForKey:key]; //you get the key's category
NSMutableArray *toRemove = [[NSMutableArray alloc] init]; //and initialize the array for items you wish to remove
for (NSString *name in array) { //then, for each name
if ([name rangeOfString:searchTerm options:NSCaseInsensitiveSearch].location == NSNotFound)
[toRemove addObject:name];
//you check if the name is in range of the searchterm, with which you call this function
//if you don't find it, you add it to the removal list
}
if ([array count] == [toRemove count])
[sectionsToRemove addObject:key]; //if you haven't found any name, it means you've added all the names in the toRemove array
[array removeObjectsInArray:toRemove]; //that means the count of both arrays are the same
[toRemove release]; //so you remove that section entirely, since there is no result there
}
[self.keys removeObjectsInArray:sectionsToRemove]; //you remove all the keys which aren't found
[sectionsToRemove release]; //leaving you the keys which are found
[table reloadData]; //you reload the table with the found results only
}
I hope it all made sense, I did my best commenting it ;)
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];

EXC_BAD_ACCESS in viewDidLoad of FlipsideViewController

I'm trying to display some data on the flip side view of a utility template application but the application aborts at the end of viewDidLoad method. I'm very new to iOS and could do with a bit of guidance.
[super viewDidLoad];
self.view.backgroundColor = [UIColor viewFlipsideBackgroundColor];
NSString *thePath = [[NSBundle mainBundle] pathForResource:#"SavedData"ofType:#"plist"];
NSMutableDictionary *tempRootDictionary;
NSMutableArray *tempMutableArray;
if (thePath && (tempRootDictionary = [NSMutableDictionary dictionaryWithContentsOfFile:thePath])) {
NSArray *keys = [tempRootDictionary allKeys];
int keysCount = [keys count];
tempMutableArray = [NSMutableArray arrayWithCapacity:keysCount];
for (int i=0; i<keysCount; i++) {
NSDictionary *dictionary = [tempRootDictionary objectForKey:[keys objectAtIndex:i]];
MyModelObject *aModelObject = [[MyModelObject alloc] init];
[aModelObject setName:[dictionary objectForKey:#"name"]];
[aModelObject setContext:[dictionary objectForKey:#"context"]];
[aModelObject setUsername:[dictionary objectForKey:#"username"]];
[aModelObject setPassword:[dictionary objectForKey:#"password"]];
[tempMutableArray addObject:aModelObject];
[aModelObject release];
[dictionary release];
}
} else {
return;
}
Help would be really appreciated,
Many thanks...
The only obvious problem I see in the code posted is this:
[dictionary release];
On the line that you set dictionary, you are only getting a reference to the object in tempRootDictionary and not a new alloc'd instance of it. So don't release it. Remove that line.

Memory leaks in NSMutableDictionary

My coding contains a memory leak, and somehow I can't find the leak.
Leaks points me in the direction of the way I create "ReportDetailItems"
e.g. areaContainer = [[[ReportDetailItem alloc] init] autorelease];
I've been looking at this for hours and I am at a total loss, the objects reported leaking are "ReportDetailItem", and the NSMutableDictionary contained in those objects.
Please advice.
------[ReportDetailItem.h
#interface ReportDetailItem : NSObject
{
NSNumber *total;
NSMutableDictionary *items;
}
#property (nonatomic, retain) NSNumber *total;
#property (nonatomic, retain) NSMutableDictionary *items;
- (NSString *)description;
#end
------[ReportDetailItem.m
#synthesize items, total;
- (id)init {
if (self = [super init]) {
self.items = [NSMutableDictionary dictionaryWithCapacity:0];
DLog("Alloc: %d", [items retainCount]);
}
return self;
}
- (NSString *)description {
return #"ReportDetailItem";
}
- (void)release {
[super release];
}
- (void)dealloc {
[self.items release];
[self.total release];
items = nil;
total = nil;
[super dealloc];
}
#end
------[Leaking code
NSError *error;
NSArray *data = [self.managedObjectContext executeFetchRequest:request error:&error];
if (data == nil || [data count] == 0) {
DLog(#"No data.")
} else {
for (int i=0; i < [data count]; i++) {
TaskEntity *task = [data objectAtIndex:i];
NSString *areaKey = task.activity.project.area.title.text;
NSString *projectKey = task.activity.project.title.text;
NSString *activityKey = task.activity.title.text;
ReportDetailItem *areaContainer;
if (![dataSource objectForKey:areaKey]) {
areaContainer = [[[ReportDetailItem alloc] init] autorelease];
} else {
areaContainer = [dataSource objectForKey:areaKey];
}
areaContainer.total = [NSNumber numberWithInt:([task.seconds intValue] + [areaContainer.total intValue])];
[dataSource setObject:areaContainer forKey:areaKey];
ReportDetailItem *projectContainer;
if (![areaContainer.items objectForKey:projectKey]) {
projectContainer = [[[ReportDetailItem alloc] init] autorelease];
} else {
projectContainer = [areaContainer.items objectForKey:projectKey];
}
projectContainer.total = [NSNumber numberWithInt:([task.seconds intValue] + [projectContainer.total intValue])];
[areaContainer.items setObject:projectContainer forKey:projectKey];
ReportDetailItem *activityContainer;
if (![projectContainer.items objectForKey:activityKey]) {
activityContainer = [[[ReportDetailItem alloc] init] autorelease];
} else {
activityContainer = [projectContainer.items objectForKey:activityKey];
}
activityContainer.total = [NSNumber numberWithInt:([task.seconds intValue] + [activityContainer.total intValue])];
[projectContainer.items setObject:activityContainer forKey:activityKey];
}
}
I found it, the leak was located in the way I allocated the "dataSource"
---[Leak
- (void)viewDidLoad {
[super viewDidLoad];
self.dataSource = [[NSMutableDictionary alloc] init];
[self fetchData];
}
---[No leak
- (void)viewDidLoad {
[super viewDidLoad];
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
self.dataSource = dict;
[dict release];
[self fetchData];
}
I'm pretty skeptic about the two ways u assign pointers to the ReportDetailItem. Why are you trying to autorelease the object in the first place? If not try this
ReportDetailItem *projectContainer;
if (![areaContainer.items objectForKey:projectKey]) {
projectContainer = [[ReportDetailItem alloc] init];
} else {
projectContainer = [[areaContainer.items objectForKey:projectKey] retain];
}
projectContainer.total = [NSNumber numberWithInt:([task.seconds intValue] + [projectContainer.total intValue])];
[areaContainer.items setObject:projectContainer forKey:projectKey];
if(projectContainer) {
[projectContainer release];
projectContainer = nil;
}