Passing a dictionary from view controllers - iphone

In one of my Navigation view controllers I build an array of dictionaries to display in a table. Based on which one I select I then remove the dictionary from the array using
NSDictionary *notice = [notices objectAtIndex: roomIndex];
I create the new view controller using
Feed *notice_view = [[Notice alloc] initWithObject: notice];
I push the navigation view controller and I've implemented initWithObject which takes a Dictionary.
I release the notice and notice_view and all this works fine but if I selected go back, select it go back about the third or forth time the whole app crashes. If I dont release both of them it works fine no problems what so ever, except of course the memory leaks.If i only release one of them, either of them, it fails again. What gives? Should I not be using initWithObject or should I be passing it in some other way? I've also tried using autorelease but with the same result.

notice - you should not release, since you don't own the object(you are just using a object which is returned from NSArray) else retain this object when you retrieve the object from NSArray and release it later stage.
notice_view - as per you explanation I don't see any issue with releasing, I am assuming you don't have any reference to this object from other part of the code.

I'm guessing you'll want to get rid of [selectedNotice release], since there doesn't seem to be a corresponding -retain call in there.

Related

How to remove a childviewcontroller using objectAtIndex

I got a ViewController where I add many childs on like this:
[self addChildViewController:myViewController];
After this I want to remove some of the childs dependent on where I am in my program to free up memory. So I was thinking of something like this:
[self.childViewControllers objectAtIndex:1]
and then use removeFromParentViewController. But how can I provide this code on objectAtIndex?
I also tried: [self.childViewControllers objectAtIndex:1] = nil;
But this doesn't work, I get the error that the expression is not assignable.
You can get an array of view controllers by doing "[self.navigationController viewControllers]".
Then you can get any one of them via "objectAtIndex:" on that array.
When you get any one of them, you can call removeFromParentViewController" on that view controller.
However, I wouldn't do what you're trying to do. This is going to likely to confuse the heck out of your users, who were navigating through your app thinking they came from one specific view controller, only now when they back up they're going back to somewhere unexpected.

Releasing after pushing in iOS

So I have the following code where I am releasing an object after pushing it to another view. When I analyse it I get the error - Incorrect decrement of the reference count of an object that is not owned at this point by the caller. Would anyone know how to fix this? I've tried so many options each time getting a different memory leak
- (void)showCurrentArticle:(id)sender {
if(animating)
return; //it is already there
animating = YES;
JsonViewController *newsController = [(JsonViewController *)[self.newsNavController.viewControllers objectAtIndex:0]retain];
newsNavController.title = #"Parliament";
Item *currentItem = (Item *)[self.fetchedObjectsArray objectAtIndex:currentItemIndex];
NSString * urlString = [CONST_FEED_DISCRIPTION_URL stringByAppendingString:currentItem.guid];
[newsController initWithURLString:urlString date:currentItem.date];
[self.navigationController pushViewController:newsController animated:YES];
[newsController release];
}
This code takes a view controller that's already present in the navigation stack, reinitialises it, then pushes it onto the stack again. This doesn't seem right at all. You probably should be creating a new view controller. What's the background on this? What are you trying to achieve?
You are popping, change a title, than you are doing an initialization...
Decide if you will do deep clone of JsonViewController (alloc, init, copy field values) or just reference copy (retain). It will be mess later if you try to mix.
Your retain and release of the newsController object are unnecessary. That is why you are getting the warning. It looks like newsController is owned by the newsNavController object, which will retain it. The only reason you would need to retain newsController in this code is if you needed to use it outside the scope of this method. Since you don't need to retain it, you don't need to release it, hence the error. You may be assuming that the -initWithURLString:date: method is incrementing the retain count, but it is only new, alloc, and retain that do this. You should probably rename that method to not use the term init to avoid confusion.
What are you doing with -initWithURLString:date:??? Are you just adding a url? Then you should call it addURL...... If you really initialize it again, you set the pointer of the newsController variable to a new object. The first object it pointed to gets lost -> leak.
I assume you named the init method wrong and just add a url to a controller, which is already in the stack and add it again with a higher retain count, but still the very same object.
Don't do this. Copy the object or better - create a new instance of the viewController!!!

Table view data sources running twice, scope issue

I have a UITableView where numberOfSectionsInTableView and numberOfRowsInSection are being called twice, with scope issues on the second run. If I mask the problem, I get a scope issue on the first run of cellForRowAtIndexPath.
Most data all comes from an NSDictionary which is configured during viewDidLoad. I also have an NSArray configured at the same time. Once set they are never changed nor released.
When numberOfSectionsInTableView is called the first time, it's fine. Counts the elements as needed etc. It's then immediately called a second time (no idea why). On the second run, it cannot access the NSDictionary or NSArray items. Crash even when trying to NSLog them. For example:
NSLog(#"theMainDictionary %#",theMainDictionary);
usually results in EXC_BAD_ADDRESS but occasionally something like this:
theMainDictionary <_UITableViewSeparatorView: 0x4e73680; frame = (0 307; 320 1); opaque = NO; autoresize = W; layer = <CALayer: 0x4e4bf20>>
Again, this same line runs fine (logging the dictionary as expected) the first run through.
If I mask the problem by returning a fixed NSInteger, numberOfRowsInSection then does the same thing. If I mask numberOfRowsInSection, cellForRowAtIndexPath crashes on the first run. Same issue though - can't access theMainDictionary or the related NSArray.
I can't figure out why they're running twice - there's no reloadData anywhere. Nor do I know why the second call runs any differently. Any assistance greatly appreciated.
You're probably creating your dictionary with [NSDictionary dictionary] or one of the several similar factory methods (which returns an autoreleased instance), and then saving it directly to an ivar without retaining it. It will work fine until your program gets back to the main run loop, at which time the autorelease will resolve and the object gets freed.
There are a few ways to fix it:
Assign to a property declared retain rather than an ivar. This means self.theMainDictionary rather than just theMainDictionary. This will retain it for you, so it will stick around until you release it (or assign a different dictionary or nil to the property).
Use [[NSDictionary alloc] init] (or one of the many other init methods) rather than [NSDictionary dictionary] style. This returns an instance that you own, so it will stick around until you release it.
Explicitly call retain on the dictionary when saving it to the ivar. This takes ownership, so it will stick around until you release it.
In all cases, do remember to release the dictionary in your dealloc method, or the memory will leak.
All of the above probably applies to the array too. See Apple's documentation for a much more detailed explanation of memory management in Cocoa.

EXC_BAD_ACCESS error when my view controller tries to access a singleton variable a second time

I have an app i building which is a simple naviagtion app. I do not want to load the data from my xml multiple times so I am using a singleton to load and hold the data. My first table pushes the view of the second table. This table calls the singleton and the get the array of data from there to display in the table.
This all works fine, I click on a cell in the first table which takes me to the second table where the singleton is used. I navigate back to the the first table, then back to the second table, this is when i get the EXC_BAD_ACCESS error. It doesn't error when i init the singleton but when I try and access the array in it. The code is as follows
MediaData *dataClass = [MediaData sharedManager];
//when i check in the singleton the second time sharedManager is already there
sortedData = dataClass.arrMediaData; //this line errors the second time
NSLog(#"sorted array. %#", sortedData);
[dataClass release];
Any help would be great as it is not a very descriptive error, thanks
The last line in your code is causing the issue. Singletons shouldn't be released.
As Jasarien said, don't release the singleton.
You can use NSZombieEnabled and run on a device to get more descriptive errors: http://www.cocoadev.com/index.pl?NSZombieEnabled

Core Data - How to check if a managed object's properties have been deallocated?

I've created a program that uses core data and it works beautifully.
I've since attempted to move all my core data methods calls and fetch routines into a class that is self contained. My main program then instantiates that class and makes some basic method calls into that class, and the class then does all the core data stuff behind the scenes. What I'm running into, is that sometimes I'll find that when I grab a managed object from the context, I'll have a valid object, but its properties have been deallocated, and I'll cause a crash. I've played with the zombies and looked for memory leaks, and what I have gathered is it seems that the run loop is probably responsible for deallocating the memory, but I'm not sure.
Is there a way to determine if that memory has been deallocated and force the core data to get it back if I need to access it? My managedObjectContext never gets deallocated, and the fetchedResultsController never does, either.
I thought maybe I needed to use the [managedObjectContext refreshObject:mergeData:] method, or the [managedObjectContext setRetainsRegisteredObjects:] method. Although, I'm under the impression that last one may not be the best bet since it will be more memory intensive (from what I understand).
These errors only popped up when I moved the core data calls into another class file, and they are random when they show up.
Any insight would be appreciated.
-Ryan
Sounds to me like you are not retaining objects you want to keep hanging around. If you are doing something like this:
NSArray *array = [moc executeFetchRequest:request error:&error];
you do not own the returned array and it will most likely disappear when the current autorelease pool is drained. This will occur when the run loop finishes processing the current event.
All this is speculation. If you want a proper answer, you need to post your code.
It's hard to know what the problem is based on your description, but you might want to look at the Core Data memory management guide. You shouldn't have to worry about memory management for managed objects and their entities (they're fetched and faulted automatically). When you talk about "properties," do you mean custom properties backed by ivars? If so, these should be released in didTurnIntoFault and allocd as needed (probably in the accessor).
I was struggling with a similar issue. I'm using a managed object class and want to set its properties dependent on user input. But the sometimes the properties and sometimes the whole managed object were deallocated.
After reading the Apple documentation http://developer.apple.com/library/IOs/#documentation/Cocoa/Conceptual/CoreData/Articles/cdMemory.html the chapter "The Role of the Managed Object Context" I learned that managed objects are released each run loop completes.
And there is the golden advice to set
[myMangedObjectContext setRetainsRegisteredObjects:YES];
(I had to set it in the init method (initWithNibName for me) of my view controller.)
You should also regard to retain only the objects you need to as explained in the documentation. But read it yourself.
If I'm not right please correct me.
I also made a class that handles all my CoreData fetching and stuff. I ran into a couple of gotcha's, so here are some tips. (If I am making any memory management errors in these examples, please let me know.)
Two things:
1) Made a "fetchFiredObject" method in the CoreData handler class. So when I want to get a managedObject that has all its variables and is a "fully feathered bird" so to speak, instead of doing:
aManagedObject *myManagedObject = [myCoreDataHandler.managedObjectStorageArray objectAtIndex:1];
int x = myManagedObject.someVariable.intValue;
instead I do:
aManagedObject *myManagedObject = [myCoreDataHandler fetchFiredObjectAtIndex:1];
int x = myManagedObject.someVariable.intValue;
And in myCoreDataHandler's fetchFiredObjectAtIndex:i method, we're going into the array, finding the object key at index i, then doing a fetchRequest for that object key, and returning the freshly-fetched managedObject so that it won't have been faulted or deallocated, etc. :D
2) When I create a new child viewController, I populate its "myCoreDataHandler" value from the parent upon creation. However, this happens on a subsequent line of code after the line of code that creates the new viewController. Therefore, any code in the child's viewDidLoad that tries to use myCoreDataHandler's methods will return empty objects because viewDidLoad completes before the parent's next line of code where it sets the values of globals in the child object. So make sure you are not accessing your "Core Data handling object" from within viewDidLoad or anything local methods called by viewDidLoad! Instead call them from the parent after creating the new viewController.