i'm new on Objective-C programming and i'm having the typical memory problems. I must do an app based on navigation controller and when passing few views (using push view controller), load an animation of 100 images. In the simulator works well, but on the phone not... I open up different animations and then it closes. I'm using arc to avoid that, but it seems not to be working. I've also tried to disable arc and release the UIImageView manually but it crashes even quickly. Here's an example of one of that views:
//.h
#interface Gegant_nou : UIViewController {
IBOutlet UIImageView *ImageViewGegant;
}
#property (nonatomic, strong) UIImageView* ImageViewGegant;
//.m
- (void)viewDidLoad {
[super viewDidLoad];
UIBarButtonItem *rigthButton = [[UIBarButtonItem alloc] initWithTitle:#"Detalls" style:UIBarButtonItemStyleBordered target:self action:#selector(canviarDetalls)];
self.navigationItem.rightBarButtonItem = rigthButton;
[rigthButton release];
ImageViewGegant.animationImages =#
[[UIImage imageNamed:#"0001.png"],
[UIImage imageNamed:#"0002.png"],
. load all the images
.
[UIImage imageNamed:#"0099.png"],
[UIImage imageNamed:#"0100.png"]];
ImageViewGegant.animationDuration = 4;
ImageViewGegant.animationRepeatCount = 0;
[ImageViewGegant startAnimating];
[self.view addSubview:ImageViewGegant];
self.title = #"Gegant nou";
[ImageViewGegant release];
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)didReceiveMemoryWarning{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (void)viewDidUnload{
[super viewDidUnload];
[ImageViewGegant release];
}
Any idea of why happens? Thank you for helping me!
It would be easier to assist you if you provided some crashlog or stacktrace to provide more information about where the problem lies.
Are you totally sure the problem is memory related at all? Since you are using ARC it is pretty unlikely unless you have parts of your codebase where you don't use ARC or if you use c libraries like CoreGraphics etc, where you still need to retain/release even if you use ARC.
If you do have memory problems with say overrelease and you get a EXC_BAD_ACCESS crash, you can try to enable zombies in your app by Product -> Edit scheme.. -> Diagnostics and then "Enable Zombie objects". This will hopefully provide more information of the objects that are causing the problem.
On a completely different topic, I would strongly advice you to write all instance variables with camelcase. It is confusing to read, most developers will assume "ImageViewGegant" is the name of a class.
Problem solved! What was happening was that I was using UIImageNamed to load the animation, and although I was using ARC, UIImageNamed loads the image but don't releases it, so it loads all the frames and fills the memory very quickly. Now I don't have that memory problems. Thanks for all!
Related
I've been at this for a few hours now. I've got several View Controllers in this project and not a single one is causing issues but now all of a sudden this new one is. I even deleted it and made a "Test" View Controller, but no dice. The best I can tell it is not actually creating its view, thus when the view is referenced the app crashes. The test VC has no added or deleted code except for a log statement in the -viewDidLoad method. I am not overriding -loadView. I have tried adding the view to a subview, have tried pushing the VC into the Navigation Controller, I have even tried simply logging test.view. I have tried creating the VC with a NIB and have tried it without one. Absolutely nothing works at all. Any help will be appreciated.
Where VC is being created inside of another VC. The log statment causes the crash. But so does adding as a subview and even pushing into nav controller.
TestViewController *test = [[TestViewController alloc] init];
NSLog(#"test view = ", test.view);
Implementation of TestViewController.
#implementation TestViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
NSLog(#"view = %#", self.view);
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
I'd say to double check all the connections from the view. Especially if its been copied or moved as its easy to leave a connection to an old VC
if you are not using ARC in your project then dont check the autolayout box for the nib file. If you are using ARC then the connections of it to the file's owner can be the only issue.
if you use xib,and the items is copied from other xib or storyboard ,make sure the root view is exist,and drag tothe file's owner.
I have a table view that when a cell is selected it pushes a view controller onto the navigation stack:
SAPostTableViewController *postViewController = [[SAPostTableViewController alloc] initWithNibName:NSStringFromClass([SAPostTableViewController class]) bundle:nil];
postViewController.site = site;
[self.navigationController pushViewController:postViewController animated:YES];
[postViewController release];
SAPostTableViewController has a static tableView which, and it's cells, are loaded from a nib.
I have overridden the initWithNibName:bundle: method:
-(id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
self.sections = [NSMutableDictionary dictionary];
}
return self;
}
sections is a retained property.
In viewDidLoad of SAPostTableViewController I have this:
- (void)viewDidLoad
{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(cellVisibiltyChanged:) name:#"SAStaticCellVisibiltyChanged" object:nil];
}
and so to match in viewDidUnload:
- (void)viewDidUnload
{
[super viewDidUnload];
[[NSNotificationCenter defaultCenter] removeObserver:self name:#"SAStaticCellVisibiltyChanged" object:nil];
}
However when I press the back button in the navigation bar (all standard behaviour, no override) and SAPostTableViewController is popped, it doesn't call viewDidUnload or dealloc. So this means that if I then reselect the cell that pushes SAPostTableViewController it creates a new instance of SAPostTableViewController and repeating this back and forward just means the memory usage keeps increasing as the popped SAPostTableViewControllers never get deallocated. (I know this by running Instruments on allocations)
The weird thing is that if I release SAPostTableViewController twice then it works as I'd expect:
SAPostTableViewController *postViewController = [[SAPostTableViewController alloc] initWithNibName:NSStringFromClass([SAPostTableViewController class]) bundle:nil];
postViewController.site = site;
[self.navigationController pushViewController:postViewController animated:YES];
[postViewController release];
[postViewController release];
(If I add a third release statement, it crashes as I'd expect it to with just 2)
I have resorted to using retainCount and stepped through the lines of code the are executed in the first line of the directly above code, the retainCount remains at 1. It jumps up between the first and second line, so I can't see anywhere it is being retain an extra time?
The SAPostTableViewController is only used in this place, it is not a delegate of anything, nor does it have a delegate.
How can I find a fix, or is it something simple I've missed?
Here is what Instruments shows after pushing SAPostTableViewController just once (with only one release statement):
And what it shows after navigating back and forth repeatedly (again, one release statement):
You are creating a new Object when you clic one Cell, why you don't create your Object (SAPostTableViewController) in the init Method and then Push the same object watch time you click in Cell
you can do something like this :
postViewController = [[SAPostTableViewController alloc] initWithNibName:NSStringFromClass([SAPostTableViewController class]) bundle:nil];
and in the
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
postViewController.site = site;
[self.navigationController pushViewController:postViewController animated:YES]; [postViewController release];
}
I don't know what your problem is, but here are some things to consider:
You should absolutely NOT release the view controller twice. If you have indeed discovered a memory leak in UIKit (which is unlikely), then it is likely it would be fixed in a future version of UIKit. That means that anyone running an old version of your app on a new version of the operating system would experience nothing but crashes (due to over-releasing the view controller). It is better to leak than to crash. A leaky app is still a usable app (at least until you leak too much). But a crashing app can't be run at all.
-viewDidUnload is not doing what you think it should be doing. It is only called when the view controller's view is unloaded due to memory pressure. It is not called during normal deallocation. It would be wiser to rely on -viewWillAppear: and -viewDidDisappear: instead.
A quick rundown of whats happening here.
I've got a GameScene and a GameOverUIController. When Game ends, It loads the GameOverUIController, which loads the xib, which loads the MobFoxBannerView.
Here's the issue: If you push the "play again" button to fast or you play a round longer than about 3 minutes, the ad loads in the background but essentially has no where to go, and crashes.
I took a friends advice of adding the ViewDidUnload to set the bannerview to nil, but it still crashes... I'm not the most amazing programmer admitted, but I feel like I'm making the dumbest error somewhere... Any help is greatly appreciated. Am I just using the wrong syntax on something here?
I've done the following things.
I synthesize bannerView on the GameOverUI Implementation.
Manually adding it to the view now, before I had added a UIwebview directly to xib Interface builder for GameOverUIController
self.bannerView = [[[MobFoxBannerView alloc] initWithFrame:CGRectMake(0, 0, 320, 50)] autorelease];
bannerView.delegate = self;
[self.view addSubview:bannerView];
[self.view bringSubviewToFront:bannerView];
And thats in my main implementation. So everytime it loads the GameOver Screen it requests a new add.
Then I set the values in the header file.
-(NSString *) publisherIdForMobFoxBannerView:(MobFoxBannerView *)banner;
#property (nonatomic, retain) MobFoxBannerView *bannerView;
and set my publisher ID in the the bottom of GameOverUIController.m
- (NSString *)publisherIdForMobFoxBannerView:(MobFoxBannerView *)banner
{
return #"xxxxxxxxxxxx";
}
Then... STILL get a crash so then I tried to set it to nil hoping that would work... but I'm not sure about the syntax...
On GameOverUIController.m
- (void)viewDidUnload
{
[super viewDidUnload];
self.bannerView = nil;
// or ? bannerView.delegate = nil;
}
Niether of those lines works..... I'm at a total loss. Going to move onto another ads platform unless I can figure this out before the weekend is over. Bane of my existence right now. Any help would be greatly appreciated. Thank you very much
Edit:
Figured it out...
Had nothing to do with ViewUnload....
- (void)dealloc
{
bannerView.delegate = nil;
[super dealloc];
}
Was adding it to the wrong location... Works perfectly now.
I guess your problem is in
bannerView.delegate = self;
when add is loaded (because of bad internet it can be very slow for instance) - delegate method is being called, but "self" is released - so runtime exception is thrown.
By the way, I don't know a thing about MobFox framework. It's just a common anti-pattern.
I'm having some trouble with a UITableView. It loads perfectly the first time I open it, but after the second try its not getting into the viewDidLoad method which causes the data not be refreshed on my tableview. I also made the proper release on my dealloc method. Any ideas about this? I've looked thru google but I didnt get anything useful. Thanks a lot for all the help you can provide me!
Here are my viewDidLoad and viewDidUnload methods
- (void)viewDidLoad
{
[super viewDidLoad];
saved_news.rowHeight =85;
addButton = [[UIBarButtonItem alloc] initWithTitle:#"Edit" style:UIBarButtonItemStyleBordered target:self action:#selector(edititems:)];
[self.navigationItem setLeftBarButtonItem:addButton];
[self setSaved:[CoreData sharedInstance].selectItems];
[saved_news reloadData];
}
- (void)viewDidUnload
{
[super viewDidUnload];
saved = nil;
saved_news = nil;
addButton =nil;
}
viewDidLoad and viewDidUnload are typically called only once during the lifetime of a controller (unless there's a low memory situation). I think what you are looking to use here are the viewDidAppear: and viewDidDisappear: methods.
Call
- (void)viewWillAppear:(BOOL)animated;
- (void)viewDidAppear:(BOOL)animated;
as you require load table here
[Yourtablename reloaddata];
Hope this helps..
I feel like I don't understand something fundamental here. I've been working on memory management in my app while using Instruments to check out live allocations. I have a modal view controller (settingsViewController) that has an image for a background. One thing I noticed was that even after settingsViewController dealloc is called, there still is a live Malloc 520 KB, ImageIO is the responsible library. I'd expect live memory to drop back down after dismissing settingsViewController. Is the UIImageView still hanging around somewhere?
Here is how I load the image in viewDidLoad, as well as dismiss the view controller when I'm finished.
- (void)loadView {
[super loadView];
////// background ////////
UIImageView *background = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"settings_background.png"]];
[self.view addSubview:background];
[background release];
//////////////////////////
}
- (void)viewDidLoad {
[super viewDidLoad];
///////// done button //////////
UIBarButtonItem *done = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:#selector(doneButtonPressed)];
self.navigationItem.leftBarButtonItem = done;
[done release];
////////////////////////////////
}
- (void) doneButtonPressed {
[self dismissModalViewControllerAnimated:YES];
}
- (void)dealloc {
NSLog(#"settingsViewController dealloc"];
[super dealloc];
}
At this point, this is all that is in the settingsViewController, so no need to do anything special in dealloc, right? Here is how I'm showing testViewController in the rootViewController.
- (void) loadSettingsView {
SettingsViewController *settingsViewController = [[SettingsViewController alloc] init];
UINavigationController *settingsNavigationController = [[UINavigationController alloc] initWithRootViewController:settingsViewController];
[self presentModalViewController:settingsNavigationController animated:YES];
[settingsViewController release];
[settingsNavigationController release];
}
I'd like to make sure I understand what is going on before moving forward. I have several different modal view controllers, each with a different image as a background. Since each one creates a Malloc 520 KB, I end up using 2-3 MB of precious memory for no good reason. What is holding on to that 520 KB?
When you use the +[UIImage imageNamed:] method, the framework caches the image data for you. That's why you see it hold onto some memory even after your view is released. If you're working in the simulator and you want to see it release that memory, send the simulator a memory warning after you've dismissed your view. The image framework should then release the cached image data.