I have created two view controllers in which there is UIImage animations.Its crashing frequently and showing memory leaks in xcode instrument.
My Controllers Code-
- (void)viewDidLoad {
NSArray *firstArray;
firstArray = [NSArray arrayWithObjects:
[UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"up0001" ofType:#"png"]],
[UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"up0002" ofType:#"png"]],
::
::
[UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"up0035" ofType:#"png"]], nil];
imgView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 1024, 768)];
imgView = UIViewContentModeScaleToFill;
[imgView setAnimationImages:firstArray];
imgView.animationDuration = 1.75;
imgView.animationRepeatCount = 0;
[imgView startAnimating];
[self.view addSubview: imgView];
}
- (void)dealloc {
[super dealloc];
[imgView release];
imgView = nil;
}
And I am changing viewcontrollers as my rootviewcontroller by getting appdelegate object and calling following appdelegate function in my Appdelegate.m(Please suggest any good approach)
- (void)changeRootViewController:(NSString *)controllerName
{
if(self.viewController){
[self.viewController.view removeFromSuperview];
self.viewController=nil;
}
if (controllerName == #"ViewController") {
ViewController *lviewController =[[ViewController alloc] initWithNibName:#"ViewController" bundle:nil];
self.viewController = (RootViewController *)lviewController;
[lviewController release];
lviewController.view = nil;
[self.window setRootViewController:self.viewController]; //LEAKS 100%
} else if (controllerName == #"MainViewController") {
// Use a different VC as roowViewController
MainViewController *lviewController =[[MainViewController alloc] initWithNibName:#"MainViewController" bundle:nil];
self.viewController = (RootViewController *)lviewController;
[lviewController release];
lviewController.view = nil;
[self.window setRootViewController:self.viewController]; //LEAKS 100%
} else if (controllerName == #"SecondViewController") {
// Use a different VC as roowViewController
SecondViewController *lviewController =[[SecondViewController alloc] initWithNibName:#"SecondViewController" bundle:nil];
self.viewController = (RootViewController *)lviewController;
[lviewController release];
lviewController.view = nil;
[self.window setRootViewController:self.viewController]; //LEAKS 100%
}
[self.window makeKeyAndVisible];
}
And calling this in my respective controlers button pressed as -
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
[appDelegate changeRootViewController:#"ViewController"];
OR
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
[appDelegate changeRootViewController:#"MainViewController"];
I want to manage view controllers from my main controller swapping controllers in and out without Navigationbar.Please help me figure out the best possible approach and avoid leaks as well.
Look at this piece of code:
if (controllerName == #"ViewController") {
ViewController *lviewController =[[ViewController alloc] initWithNibName:#"ViewController" bundle:nil];
self.viewController = (RootViewController *)lviewController;
[lviewController release];
lviewController.view = nil;
[self.window setRootViewController:self.viewController]; //LEAKS 100%
}
When you alloc "lviewController", its retain count is 1;
when you do "self.viewController" as I suppose viewController is a retained property, then lviewController retain count is increased to 2;
then you release it, balancing the previous alloc, and retain count returns to 1;
finally you assign it to rootViewController, which is a retained property, so again lviewController retain count is 2;
finally when you "swap" view controller in your window, the lviewController is released, so it retain count becomes 1. As you can see, it will never be dealloc'd. This means that each time you call this function, you make a leak.
You require to change some of your statement in your code ..
This line have no meaning ..
imgView = UIViewContentModeScaleToFill;
There is a function by using that you have to set the value of the UIImageView property to UIViewContentModeScaleToFill find that in a UIImageView documentation.
[imageView setContentMode:UIViewContentModeScaleToFill];
The same with this...
lviewController.view = nil; //Remove this from your code ..
And finally change the implmentation for the dealloc function and remember [super dealloc]; should be in the last in any implementation of dealloc .
- (void)dealloc {
[imgView release];
imgView = nil;
[super dealloc];
}
The probable leak is due to the code inside "SecondViewController", "MainViewController", "ViewController" classes. And the reason for crash is you are releasing image view after [super dealloc]
try this,
- (void)dealloc {
[imgView release];
imgView = nil;
[super dealloc];
}
Related
I have 1 tabbarcontroller have Login and Complete Tab. I want to click on Logout button in LoginTab, all data and tableview in COmplete tab is reset. I used this code but it not work:
In CompleteTab.m:
-(void) viewDidLoad
{
temp = [[NSMutableArray alloc] init];
iduploadArray= [[NSMutableArray alloc] init];
FileCompletedArray = [[NSMutableArray alloc] init];
DiffArr= [[NSMutableArray alloc] init];
_tableView = [[UITableView alloc] initWithFrame:self.view.bounds];
tableData = [[NSArray alloc] initWithObjects:FileCompletedArray,nil];
// [_tableView setAllowsSelection:YES];
//tableView.dataSource = self;
// [self.view addSubview:tableView];
// [self parseXMLFile:#"x"];
NSURL *url1 = [NSURL URLWithString:#"server.com"];
AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL: url1] ;
....
temp = [FileCompletedArray mutableCopy];
_tableView.dataSource = self;
_tableView.delegate=self;
[self.view addSubview:_tableView];
}
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"error: %#", error);//: %#", operation.responseString);
}
];
[httpClient enqueueHTTPRequestOperation:operation];
}
-(void) resetAll
{
[temp removeAllObjects];
[FileCompletedArray removeAllObjects];
[DiffArr removeAllObjects];
[_tableView reloadData];
}
In LoginTab.m:
- (IBAction)LogoutButton:(id)sender {
login = false;
username.hidden = NO;
pass.hidden = NO;
LoginButton.hidden = NO;
LogoutButton.hidden = YES;
//make all the arrays get reset
username.text =#"";
pass.text = #"";
[completeview resetAll];
}
I debug: when I click on Logout button,it called resetAll() function but each variable is 0x000000. So it cannot reset data and reload tableview. Can you help me? Thanks
Since the logout button is in loginTab, it doesnot have any reference to your completeTab. So you need to keep the completeTab reference some where in your app. Best choice is in appDelegate. Then on logout button click, take this instance and reset all data.
Keep your completab view controller instance in AppDelegate like this
#property (nonatomic, retain) UIViewController *completeTab;
self.completeTab = \\Your complete tab viewcontroller instance.
Then on logout button click
[(AppDelegate *)[[UIApplication sharedApplication] delegate].completTab resetAll]
Hope this helps.
Use the selector to call the reset method like this
[completeview performSelector:#selector(resetAll)];
Please create sample project with Tabbased Application.
====== AppDelegate.m ======
#import "LoginTab.h"
#import "CompleteTab.h"
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
// Override point for customization after application launch.
UIViewController *viewController1 = [[[LoginTab alloc] initWithNibName:#"LoginTab" bundle:nil] autorelease];
UIViewController *viewController2 = [[[CompleteTab alloc] initWithNibName:#"CompleteTab" bundle:nil] autorelease];
self.tabBarController = [[[UITabBarController alloc] init] autorelease];
self.tabBarController.viewControllers = #[viewController1, viewController2];
self.window.rootViewController = self.tabBarController;
[self.window makeKeyAndVisible];
return YES;
}
#end
====== LoginTab.m ======
#implementation LoginTab
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
self.title = NSLocalizedString(#"LoginTab", #"LoginTab");
self.tabBarItem.image = [UIImage imageNamed:#"LoginTab"];
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (IBAction)LogoutButton:(id)sender {
// Post Notification to CompleteTab Class
[[NSNotificationCenter defaultCenter]
postNotificationName:#"resetAll"
object:self];
}
====== CompleteTab.m ======
#implementation CompleteTab
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
self.title = NSLocalizedString(#"CompleteTab", #"CompleteTab");
self.tabBarItem.image = [UIImage imageNamed:#"CompleteTab"];
}
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(resetAll:)
name:#"resetAll"
object:nil];
return self;
}
- (void) dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super dealloc];
}
- (void) resetAll:(NSNotification *) notification
{
NSLog(#"Reset All Called");
}
I am able to call resetAll method of CompeteTab using NSNotification Concept. Please follow this code.
I'd also recommend you check out the free Sensible TableView framework as it has such restting functionality out of box.
As for the method [tableView reloadData] : The table view's delegate or data source calls this method when it wants the table view to completely reload its data. It should not be called in the methods that insert or delete rows, especially within a block implemented with calls to beginUpdates and endUpdates.
I believe you are calling the reloadData in resetAll which is updating the FileCompletedArray which provides the dataSource for the table. Can you call it from somewhere else.
How do I access a previous view controller while in a subview? Because I'm able to perform actions but I'm just not able to use self.[my main view controller].
This is my code, for testing purposes:
PhotoViewController.m
-(IBAction)likeButton:(UIButton *)sender
{
//this part works
NSString *num = #"2";
self.label.text = [NSString stringWithFormat:#"%# + %#",
self.label.text,
num];
//this part doesn't work
//switch over to the third view to see if it worked
self.tabBarController.selectedIndex = 0;
}
I have a UITabBarController and one of its view controllers has a UIScrollView. Inside of the UIScrollView is a PhotoViewController object.
AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch
MyTabBarViewController *vc2 = [[MyTabBarViewController alloc] init];
SecondViewController *vc3 = [[SecondViewController alloc] init];
controller = [[DemoAppViewController alloc] init];
controller.view.frame = CGRectMake(0, 20, 320, 460);
controller.title = #"Intro Screen";
vc2.title = #"Explore";
vc3.title = #"Send a Pic";
UITabBarController *tbc = [[UITabBarController alloc] init];
tbc.viewControllers = [NSArray arrayWithObjects:controller, vc2, vc3, nil];
[controller release];
[vc2 release];
[vc3 release];
[self.window addSubview:tbc.view];
[self.window makeKeyAndVisible];
return YES;
}
Also, my TabBarViewController.m //not my actual UITabBarController though, wording is confusing
- (void) viewWillAppear:(BOOL)animated
{
[super viewWillAppear:YES];
arrayCount = [array count];
scroller.delegate=self;
scroller.pagingEnabled=YES;
scroller.directionalLockEnabled=YES;
scroller.showsHorizontalScrollIndicator=NO;
scroller.showsVerticalScrollIndicator=NO;
//should have an array of photo objects and the number of objects, correct?
scrollWidth = 0;
scroller.contentSize=CGSizeMake(arrayCount*scroller.frame.size.width, scroller.frame.size.height);
for (int i = 0; i < arrayCount;i++) {
PhotoViewController *pvc = [[PhotoViewController alloc] initWithNibName:#"PhotoViewController" bundle:nil];
UIImageView *scrollImageView = [[UIImageView alloc] initWithFrame:CGRectOffset(scroller.bounds, scrollWidth, 0)];
CGRect rect = scrollImageView.frame;
pvc.view.frame = rect;
pvc.label.textColor = [UIColor whiteColor];
id individualPhoto = [array objectAtIndex:i];
NSLog(#"%#",individualPhoto);
NSArray *keys=[individualPhoto allKeys];
NSLog(#"%#",keys);
NSString *imageURL=[individualPhoto objectForKey:#"source"];
NSURL *url = [NSURL URLWithString:imageURL];
NSData *data = [NSData dataWithContentsOfURL:url];
pvc.imageView.image = [[UIImage alloc] initWithData:data];
pvc.label.text = [individualPhoto objectForKey:#"id"];
[scroller addSubview:pvc.view];
[scrollImageView release];
//[pvc release];
scrollWidth += scroller.frame.size.width;
}
if (arrayCount > 3) {
pageControl.numberOfPages=3;
} else {
pageControl.numberOfPages=arrayCount;
}
pageControl.currentPage=0;
}
If a UIView subclass needs to message a controller above itself, a common (and often recommended?) way to do this is to have the view subclass implement the delegate protocol (a weak linked instance variable pointing to the view controller that you want to use). The view controller should then set itself as the delegate of the view when that view is being initialize.
Try defining this method in your PhotoViewController:
+ (YOURTABBARCONTROLLER*)parentTabBarController:(UIResponder*)view {
id nextResponder = nil;
id v = view;
while (nextResponder = [v nextResponder]) {
NSLog(#"Found Responder: %#", nextResponder); //-- ADDED THIS
if ([nextResponder isKindOfClass:[YOURTABBARCONTROLLER class]])
return nextResponder;
v = nextResponder;
}
return nil;
}
it will traverse the responder chain and return the first controller of a given type that is found. Replace YOURTABBARCONTROLLER with your actual tab bar controller class and you should be able to have:
-(IBAction)likeButton:(UIButton *)sender
{
//this part works
NSString *num = #"2";
self.label.text = [NSString stringWithFormat:#"%# + %#",
self.label.text,
num];
[PhotoViewController parentTabBarController:self.view].selectedIndex = 0;
// self.tabBarController.selectedIndex = 0;
}
Updated
-(IBAction)likeCommentButton:(UIButton *)sender
{
//code goes here
TypeSomethingViewController *typeSomethingViewController = [[TypeSomethingViewController alloc] init];
typeSomethingViewController.delegate = self;
[self presentModalViewController:typeSomethingViewController animated:YES];
[typeSomethingViewController release];
}
-(void)typeSomethingViewController:(TypeSomethingViewController *)controller didTypeSomething:(NSString *)text
{
//NSLog(#"response: %#", controller);
NSString *commentID = self.label.text;
for(UIViewController *controller in [PhotoViewController parentTabBarController:self.parentViewController.view].viewControllers)
{
if([controller isKindOfClass:[DemoAppViewController class]])
{
DemoAppViewController *davc = (DemoAppViewController *)controller;
//[davc commentPicture:commentID :message];
[davc likePicture:commentID];
}
}
[PhotoViewController parentTabBarController:self.view].selectedIndex = 0;
[self dismissModalViewControllerAnimated:YES];
}
Try this out to switch to the first controller.
self.tabBarController.selectedViewController
= [self.tabBarController.viewControllers objectAtIndex:0];
Change the index value to switch to whichever controller you want to switch to.
The tabBarController should be a property of the app delegate.
Try accessing it with :
MyAppDelegate *appDelegate = (MyAppDelegate *)[[UIApplication sharedApplication]
delegate];
appDelegate.tabBarController.selectedIndex = 0;
Unless you declare the same property in PhotoViewController, you won't be able to access it this way.
Try importing the app delegate header in PhotoViewController.h like so :
#import "MyAppDelegate"
then try this code above replacing tabBarController by tbc which, as the example suggests is the name given to this property.
I'm trying to create an application that allows users to go through a set of images like a magazine. I've got one UIView class on top of the AppDelegate and on swipe to the left/right I'm either going forward or backward a page. My problem is that when I swipe and change the image source the program keeps allocating more memory, and I'm not certain where/how to release the previously allocated memory. I've looked in to the difference between imageNamed and imageWithContentsOfFile and I believe I'm using those correctly so I'm stumped. Any help would be much appreciated!
AppDelegate.h
#interface AppDelegate : NSObject {
UIWindow *window;
MagazineWebViewController *webViewController;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) IBOutlet MagazineWebViewController *webViewController;
- (void)goToA:(NSNumber *)page;
#end
AppDelegate.m
#implementation AppDelegate
#synthesize window, webViewController;
- (void)applicationDidFinishLaunching:(UIApplication *)application {
webViewController = [[MagazineWebViewController alloc] init];
NSNumber *page = [NSNumber numberWithInt:1];
[webViewController setPage:page];
[window addSubview:webViewController.view];
[window makeKeyAndVisible];
}
- (void)goToA:(NSNumber *)page {
UIImage *image = [[UIImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:#"%#", page] ofType:#"png"]];
webViewController.imageView.image = image;
[image release];
[webViewController setPage:page];
}
- (void)dealloc {
[webViewController release];
webViewController = nil;
[window release];
[super dealloc];
}
#end
MagazineWebViewController.h
#interface MagazineWebViewController : UIViewController {
UIImageView *imageView;
NSNumber *page;
}
#property (nonatomic, assign)NSNumber *page;
#property (nonatomic, retain)UIImageView *imageView;
- (void)swipeLeft;
- (void)swipeRight;
- (void)tableOfContents;
#end
MagazineWebViewController.m
#implementation MagazineWebViewController
#synthesize page, tocController, imageView;
- (id)init {
UINavigationBar *navBar = [[UINavigationBar alloc] initWithFrame:CGRectMake(0, 0, 768, 60)];
navBar.tintColor = [UIColor blackColor];
UIBarButtonItem *contents = [[UIBarButtonItem alloc] initWithTitle:#"Table of Contents" style:UIBarButtonItemStylePlain target:self action:#selector(tableOfContents)];
UINavigationItem *item = [[UINavigationItem alloc] initWithTitle:#"Title"];
item.leftBarButtonItem = contents;
item.hidesBackButton = YES;
[navBar pushNavigationItem:item animated:NO];
[contents release];
[item release];
[self.view addSubview:navBar];
[navBar release];
self.imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 40, 768, 984)];
UIImage *image = [[UIImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"1" ofType:#"png"]];
self.imageView.image = image;
[image release];
self.imageView.contentMode = UIViewContentModeScaleToFill;
UISwipeGestureRecognizer *swipeLeft = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(swipeLeft)];
swipeLeft.direction = UISwipeGestureRecognizerDirectionLeft;
[self.view addGestureRecognizer:swipeLeft];
[swipeLeft release];
UISwipeGestureRecognizer *swipeRight = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(swipeRight)];
swipeRight.direction = UISwipeGestureRecognizerDirectionRight;
[self.view addGestureRecognizer:swipeRight];
[swipeRight release];
[self.view addSubview:self.imageView];
[self.imageView release];
return self;
}
- (void)swipeLeft {
int pageNum = [page intValue];
if (pageNum < 115) {
pageNum++;
UIViewAnimationTransition trans = UIViewAnimationTransitionCurlUp;
[UIView beginAnimations:nil context:nil];
[UIView setAnimationTransition:trans forView:self.view.window cache:YES];
BaseballMagazine2011AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
[appDelegate goToA:[NSNumber numberWithInt:pageNum]];
[UIView commitAnimations];
}
}
- (void)swipeRight {
int pageNum = [page intValue];
if (pageNum > 1) {
pageNum--;
UIViewAnimationTransition trans = UIViewAnimationTransitionCurlDown;
[UIView beginAnimations:nil context:nil];
[UIView setAnimationTransition:trans forView:self.view.window cache:YES];
BaseballMagazine2011AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
[appDelegate goToA:[NSNumber numberWithInt:pageNum]];
[UIView commitAnimations];
}
}
- (void)tableOfContents {
}
- (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 {
[imageView release];
imageView = nil;
[page release];
page = nil;
[tocController release];
tocController = nil;
[super viewDidUnload];
}
- (void)dealloc {
[imageView release];
imageView = nil;
[page release];
page = nil;
[super dealloc];
}
#end
In your AppDelegate.m, Try prefacing each reference to webViewController with 'self.'. For example:
self.webViewController = [[MagazineWebViewController alloc] init];
By not referencing the property with self, you are bypassing the properties auto generated setters and getters. And since you set this property to retain, this would bypasses some memory handling logic. I'm pretty sure that is your issue... Hope this helps!
I think it's because you alloc every time an UIImage (like said in the comments).
Did you try not doing allocations ?
self.imageView.image = [ UIImage imageNamed:#"1.png" ];
I think you won't have any problem with this.
But it's difficult to say where come from the leak without all your program ^^
Maybe a retain property or something like that.
I have a viewcontroller that repeatedly repositions 6 items within a uiscrollview. However, even though I've limited the number of items within the uiscrollview to 6, I'm still leaking memory when i update their position and their image. Can someone let me know if the following code which represents a unit within the uiscrollview is properly coded? startLoad is the method that I call after to reload the image.
#import "ScrollUnit.h"
#implementation ScrollUnit
#synthesize index;
#synthesize ProductToDisplay;
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
// Initialization code.
}
return self;
}
-(void)startLoad
{
[imageview removeFromSuperview];
[imageview release];
NSOperationQueue *queue = [NSOperationQueue new];
NSInvocationOperation *operation = [[NSInvocationOperation alloc]
initWithTarget:self
selector:#selector(loadImage)
object:nil];
[queue addOperation:operation];
[operation release];
}
-(void)loadImage
{
NSString *myimageName = [self.ProductToDisplay valueForKey:IMAGEKEY];
NSString *myimageUrl = [NSString stringWithFormat:#"%#/%#",IMAGE_SERVICE,myimageName];
NSData* imageData = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:myimageUrl]];
UIImage* image = [[[UIImage alloc] initWithData:imageData] autorelease];
[imageData release];
[self performSelectorOnMainThread:#selector(displayImage:) withObject:image waitUntilDone:NO];
}
- (void)displayImage:(UIImage *)image
{
imageview = [[[UIImageView alloc] initWithFrame:CGRectMake(9, 0, 320, 320)]retain];
imageview.contentMode = UIViewContentModeScaleAspectFit;
imageview.backgroundColor = [UIColor whiteColor];
imageview.image = image;
[self addSubview:imageview];
[imageview release];
//[image release];
}
- (void)dealloc {
[super dealloc];
}
#end
Get rid of the retain message on this line and you should be all set:
imageview = [[[UIImageView alloc] initWithFrame:CGRectMake(9, 0, 320, 320)]retain];
The reason why you need to do this is because you already own the object by calling alloc, so at that point, the relative reference count is 2.
Once you invoke addSubview:, passing in the imageview, the reference count gets bumped to 3, then right back down to 2 once you release it on the next line.
So once that object gets sent release in -dealloc, you're still stuck because the reference count is now 1, not 0 as you expected.
There is also another little thing that might bug (or not). You don't release imageview before you assign it in displayImage method. As long as only startLoad is called you are fine but if displayImage is called from the outside then you still leak.
You might want to use a property with retain and then synthesis the getter and setter methods. This way the iOS will release your previous assignment before it retains your new assigned object. That said then you need to release created image view right were you create it and you have to use "self.imageview" in order to make sure that you use the setter (setImageview).
I have a big problem since a few days that I can't solve.
First I have a login view controller with this code :
#implementation MMConnectionViewController
#synthesize login, password, activityIndicator, mainVC;
- (BOOL)textFieldShouldReturn:(UITextField *)aTextField
{
[aTextField resignFirstResponder];
[self performSelectorOnMainThread:#selector(startRolling) withObject:nil waitUntilDone:NO];
[NSThread detachNewThreadSelector:#selector(connect) toTarget:self withObject:nil];
return YES;
}
- (void)viewWillAppear:(BOOL)flag {
[super viewWillAppear:flag];
[login becomeFirstResponder];
login.keyboardAppearance = UIKeyboardAppearanceAlert;
password.keyboardAppearance = UIKeyboardAppearanceAlert;
[self setTitle:#"Monaco Marine"];
UIBarButtonItem *backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:#"Logout"
style:UIBarButtonItemStyleBordered
target:nil
action:nil];
self.navigationItem.backBarButtonItem = backBarButtonItem;
[[UIApplication sharedApplication] setStatusBarStyle: UIStatusBarStyleBlackOpaque];
[backBarButtonItem release];
}
- (void)connect {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
mainVC = [[MMMainViewController alloc] initWithLogin:login.text password:password.text connectPass:#"1" navigationController:self.navigationController nibName:#"MMMainViewController" bundle:nil];
if (mainVC) {
[self performSelectorOnMainThread:#selector(dataLoadingFinished) withObject:nil waitUntilDone:YES];
}
[pool release];
}
- (void)dataLoadingFinished {
self.stopRolling;
[self.navigationController pushViewController:mainVC animated:YES];
}
- (void)showAlertWithMessage:(NSString *)message {
self.stopRolling;
NSLog(#"%#",message);
UIAlertView *warning = [[UIAlertView alloc] initWithTitle:#"Connection Failed" message:[NSString stringWithFormat:#"%#",message] delegate:self cancelButtonTitle:#"Retry" otherButtonTitles:nil];
[warning show];
[warning release];
}
- (void)startRolling {
[activityIndicator startAnimating];
}
- (void)stopRolling {
[activityIndicator stopAnimating];
}
- (void)viewDidLoad {
[login becomeFirstResponder];
}
- (void)dealloc {
[login release],login=nil;
[password release],password=nil;
[activityIndicator release],activityIndicator=nil;
[super dealloc];
}
After, there's MMMainViewController with this code :
#implementation MMMainViewController
#synthesize login, password, connectPass, navigationController, accountVC;
- (void)viewDidLoad {
// Set a title for each view controller. These will also be names of each tab
accountVC.title = #"Account";
accountVC.tabBarItem.image = [UIImage imageNamed:#"icon_user.png"];
self.view.frame = CGRectMake(0, 0, 320, 480);
// Set each tab to show an appropriate view controller
[self setViewControllers:
[NSArray arrayWithObjects:accountVC, nil]];
[navigationController setNavigationBarHidden:NO animated:NO];
UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithTitle:#"Menu"
style:UIBarButtonItemStyleBordered
target:nil
action:nil];
self.navigationItem.backBarButtonItem = backButton;
[backButton release];
[self setTitle:#"Menu"];
}
// The designated initializer. Override if you create the controller programmatically and want to perform customization that is not appropriate for viewDidLoad.
- (id)initWithLogin:(NSString *)l password:(NSString *)p connectPass:(NSString *)c navigationController:(UINavigationController *)navController nibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
UIView *contentView = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];
contentView.backgroundColor = [UIColor whiteColor];
self.view = contentView;
[contentView release];
login = l;
password = p;
connectPass = c;
navigationController = navController;
if (!accountVC)
accountVC = [MMAccountViewController alloc];
[self.accountVC
initWithNibName:#"MMAccountViewController" bundle:nil];
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
return self;
}
- (void)dealloc {
[connectPass release];
[login release];
[password release];
[super dealloc];
}
The layer MMAccountViewController loaded from MMMainViewController is a basic view controller with nothing in it.
Now the problem is that sometimes when load my tabbed view controller and I go back to the login view controller, the screen freezes and bug with message (NSZombieEnabled = YES) :
*** -[CALayer retain]: message sent to deallocated instance 0xd0199d0
This is all I have and I really can't see where I'm wrong.
Some more idea?
Thanks for those who help me!
You are overreleasing something somewhere. You might want to run your application in Instruments to check where it may be happening (XCode: Run->Run With Performance Tool->Leaks will give you the setup that you need afaik). I can't see anything in your code, but you said yourself that you use "roughly" this code, so it may not be in this part of your program.
Update:
I still can't see that you overrelease something somewhere... I'm pretty sure the problem is not within this part of the code. If you haven't found the problem yet, you may want to try and create a test case, that is, a small program that tries to mimic this programs behavior and reproduce the bug. If you can reproduce it within a small program, I'll take a look at that.
I was also encounter the same problem, and the problem was that I was assigning a UIButton to the rightNavigationItem and release that button instance, I just remove the release code and started working.