UIAccelerometer EXC_BAD_ACCESS crash on device - iphone

I am facing a bit strange problem with implementation of UIAccelerometer.
I have a UITableViewController where I don't wanna use UIAccelerometer, but after pressing on of the rows I wanna activated one inside a UIViewController, everything is fine when I use simulator, but when I use device iPhone 3G to test it, I got EXC_BAD_ACCESS by pressing return button.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
ShakeControl *percView = [[ShakeControl alloc] init];
// ...
// Pass the selected object to the new view controller.
[self.navigationController pushViewController:percView animated:YES];
[percView release];
}
It works fine when I disable [percView release];, but it does not sounds like solution for.
Any Idea would be appreciated.
Shake control implementation:
- (void)viewDidLoad {
[super viewDidLoad];
[[UIAccelerometer sharedAccelerometer] setUpdateInterval:1.0 / kUpdateFrequency];
[[UIAccelerometer sharedAccelerometer] setDelegate:self];
}
- (void)viewDidUnload {
[super viewDidUnload];
[[UIAccelerometer sharedAccelerometer] setDelegate:nil];
}
Thx

The viewDidUnload method will get called only in specific case, such as memory warning. You have to remove the delegate in dealloc too.

Try releasing it after you dismiss it, I'm not sure if pushViewController retains.

You could setting the environment variables NSZombiesEnabled & NSAutoreleaseFreedObjectCheckEnabled with a value of 1.
This will prevent objects from really being deallocated, then you should get console logs indicating where the over-release is coming from.
You could use Run With Performance Tools -> Allocations once you know which object is being over-released and see every location where a retain/release was called to spot the imbalance.

Related

ABPeoplePickerNavigationController crashes while being dismissed in Simulator only

I get this crash in the simulator only. On a real device it works and debugs fine.
(Therefore it is not too critical but I am working on a presentation for which the simulator comes handy.)
- (BOOL)peoplePickerNavigationController:
(ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person {
[self displayPerson:person];
if ([self respondsToSelector:#selector(dismissViewControllerAnimated:completion:)]){
[self dismissViewControllerAnimated:YES completion:nil];
} else {
[self dismissModalViewControllerAnimated:YES];
}
return NO;
}
The crash is on:
[self dismissViewControllerAnimated:YES completion:nil];
All I see is: "Thread 1: EXC_BREAKPOINT (code=EXC_I386_BTP, subcode=0x0)"
There is no specific output in the debug window. Zoombies is enabled. I do ARC. I am using storyboard but I call the ABPersonPicker... programmatically using the following code:
-(void)showPeoplePickerController
{
ABPeoplePickerNavigationController *picker = [[ABPeoplePickerNavigationController alloc] init];
picker.peoplePickerDelegate = self;
if ([self respondsToSelector:#selector(presentViewController:animated:completion:)]) {
[self presentViewController:picker animated:YES completion:nil];
} else {
[self presentModalViewController:picker animated:YES];
}
return;
}
Remember that it is running well on the devices that I have (iPod Touch 4th gen, iPhone 4 and iPhone 4S)
Your problem is that you don't keep a strong reference to the picker. Add a ivar to hold it, then when done in the delegate callback, use a dispatch asyn block on the main queue to nil the ivar out and release it. (Sorry no code entering this from an iPad)
EDIT: look in your showPeoplePickerController method - you create the picker and save it in an automatic which gets released when you exit the method. You want to keep a strong reference to the picker by using an ivar instead of the automatic.
Then you don't want to release the picker in a delegate callback - this often works but will bite you at unexpected times, so you want to release this type of object after the delegate callback is done. In fact I usually set the objects delegate property to nil first if I can then release it with 'picker = nil' . In a block 'picker' gets turned into 'self->picker'. You can also use performSelector:afterDelay:0 too I just prefer blocks.
EDIT2: So what I do in
- (BOOL)peoplePickerNavigationController:shouldContinueAfterSelectingPerson:
is just return NO. I wait until this message:
- (void)peoplePickerNavigationControllerDidCancel:
to dismis it. I also have some other code that pops a an action sheet that confirms saving a selected address and also does a dismiss, but its old code and not sure how it works now. In any case hope this helps.

motion callbacks never called

I'm trying to make a shake events.
I tried:
1) How do I detect when someone shakes an iPhone? (posts of Kendall, and Eran)
2) motionBegan: Not Working
but nothig helps.
My View becomes first responder, but motionBegan/motionEnded never called.
Is there some additiol settings must be done, or i'm missing somethig? My iOS SDK is 4.3.
I have a class of UIView:
#import "ShakeView.h"
#implementation ShakeView
- (BOOL)canBecomeFirstResponder {
return YES;
}
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event {
NSLog (#"123");
if ( event.subtype == UIEventSubtypeMotionShake ) {
NSLog(#"Shake!");
}
if ([super respondsToSelector:#selector(motionEnded:withEvent:)]) {
[super motionEnded:motion withEvent:event];
}
}
#end
In my ViewController's xib class of View is ShakeView.
my ViewController pushed:
Wheel *secondViewController = [[Wheel alloc] initWithNibName:#"Wheel" bundle:nil];
[self.navigationController pushViewController:secondViewController animated:YES];
[secondViewController release];
In my ViewController:
- (void) viewDidAppear:(BOOL)animated
{
[self.view becomeFirstResponder];
[super viewWillAppear:animated];
NSLog(#"%d", [self.view isFirstResponder]);
}
- (void) viewWillDisappear:(BOOL)animated
{
[self.view resignFirstResponder];
[super viewWillDisappear:animated];
}
It logs "1", so it IS first responder. But it logs nothing else.
I spend a half day on this few lines of code, and I have no more ideas. Do anyone knows how to solve it?
Thanks.
This is much too late to help SentineL, but I was having the same problem and I like his question because it is clear that he has all the relevant code in place -- except one crucial line, in the application delegate's didFinishLaunching:
[self.window makeKeyAndVisible];
This is very hard to debug, because even without this line, everything else will be fine. Your gestures will work, your controls will respond, you will be able to make your view first responder (as SentineL checked) -- but your subclassed window or view or view controller will never receive the motion events.
Which doesn't make sense to me. Why would makeKeyAndVisible affect the accelerometer but not gestures? Hopefully some more experienced user can answer that.
P.S. If you use this code as an example, I would recommend that you omit the super respondsToSelector conditional. Of course it responds to the selector; you're overriding it.

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

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];
}

Objective-C on iPhone - tab bar crash

I'm relatively new to Objective-C and coding. I've tried doing a little dev on my own but have now become stuck on what is probably a rookie error.
I've created a tab bar controller with 5 views, one such view is a UIWebView. I've got the Webview working and it loads, but when I select a different tab, the app crashes. Please find my code below and any help would be appreciated!
#import <UIKit/UIKit.h>
#interface LiveViewController : UIViewController {
IBOutlet UIWebView *liveView;
}
#property (nonatomic, retain) UIWebView *liveView;
#end
#import "LiveViewController.h"
#implementation LiveViewController
#synthesize liveView;
// The designated initializer. Override if you create the controller programmatically and want to perform customization that is not appropriate for viewDidLoad.
/*
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization.
}
return self;
}
*/
/*
// Implement loadView to create a view hierarchy programmatically, without using a nib.
- (void)loadView {
}
*/
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
[self.liveView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:#"http://www.britishseapower.co.uk/live/"]]];
[super viewDidLoad];
}
- (void)webViewDidStartLoad:(UIWebView *)liveView
{
// starting the load, show the activity indicator in the status bar
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
}
- (void)webViewDidFinishLoad:(UIWebView *)liveView
{
// finished loading, hide the activity indicator in the status bar
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
}
- (void)liveView:(UIWebView *)liveView didFailLoadWithError:(NSError *)error
{
// load error, hide the activity indicator in the status bar
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
// report the error inside the webview
NSString* errorString = [NSString stringWithFormat:
#"<html><center><font size=+5 color='red'>An error occurred:<br>%#</font></center></html>",
error.localizedDescription];
[self.liveView loadHTMLString:errorString baseURL:nil];
}
- (void)viewWillDisappear:(BOOL)animated
{
if ( [self.liveView loading] ) {
[self.liveView stopLoading];
}
self.liveView.delegate = nil; // disconnect the delegate as the webview is hidden
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
}
- (void)dealloc {
[liveView release];
[UIWebView release];
[LiveViewController release];
[super dealloc];
}
#end
Many thanks,
Ryan
[UIWebView release]; [LiveViewController release];
This is what make your app crash.
It's not valid to send a release message to a class itself.
What you've done with [liveView release]; is enough (with the call to [super dealloc];.)
You should also set the delegate to nil in the dealloc method as in the viewWillDisappear method self.liveView.delegate = nil;. This way you're sure to avoid any further message sent to the LiveViewController from the UIWebView.
You should read a bit more of documentation on Objective-C to better understand how it works.
Not sure if this is related but I noticed that you aren't setting yourself as the delegate anywhere in code which means that it must be connected in Interface Builder. Now when the view disappears, you are breaking that connection, but if the view were to re-appear and wasn't previously unloaded that connection will remain broken.
One of the most common reasons why an app may crash is to refer to or send a message to an object that has been already released from the memory. And this type of bug can be easily located using NSZombieEnabled and looking into the console message. So if you haven't already tried that, that's the first thing you must do.
The problem could be in LiveViewController but could be in the other view controllers as well. I wouldn't believe the problem is 100% in LiveViewController because the view controller wouldn't try releasing its view when the view is not shown unless it gets a memory warning. And you run the app using the simulator, it's unlikely it will have a memory warning unless you simulate one.
You would probably know that a view controller never create a view unless the view is used by an object. One of the other view controllers may have a silly bug in its view loading process which causes a crash. Or, you might have released another view controller by mistake. Make 100% sure that the other view controllers have no problem showing their views on their own, when you keep changing between their views (without showing LiveViewController).
So what I would do is to try NSZombieEnabled and check if it accesses a released object, and if it does, what the object is. Also, I will make a double check that the problem is related to LiveViewController. If it doesn't help I would log a message when LiveViewController and its liveView is deallocated (for liveView you need to subclass it). Because delegate property almost always does not retain an object, if the LiveViewController object is released (which shouldn't happen) and liveView still has a reference to it in the delegate property it will make a crash.
Crashes like this are almost always related to releasing an object that has already been released and deallocated.
Let XCode help you find the error. In XCode 4:
- In the toolbar, select the scheme list, and select 'Edit Scheme'
- Select the 'Run Your.app' in the list on the left.
- Under 'Environment Variables', add the following name/value pairs in the appropriate columns:
CFZombieLevel 3
NSZombieEnabled YES
Now when debug your app, you will get a message telling when -release is called on an object that already has a -retainCount of zero. Now you have a good clue to start your investigation.
Note that these flags prevent objects from being deallocated, so it is best to turn them on as needed to prevent out of memory errors.

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?