Why is this CMDeviceMotionHandler never called by CoreMotion? - iphone

I've included the CoreMotion framework in my project and imported the CoreMotion framework in the header of my view controller:
#import <CoreMotion/CoreMotion.h>
Then in -viewDidLoad I have this simple test code which I run on an iPhone 4 with iOS 4.3:
- (void)viewDidLoad {
[super viewDidLoad];
CMMotionManager *motionManager = [[CMMotionManager alloc] init];
[motionManager setDeviceMotionUpdateInterval:0.1];
CMDeviceMotionHandler motionHandler = ^(CMDeviceMotion *motion, NSError *error) {
NSLog(#"foo");
};
[motionManager startDeviceMotionUpdatesToQueue:[NSOperationQueue currentQueue] withHandler:motionHandler];
NSLog(#"merde!");
}
When I run the project on the device and move it around, I never get a "foo" log. Also, I tried setting a breakpoint in the motion handler block and it never halts there. But I do get the "merde!" log, so this code is definitely executed.
Why is core motion not calling my handler? My iPhone 4 is functional. Accelerometers and gyro work perfectly in other apps. There is no hardware bug.

I had very similar code running successfully, same applies to the available samples in the Event Handling Guide for iOS (there is only an appropriate one for gyro data). But there is one major difference:
All implementations hold their own reference to the opereation queue with operationQueue = [[NSOperationQueue currentQueue] retain]; or build their own. So hopefully this helps to get more than 'merde' in your logs ;-)

Related

iOS local notification: I would like to execute a function upon reentering the app via local notification

I'm working with XCode 4.6, and am trying to build a local notification feature on iOS that will execute a function upon reentering the app.Basically I would like to change the text in some of the labels and add some sound upon reentering the app. I thought I was on the right track, but only some parts of my code work when reentering the app via local notification.
First I added this function to my AppDelegate:
-(void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification{
NSLog(#"test1"); //this traces successfully
myAppViewController * controller = [myAppViewController alloc];
[controller doSomething]; //calling a function in my myAppViewController.m
}
I thought I had figured it out, but now only the NSLog works in my function in myAppViewController.m:
-(void)doSomething{
NSLog(#"do something"); //traces successfully
self.notificationTime.text=#"something else"; //nothing happens here, it works in other functions but not here
[self doSomethingElse]; //calling another function from this function for further testing
}
The next function is called....
-(void)doSomethingElse{
NSLog(#"do something else"); //this works
//this whole thing doesn't work -- no sound --
NSURL* url = [[NSBundle mainBundle] URLForResource:#"cash" withExtension:#"mp3"];
NSAssert(url, #"URL is valid.");
self.player = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil];
[self.player prepareToPlay];
[self.player play];
//this doesn't work again
self.notificationTime.text=#"something else";
}
I was hoping to get some general advice here and it would be much appreciated. If anyone knows a complete different way of solving the problem, that would be great as well!
The didReceiveLocalNotification method is only called when you application is running in the foreground. If you see a badge and click on the App to start it, then you need to process the local notification using application:willFinishLaunchingWithOptions: (or application:didFinishLaunchingWithOptions:) To get at your local notification in either of these two methods, use UIApplicationLaunchOptionsLocalNotificationKey as a key to the options dictionary.
Note, once you extract the local notification from the launch options, it is a viable approach to call your didReceiveLocalNotification method.
You shouldn't need to allocate a second instance of the app controller. You can just use self. If you do that, does the code work as expected?

Could not locate an NSManagedObjectModel for entity name - Universal App

I have a strange error in my app, which says:
* Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '+entityForName: could not locate an NSManagedObjectModel for entity name 'Book'
I know, there are hundrets of "Could not locate an NSManagedObjectModel for entity name" topis here and on the web, but the strange thing is, it's a universal app and the iphone app always works fine, only the ipad app is crashing on startup.
In the main AppDelegate, there is some code in two methodes and in the iphone / ipad AppDelegate I'm calling this code in applicationdidFinishLaunchingWithOptions like this:
if ([self modelExists] == NO) {
[self buildModel];
}
So it's the same way I call the code, but the ipad version crashes and the iphone version does not.
The only different is that the iPhone version uses a TabBarContoller (set up in IB) and the iPad version uses a single viewController (also set up in IB).
It happens on both, simulator and device.
I have no idea what to do. Hope you can understand what I mean ...
Thx a lot
Sebastian
EDIT:
I found out, when I run the iPhone Version, the code in the main AppDelegate is called as it should be, but when I run the iPad Version NONE code of the main appDelegate is called at all, so there is no managedObject created and that's the reason for the error. But why is no code run in the main AppDelegate ? Thx
EDIT2:
This is the code in my main AppDelegate now:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
if ([self modelExists] == NO) { // Checks if the model is allready filled up or not. (Uses CoreData stuff of course)
// iPhone Version is fine here. iPad Version crashes.
[self buildModel];
}
[self buildInterface]; // Called in the iPhone or iPad AppDelegate to make the window visible etc.
return YES;
}
So didFinishLaunchingWithOptions is called in the iphone and in the ipad version. The iPad version just doesn't run the coredata stuff anyway, whereas the iphone version does run the coredata stuff as it should. Any idea what could be wrong? THX!
Maybe the app delegate is not running any code if it's just not set as an delegate of the application.
Look in your main NIB for the iPad version and make sure the "AppName App Delegate" is set as the delegate of the File's owner of that NIB.
I found my problem. Really strange ...
It was the code of "modelExists"
- (BOOL)modelExists {
NSFetchRequest *request = [[NSFetchRequest alloc] init];
request.entity = [NSEntityDescription entityForName:#"Book" inManagedObjectContext:__managedObjectContext]; //<- Crashed. Had to change it to self.managedObjectContext
request.predicate = nil;
NSError *error = nil;
...
Sebastian
I had this same problem. My app had been working fine for weeks in development, then suddenly it was crashing with this error. Changing managedObjContect to [self managedObjectContext] solved the problem.
I would love to know why....any experts out there? Why would the original code be able to resolve the call to managedObjectContext to the member function's implementation....and suddenly not be able to? There is no other static implementation visible to this code as far as I know.
Thank for posting this, save me many hours of messing around.
In my project, I had a navigation controller and I was getting this error when I tried to segue into a child view control.
The problem was that I needed to pass set the managedObjectContext. This is taken from the CoreDate Master/Detail example.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"showDetail"]) {
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
NSManagedObject *object = [[self fetchedResultsController] objectAtIndexPath:indexPath];
[[segue destinationViewController] setDetailItem:object];
// set the managedObjectContext, too, if you need it
[[segue destinationViewController] setManagedObjectContext:self.managedObjectContext];
}
}
Also, double check the segue identifier in Interface Builder matches what you have in this function (showDetail in this example).

Core Data database doesn't save

I'm trying to implement the Paparazzi 2 assignment from the Stanford CS193 course and I'm running into a problem. My one call to save the database is when the app exits (I'm borrowing heavily from Mike Postel's version to check my code):
- (void)applicationWillTerminate:(UIApplication *)application {
if (flickrContext != nil) {
if ([flickrContext hasChanges] == YES) {
NSError *error = nil;
BOOL isSaved = [flickrContext save:&error];
NSLog(#"isSaved? %#", (isSaved ? #"YES" :#"NO") );
// Replace this implementation with code to handle the error appropriately.
if(isSaved == NO){
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
}
}
}
Unfortunately, this doesn't seem to be doing the job. I'm getting the occasional EXEC_BAD_ACCESS call that might be related to this, but the database never saves. I've inserted the save into other pieces and it works fine there, just not in this routine. I'm not releasing any of the managed objects in my views, just the managed object context (flickrContext, or whatever I'm calling it in a view).
Any ideas?
Are you sure that applicationWillTerminate: is even being called?
With iOS4 and background process support, the usual application lifecycle is now:
running -> background -> background suspended -> exit
You get an applicationDidEnterBackground: call when transitioning into the background state, but no further notification when the background process suspends or exits.
So, you really need to save state in applicationDidEnterBackground: for iOS4, as well as in applicationWillTerminate: for older versions
flickrContext is your managedObjectContext? I'm betting it is nil or otherwise hosed when you hit this method. You say you are releasing it in a view - surely you should be creating just one, having it owned by the application delegate, and release it only in app delegate's dealloc?
(And when you need to use it -
NSManagedObjectContext* moc = [(MyAppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
)
Regarding your EXEC_BAD_ACCESS - what happens with NSZombieEnabled = YES? What does the static analyzer say?
Good call. I actually solved this one the old fashioned (brute force) way. It turns out that applicationWillTerminate wasn't being called, but it wasn't obvious. The routine to create the database that I had borrowed from the web was explicitly releasing an NSArray that I'm pretty sure was autoreleased. It essentially turned the program into a time bomb. Although I still haven't figured out why it lasted as long as it did and just didn't manifest until I tried to exit.
I'm still learning XCode and CocoaTouch. I know about NSZombieEnabled but I haven't figured out how to use it correctly yet. I'm still in the ham-fisted monkey stage. Thanks for the tips, though. They were helpful.

iPhone application crash (iOS4 Only)

My iPhone application occasionally crashs the first time it is run after being installed. After this every time i try and run the app it remains on the splash screen or even a black screen until eventually it dies. I have to restart the device to get the application to work. After this it works fine every time. The only change between the OS3 code and 4 is the property 'UIApplicationExitsOnSuspend' to force the app to reload every time instead of suspending. Any help would be great.
Here are the two Code snippets:
- (void)applicationDidFinishLaunching:(UIApplication *)application
{
taskListViewController = [[TaskListViewController alloc] initWithNibName:#"TaskListView" bundle:nil];
taskListViewController.managedObjectContext = self.managedObjectContext;
[taskListViewController setAppDefaults];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:taskListViewController];
[taskListViewController release];
navController.navigationBar.tintColor = [UIColor blackColor];
[window addSubview:[navController view]];
[window makeKeyAndVisible];
}
- (void)viewDidLoad
{
NSLog(#"viewDidLoad - Start");
[super viewDidLoad];
NSError *error = nil;
if(![[self fetchedResultsController] performFetch:&error])
{
NSLog(#"Error with initial fetch %#, %#", error, [error userInfo]);
}
[activityIndicator startAnimating];
self.navigationItem.leftBarButtonItem.enabled = NO;
self.navigationItem.rightBarButtonItem.enabled = NO;
infoButton.enabled = NO;
syncButton.enabled = NO;
taskListTable.userInteractionEnabled = NO;
taskListTable.allowsSelection = NO;
checkingRecovery = true;
[self insertCheck];
}
Other Methods mentioned above:
[taskListViewController setAppDefaults]
[self insertCheck];
setAppDefaults - Enumerates through the settings bundle applying the defaultValues to NSUserDefaults if they have not been set already by the user in peferences.
insertCheck - Performs some queries on the db to ensure file integrity on audio recordings but in this case as this is the first time the app is loaded it will do nothing.
Update:
I have commented out the extra method calls (the two above) and i am still having the problem.
I have found a few people having the same sort of problem on the apple developer forum with no solutions. One reply was from a user having the same problem but there application did get approved on the app store.
Thanks Sj
If you are debugging the application when it crashes, you should get a stack trace, which will show you on what line the application crashes.
If you could provide the stack trace it would be much easier to find the cause of the crash.
Have you looked at the log files?
You can copy them off your iPhone if you plug it in, load organizer (Windows->Organizer in XCode) and select device logs.
If you see a log for the time your application crashed, it should include the call stack (which should include the function causing it to crash)
Alternatively it could be that you're stuck in some code run at startup - and if your application doesn't start in a timely manor (within 30 seconds IIRC) iOS kills it.
Try it without the managedObjectContext piece and see if you are still crashing. What does the log say when you crash? Do you get a memory exception?

GKSession - what if I have Bluetooth and Wi-Fi turned off?

I'm working on an iPhone app that will allow for peer-to-peer connections. From what I understand, I have the choice between using GKPeerPicker or the GKSession. I don't like the idea of using the PeerPicker because I want to show a custom interface, so I decided to go with GKSession, and hey, BONUS is that it also works over Wi-Fi, whereas the Peer Picker does not.
OK, so problem is... what if the user has both Bluetooth and Wi-Fi turned off? In the Peer Picker, there is a prompt to turn Bluetooth on w/o leaving the app. GKSession doesn't have it... but woah wait a second, it appears that I can't even check to see if Bluetooth is on or not programatically!
Carpe Cocoa claims no problem, just use the Delegate's session:didFailWithError: method. But, as it explains in the comments... that doesn't seem to work anymore! And in my experience, I concur.
Is there some other way to programmatically check if Bluetooth is on? Is this something that I should be leveraging Reachability for? Or is it just a bug that Apple has yet to fix?
To be more specific, I'm creating my session like this:
GKSession *aSession = [[GKSession alloc] initWithSessionID:nil
displayName:user.displayName
sessionMode:GKSessionModePeer];
self.gkSession = aSession;
[aSession release];
self.gkSession.delegate = self;
self.gkSession.available = YES;
[self.gkSession setDataReceiveHandler:self withContext:NULL];
The class implements the GKSessionDelegate, and I know that it's working because when I have bluetooth turned on, the delegate methods are called no problem. I've implemented them as such:
#pragma mark -
#pragma mark GKSessionDelegate methods
- (void)session:(GKSession *)session peer:(NSString *)peerID didChangeState:(GKPeerConnectionState)state {
if (GKPeerStateAvailable == state) {
[session connectToPeer:peerID withTimeout:10];
} else if (GKPeerStateConnected == state) {
// gets user
NSError *error = nil;
[session sendData:user.connectionData
toPeers:[NSArray arrayWithObjects:peerID,nil]
withDataMode:GKSendDataReliable error:&error];
if (error)
NSLog(#"%#",error);
}
}
- (void)session:(GKSession *)session didReceiveConnectionRequestFromPeer:(NSString *)peerID {
NSError *error = nil;
[session acceptConnectionFromPeer:peerID error:&error];
if (error)
NSLog(#"%#",error);
}
- (void)session:(GKSession *)session connectionWithPeerFailed:(NSString *)peerID withError:(NSError *)error {
NSLog(#"%#",error);
}
- (void)session:(GKSession *)session didFailWithError:(NSError *)error {
NSLog(#"%#",error);
}
None of the log statements are printed and I set breakpoints in each method, but none of them are hit when the user has both Bluetooth and Wi-Fi turned off. I was hoping that something would happen to trigger session:didFailWithError: so that I could prompt the user to turn on Bluetooth or connect to a Wi-Fi network.
Now in iOS 5, this can be achieved like so:
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:FALSE], CBCentralManagerScanOptionAllowDuplicatesKey, nil];
NSMutableArray * discoveredPeripherals = [NSMutableArray new];
CBCentralManager * manager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
[manager scanForPeripheralsWithServices:discoveredPeripherals options:options];
[manager stopScan];
This requires that you import the CoreBluetooth framework in iOS 5. If bluetooth is off, the system will pop up an alert view which will offer the choice to turn bluetooth on. Otherwise, if it finds a peripheral it will call a corresponding delegate method, but if there is nothing in that implementation you don't need to worry about it.
I agree with Martin Gordon, but a workaround might be to use Apple's reachability.
Interesting point, have you tried testing it with Bluetooth OFF and the WiFi ON? I found out recently that although my program was calling this 'Bluetooth Unavailable' message, it wasn't in fact using Bluetooth AT ALL but was connecting over my WiFi network. I don't know of a way to force GKSession into a Bluetooth connection without using Apple's PeerPicker object, but the PeerPicker object does allow for people to make their own interfaces. What it doesn't seem to allow is connection types other than Peer, so if you want a Client/Server arrangement it's not going to be much help.
-Ash
You can switch on Blutooth programmatically, by using Apple's private API (i think BluetoothManger.h), but be careful , it will cause rejection in the Apple App Store push.
I second the notion of using Apple's reachability. As a bonus it's listed as one of the Apple App Store submission guidelines.
It's not that hard to implement either as much of the code needed is already written for you.
Slf provided a link to some source code using the Reachability class, additionally here's a link to Apple Dev's official reachability example.
However, make sure you are checking for connectability asynchronously.
I'm using it in my app and although it isn't the best solution at least it notifies the user that he/she needs to adjust the connection settings or that no networks exist.
You should use the same sessionID.