isRegisteredForRemoteNotifications locking UI with semaphore_wait_trap - ios

There's a strange situation happening in my iOS application when it receive push notification. The UI stay locked and nothing works. When I pause the debugger I see semaphore_wait_trap in my thread.
Debbuging the code I can see it is related to two things:
the value type in push notification (because when I change Number to String the problem disappear);
the isRegisteredForRemoteNotifications method (because when I remove it the problem disappear);
I'm receiving a push notification as follow
{aps:
{alert: { loc-args: [Fiat, Bravo, 501],
loc-key: SOME_TEXT
},
badge: 0,
sound: default.aiff
}
}
I made a new and simple project in Xcode to prove what I'm saying. I'm using the previous bundle identifier to receive the same push.
Follow the code in AppDelegate that shows the problem:
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
return YES;
}
- (void)application:(UIApplication*)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
NSLog(#"My token is: %#", deviceToken);
}
- (void)application:(UIApplication*)application didFailToRegisterForRemoteNotificationsWithError:(NSError*)error {
// [DefaultMethods saveInUserDefaults:#(1) forKey:kUserWasAskedForNotificationKey];
NSLog(#"Failed to get token, error: %#", error);
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
if( [[UIApplication sharedApplication] isRegisteredForRemoteNotifications] ){
NSLog(#"Success");
}
}
#end
Thank you for any help!

I was dealing with this problem too and have found this error in my device's logs:
com.apple.usernotifications.usernotificationservice: Exception caught
during decoding of received message, dropping incoming message.
Exception: Exception while decoding argument 0 (#2 of invocation):
Exception: value for key 'NS.objects' was of unexpected class
'NSNumber'. Allowed classes are '{(
NSString,
NSArray )}'.
After calling isRegisteredForRemoteNotifications the application has stopped.
We have fixed this issue on our server and problem went off. Good luck.

I was having the same stall issue.
It turns out that I was also getting a push notification parsing error on the console (like the one mentioned above by #CFIFOK).
"NSXPCConnection: ---" connection to service named com.apple.usernotifications.usernotificationservice:
Exception caught during decoding of received message, dropping incoming message.
Exception: Exception while decoding argument 0 (#2 of invocation):
Exception: value for key 'NS.objects' was of unexpected class 'NSNumber'.
Allowed classes are '{(
NSString,
NSArray
)}'.
This was due to the "title-loc-args" : [3333] not accepting 3333 literally but accepting it as a string "title-loc-args" : ["3333"]. This little thing made my entire interface stall after I accessed the mentioned method isRegisteredForRemoteNotifications.
One thing to take into account is that this stall only happens on iOS 11. It works perfectly fine on iOS 12.0 (16A5366a).
In order to debug the error I used Pusher app (https://github.com/noodlewerk/NWPusher) and traced down the argument that was giving me the parsing error.
Hope this helps!

Related

ios - signal function with SIGPIPE and SIG_IGN

I have joined in a old project and I found this line
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
signal(SIGPIPE, SIG_IGN);
....
}
I have found in docs this:
/*
* For historical reasons; programs expect signal's return value to be
* defined by <sys/signal.h>.
*/
But I'm still confused as to what the purpose of that line is.
From Apple's documentation:
When a connection closes, by default, your process receives a SIGPIPE signal. If your program does not handle or ignore this signal, your program will quit immediately.
Ignore the signal globally with the following line of code:
signal(SIGPIPE, SIG_IGN);

iOS saving data if app crash

I have got requirement in one of my projects where user is asking to save data locally in case of sudden app crashes. Its form based app so user fill lots of data in form and if app crashes suddenly then user lost all data entered.
App is using Core Data to save data locally.
There is a point where we save entered data in core data but not during every second user fills data.
Also if app crashes core data also vanishes.
In fact, if your app crash, the callback :
- (void)applicationWillTerminate:(UIApplication *)application
will not be called. This one is only called if for some reasons the system need to shutdown your app (usually because resources are rare or because your background job is still doing work after the maximum time allowed) or if you are on < iOs 4. You don't have any way to know when your app will crash (but when you relaunch the app, you can know if it had crashed).
So for your particular case you have two solutions :
Use either a NSTimer with a quick firing rate, or call a fonction each time you edit a field and update the core-data context then save it on disk.
NSError *error = nil;
[managedObjectContext save:&error]
Did you set a persistentStoreCoordinator on your context ? If no, core-data will never persist your data on disk.
Crashes don't appear out of nowhere, find the place(s) where crashes might happen and fix it or if you can't, use a try-catch to keep your app running (but please, try not to do that...).
Hope this help
You can implement a HandleException to catch all exceptions that crash your application.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
//for uncaughted exceptions
NSSetUncaughtExceptionHandler(&HandleException);
struct sigaction signalAction;
memset(&signalAction, 0, sizeof(signalAction));
signalAction.sa_handler = &HandleSignal;
sigaction(SIGABRT, &signalAction, NULL);
sigaction(SIGILL, &signalAction, NULL);
sigaction(SIGBUS, &signalAction, NULL);
//and more if you need to handle more signals
//another setup ...
return YES
}
#pragma mark crash management
void HandleException(NSException *exception) {
NSLog(#"[FALTAL] App crashing with exception: %#", exception);
//try to save your DB here.
}
void HandleSignal(int signal) {
//try to save your DB here.
}
#pragma -
However, I don't know about how many time you will have before application exits. But I suppose that you will have enough time to do the DB-backup task.
In particular case you can should use, try catch block, (but not) everywhere.
try {
//write your code
}catch(NSException *e){
//See what's the error
}finally{
//Save your context
}
This it the best solution in my thinking. However you can create a NSTimer which executes a method at some reasonable seconds where you can hold and save your context.
You can also save your context in AppDelegate's method like (if you're targeting iOS 4.0 and above and if your app was exit by iOS it self for some reason),
- (void)applicationWillTerminate:(UIApplication *)application{};
below method will always call when your app goes in background,
- (void)applicationDidEnterBackground:(UIApplication *)application{};
Use
(void)applicationWillTerminate:(UIApplication *)application
delegate method of AppDelgate to save your data in core data.

NSNotificationCenter callback while app in background

One question and one issue:
I have the following code:
- (void) registerForLocalCalendarChanges
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(localCalendarStoreChanged) name:EKEventStoreChangedNotification object:store ];
}
- (void) localCalendarStoreChanged
{
// This gets call when an event in store changes
// you have to go through the calendar to look for changes
[self getCalendarEvents];
}
These methods are in a class/object called CalendarEventReporter which contains the method getCalendarEvents (in the callback).
Two things:
1) If the app is in the background the callback does not run. Is there a way to make it do that?
2) When I bring the app back into the foreground (after having changed the calendar on the device) the app crashes without any error message in the debug window or on the device. My guess is that the CalendarEventReporter object that contains the callback is being garbage-collected. Is that possible? Any other thoughts on what might be causing the crash? Or how to see any error messages?
1) In order for the app to run in the background you should be using one of the modes mentioned in the "Background Execution and Multitasking section here:
uses location services
records or plays audio
provides VOIP
services
background refresh
connection to external devices
like through BLE
If you are not using any of the above, it is not possible to get asynchronous events in the background.
2) In order to see the crash logs/call stack place an exception breakpoint or look into the "Device Logs" section here: Window->Organizer->Devices->"Device Name" on left->Device Logs on Xcode.
To answer your first question, take a look at https://developer.apple.com/library/ios/documentation/iphone/conceptual/iphoneosprogrammingguide/ManagingYourApplicationsFlow/ManagingYourApplicationsFlow.html
What I did to get code running in the background is to do something like
In the .h file
UIBackgroundTaskIdentifier backgroundUploadTask;
In the .m file
-(void) functionYouWantToRunInTheBackground
{
self.backgroundUploadTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
[self endBackgroundUpdateTask];
}];
//code to do something
}
-(void) endBackgroundUpdateTask
{
[[UIApplication sharedApplication] endBackgroundTask: self.backgroundUploadTask];
self.backgroundUploadTask = UIBackgroundTaskInvalid;
}
The code above I pretty much learned from objective c - Proper use of beginBackgroundTaskWithExpirationHandler
As for your second question, you should set a breakpoint where code is supposed to run when you bring the app back to the foreground. No one can figure out why an app crashes if not given enough code or information.
The solution to the second part of the question was to raise the scope of the object containing the callback code. I raised it to the level of the containing ViewController. This seems to work. I still can't figure out how to raise the Notification (i.e. execute the call back) if the notification comes while the app is in the background/suspended. This prevented the object containing the callback from being cleaned up.

Why does my iOS app crash when receiving a push notification?

My iOS app is crashing when it receives a push notification message while running. I'm using the sandbox APNS environment, and using Amazon SNS to send the APNS messages.
When debugging, I set a breakpoint on the first line of the following code snippet:
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
NSDictionary *apnsPayload = [NSDictionary dictionaryWithDictionary:userInfo];
When the app receives a push notification, it hits the breakpoint and lets me debug; at this point I can see that userInfo is non-nil and contains the expected dictionary.
However, when I step through the code, the app crashes with EXC_BAD_ACCESS at the very next line—the assignment to apnsPayload. It seems like userInfo might be getting deallocated prematurely, but I'm not sure why, or more importantly how to change this.
I don't think it makes sense to turn the NSDictionary into another NSDictionary with [NSDictionary dictionaryWithDictionary:] ... also NSDictionary can be non-nil but contain 0 key entries (an empty dictionary).
Perhaps you want: NSDictionary *apnsPayload = [userInfo objectForKey: #"alert"]; ?
See: https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Chapters/ApplePushService.html
Well, I've still no idea why this is happening, but it stops when I NSLog() the userInfo argument first. Adding the following line as the first line of the function prevents the crash:
NSLog(#"Received APNS with userInfo %#", userInfo);
I can then assign using - [userInfo objectForKey:] without causing a crash. (To be clear, attempting this same assignment without the prior NSLog() results in the EXC_BAD_ACCESS crash.)

ios logins using NSUserDefaults, handle crash or device shutdown

I’m trying to handle critical behavior when user login on my ipad application.
Once successfully logged in, we will remember the login using nsuserdefaults but will require a re-login when:
Crash occurred
Device was shutdown
is it possible to reset the login value on NSUserDefault when the above actions occurred ? if Yes how can I handle them ?
thanks
For case 1 add an exception handler
- (void) applicationDidFinishLaunching: (UIApplication *) application
{
NSSetUncaughtExceptionHandler (&myExceptionHandler);
}
....
- (void) myExceptionHandler (NSException *exception)
{
// Make a note in your default settings
// User needs to log in
}
For case 2 trap
- (void)applicationDidEnterBackground:(UIApplication *)application
{
// Make a note in your default settings
// User needs to log in
}
I don't know of a way for an app to know when the device is powered off. If you meant when the application is exited read on.
Or just stick the logic in the
-(void)applicationDidBecomeActive:(UIApplication *)application
And catch both scenarios.

Resources