EXC_BAD_ACCESS and Zombies, Yet not really sure why it keeps coming up - iphone

I don't know what's going wrong here. The crash happens when switching back and forth between views.
Here's what instruments gives me:
Clicking into it references this code with the first action :
-(IBAction)pushnews; {
NewsViewController *news = [[[NewsViewController alloc]init]autorelease];
news.title =#"Page";
[self.navigationController pushViewController:news animated:YES]; }
I use autorelease sometimes but usually I just release it my self. Should I get rid of autorelease and add [news retain]
What am I doing wrong?
Edit based on answers:
Following EmptyStack's Advice: ViewWillDisappear Code looks like this:
- (void)viewWillDisappear:(BOOL)animated {
webView.delegate = nil; }
This seems to resolve issues (pending more testing)
In viewdidload I said: webView.delegate = self;, which may have been the issue!

My guess is that, there is a UIWebView in NewsViewController, and it is causing the crash. It is possible that, a delegate method of web view is called after the web view is released. If so, try to setwebView.delegate = nil; in NewsViewController's viewWillDisappear: method.

try this instead :
-(IBAction)viewcontroller;
{
NewsViewController *news = [[NewsViewController alloc]init];
news.title =#"Page";
[self.navigationController pushViewController:news animated:YES];
[news release];
}

Related

Put FBLoginView in ViewDidLoad crash the app

I have put Facebook loginview code like this
(void)viewDidLoad {
[super viewDidLoad];
// Create Login View so that the app will be granted "status_update" permission.
loginview = [[FBLoginView alloc] init];
loginview.frame = CGRectOffset(loginview.frame, 5, 5);
loginview.delegate = self;
[self.view addSubview:loginview];
[loginview sizeToFit];
}
on first time when i logged in it works fine.But after logged in when i jump to this view from another view it crash the app.
What is the problem?I didn't get it.
I had this same problem. I fixed it by doing this:
-(void)viewWillDisappear:(BOOL)animated{
[super viewWillDisappear:animated];
// This isn't public, so you need to use performSelector...
[fbLoginView performSelector:#selector(unwireViewForSession)];
}
This is based on a bug report here:
https://github.com/buzztabapp/facebook-ios-sdk/commit/2301de144958a5502f9dae0a1bb7c234873581ba
maybe you could try this:
-(void)viewDidLoad
{
...
static id sharedInstance = self;
loginview.delegate = sharedInstance;
...
}
By creating your delegate view instance as static, you store it in the same scope than the facebook login view (which is created in static scope). You avoid bad access error.
I have quit a same problem while dismissing ViewController with FBLoginView.
I solved this problem by setting FBLoginView delegate to nil before calling dismissViewControllerAnimated:completion:
...
self.loginFBView.delegate = nil;
[self dismissViewControllerAnimated:NO completion:nil];

Reducing many similar methods to one parametrized method

I'm studying Objective-C.
A collegue left my company and I "inherited" her code. In a project, in a UIViewController class I found this code:
-(IBAction)goToSect1:(id)sender{
sect1=[[Sect1ViewController alloc]initWithNibName:#"SECT-1" bundle:nil];
[self presentModalViewController:sect1View animated:YES];
}
-(IBAction)goToSect2:(id)sender{
sect2=[[Sect2ViewController alloc]initWithNibName:#"SECT-2" bundle:nil];
[self presentModalViewController:sect2View animated:YES];
}
-(IBAction)goToSect3:(id)sender{
sect3=[[Sect3ViewController alloc]initWithNibName:#"SECT-3" bundle:nil];
[self presentModalViewController:sect3View animated:YES];
}
-(IBAction)goToSect4:(id)sender{
sect4=[[Sect4ViewController alloc]initWithNibName:#"SECT-4" bundle:nil];
[self presentModalViewController:sect4View animated:YES];
}
-(IBAction)goToSect5:(id)sender{
sect5=[[Sect5ViewController alloc]initWithNibName:#"SECT-5" bundle:nil];
[self presentModalViewController:sect5View animated:YES];
}
-(IBAction)goToSect6:(id)sender{
sect6=[[Sect6ViewController alloc]initWithNibName:#"SECT-6" bundle:nil];
[self presentModalViewController:sect6View animated:YES];
}
I consider this a little crazy, since we have six methods doing fundamentally the same thing. Is there a way to have only one parametrized method? How? Should I consider using the sender tag and a switch inside the body of my new method?
Thanks, any help is appreciated.
-(IBAction)goToThisViewControllerByUsingThisSection:(id)sender{
// Here I assume you are using this function with UIButton or other controls.
// If so, then you have to assign a tag for each section button or do as needed by your app.
// If you call this method in didselectrowatindexpath in delegate of UITableView then simply do use:
// indexPath.section instead of sender.tag
NSString *sectionWithViewController=[NSString stringWithFormat:#"Sect%iViewController",sender.tag];
Class classNam=NSClassFromString(sectionWithViewController);
UIViewController *unKnownViewController=[[classNam alloc]initWithNibName:[NSString stringWithFormat:#"SECT-%i",sender.tag] bundle:nil];
[self presentModalViewController:unKnownViewController animated:YES];
}
I wouldn't alter it at all. Those are IBActions, meaning that something in your interface is binded to them, more than likely buttons. So you have 6 buttons on your UI, each lead to a different view controller.
With the current way you have it, you can alter the individual functionality of each button without having to worry about affecting the others. Otherwise you wild be binding all those buttons to the same method, and then inside the method have to do a check for which button it is. At best, you will get rid of 5 lines of code and introduce 6 more. So the change will actually reduce readability and increase your number of lines of code.
In my opinion you should just leave it like that. The other option would be to have a single method like this:
-(IBAction)goToSection:(id)sender{
//Check the sender and then allocate depending on sender...
}
And simply bind the same method to all the buttons...
In my opinion that would look a lot worst.
There is not much you can do as mentioned by others.
Some suggestions:
If you use appropriate naming or change your init this line can be from
[[Sect1ViewController alloc] initWithNibName:#"SECT-1" bundle:nil];
to
[[Sect1ViewController alloc] init];
Either name the xib after the controller like Sect1ViewController or Sect1View or change your init for the class
// Sect1ViewController.m
- (id)init
{
self = [super initWithNibName:#"SECT-1" bundle:nil];
if (self) {
// ...
}
return self
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
return [self init];
}
Generally a viewController has a better idea what xib it should use than any calling code and this keep encapsulation.
May be a bad idea but included so you can see some things you can do
This structure of the method is repeating. I am not 100% you need to hold onto the viewController you are creating as the presenting controller will take a
retain on it.
With this in mind we can DRY this code up slightly like so
-(IBAction)goToSect1:(id)sender{
[self presentClass:[Sect1ViewController class]];
}
-(IBAction)goToSect2:(id)sender{
[self presentClass:[Sect2ViewController class]];
}
-(IBAction)goToSect3:(id)sender{
[self presentClass:[Sect3ViewController class]];
}
-(IBAction)goToSect4:(id)sender{
[self presentClass:[Sect4ViewController class]];
}
-(IBAction)goToSect5:(id)sender{
[self presentClass:[Sect5ViewController class]];
}
-(IBAction)goToSect6:(id)sender{
[self presentClass:[Sect6ViewController class]];
}
- (void)presentClass:(Class)class;
{
UIViewController *viewController = [[class alloc] init];
[self presentModalViewController:viewController animated:YES];
[viewController release]; viewController = nil;
}
}
This does not scale well as for every new button you need to add a new action even though they do the same thing - yuk
try that:
-(IBAction)goToSect:(id)sender{
if (sender /*do your check here*/)
{
sect=[[Sect1ViewController alloc]initWithNibName:#"SECT-1" bundle:nil];
}else if (sender /*another check*/){
sect=[[Sect2ViewController alloc]initWithNibName:#"SECT-2" bundle:nil];
} //other checks
[self presentModalViewController:sect1View animated:YES];
}
you will need all these if-checks because there are different ViewControllers. If they are pretty much the same I'd just leave 1 and pass/change some parameters.
hope it helps

presentModalViewController memory leak or EXC_BAD_ACCESS

-(void) addBookmarkTapped:(id)sender {
BookmarkAddViewController *bookmarkAddViewController =
[[BookmarkAddViewController alloc] initWithName:currTitle link:self.addressBar.text];
[self presentModalViewController:bookmarkAddViewController animated:YES];
[bookmarkAddViewController release];
}
code above cause 'EXC_BAD_ACCESS' when back to the main controller. Same error if I make bookmarkAddViewController 'autorelease'.
It will not crash if I remove the release, but it will cause memory leak?
[bookmarkAddViewController release];
I see many examples doing the same way, why it doesn't work in my case?
It might have to do with your init method in bookmarkAddViewController.(Please post.) Make sure you dismiss the controller properly with [self dismissModalViewControllerAnimated:YES];.

memory bad access?

How can this statement ever give me bad access?
myWebView = [[NewsWebViewController alloc] initWithNibName:#"NewsWebViewController" bundle:nil];
[[self.view.superview superview] addSubview:myWebView.view];
if(myWebView!=nil) {
[myWebView release];
myWebView = nil;
}
Ive ran it through instruments and it crashes every time. myWebView is an ivar in my header file.
Any thoughts? Many thanks
Jules
ok here is the actual issue. When I removed the webview it gets dealloc'd but I didnt set its delegate to nil. Therefore webViewDidFinishLoading etc was trying to access it and giving me bad access.
Thanks to all for your input.
You should check that myWebView is nil before you add it's view to a subview. You do not need to set myWebView to nil after you release it.
You are setting mywebview to nil after releasing so it crashes as the object no longer exists. Do it in this order:
if(myWebView!=nil) {
myWebView = nil;
[myWebView release];
}

presentModalViewController in viewDidLoad on first launch

I've been searching around but unfortunately have had no luck.
My app requires the user to sign in/sign up the first time he or she launches the app. I know how to determine first launch (using NSUserDefaults) but whenever I try to present the modal containing the sign in/ sign up controls, nothing happens.
Here's what I have:
-(void)viewDidLoad {
[self showLogin];
[super viewDidLoad];
}
-(void)showLogin {
FlipsideViewController *controller = [[FlipsideViewController alloc] initWithNibName:#"AccountView" bundle:nil];
controller.delegate = self;
controller.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self presentModalViewController:controller animated:YES];
[controller release];
}
However, nothing happens. The main view just loads as normal. Any help is greatly appreciated.
-Giles
[UPDATE]
Fixed simply by using..
-(void)viewDidAppear:(BOOL)animated
{
}
instead of
-(void)viewDidLoad
{
}
Thanks anyway!
/idiocy
I had the same issue and ended up using viewDidAppear as well. The only problem with the viewDidAppear approach is that if you load other UIViewControllers on top, then reshow the base, then your setup code gets called over and over. I ended up having to add a boolean value (initialised to YES) to this view controller and check that value before deciding what to do. Hope this helps someone...
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:(BOOL)animated];
if(justLaunched)
{
justLaunched = NO;
if(settingsFileExists)
{
[self displayMainView];
}
else
{
[self displaySetupView];
}
}
}
How about using performSelector:withObject:afterDelay in the viewDidLoad function? That's how I do it, with a short delay of 0.1s.
And invoking this in the viewDidLoad isn't very safe : the sequence viewDidLoad / viewDidUnload can occur at runtime when the iPhone needs to release some views in order to get back some free memory.
The side effect of such sequence would be that your login controller would be shown...
As you said the viewDidAppear looks better but not simply put it at the end of the appDidFinishedLaunching the delegate of your UIApplication?