iOS App UI freeze when coming from background - objective-c

I'm facing a strange issue and I have no clue why this is happening.My app works fine when it is active, but the app UI is freezing when it comes from background (by pressing the home button and by locking the device).
NOTE:This behaviour is only observed on devices but not in simulator.
And the console is throwing the messages:
Jul 5 13:28:55 Tejas-iPhone backboardd[7234] <Warning>: BKSendHIDEvent: IOHIDEventSystemConnectionDispatchEvent error:0xE00002E8 -- Unknown event dropped
along with too many logs of :
Jul 5 14:41:40 Tejas-iPhone boostApp[7913] <Error>: CoreLocation: Discarding message for event 0 because of too many unprocessed messages
Jul 5 14:41:42 Tejas-iPhone boostApp[7913] <Error>: CoreLocation: Discarding message for event 12 because of too many unprocessed messages
Jul 5 14:44:56 Tejas-iPhone boostApp[7913] <Error>: CoreLocation: Discarding message for event 1 because of too many unprocessed messages
Jul 5 14:44:56 Tejas-iPhone boostApp[7913] <Error>: CoreLocation: Discarding message for event 27 because of too many unprocessed messages
I found out that CoreLocation will log the above message if the locationManager is not running on main thread.
Here is how I initialise the CLLocationManager:
-(id)init {
if ( self = [super init] ) {
[self runLocationManagerOnMainThread];
}
return self;
}
-(void)runLocationManagerOnMainThread{
if (![NSThread mainThread]) {
[self performSelectorOnMainThread:#selector(runLocationManagerOnMainThread) withObject:nil waitUntilDone:NO];
}
self.locationManager = [[LocationManager alloc] init];
self.locationManager.delegate = self;
self.locationManager.distanceFilter = 1;
self.locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
self.buildings = [[NSMutableArray alloc] init];
}
+ (id)sharedInstance {
static LocationMonitor *sharedMyManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedMyManager = [[self alloc] init];
});
return sharedMyManager;
}
Please let me know if I need to mention any specific details.I tried this but it doesn't have any valid answers.

This is wierd . I integrated NSLogger to my project a while ago and I started to see that xcode terminal stopped logging logs and I have to always rely on apple configurator and NSLogger to see my logs.
After I delete the NSLogger from pods and from my project, my app started to work more faster and the UI is not freezing anymore irrespective of how many times the app is opened from background.

Related

Native cellular call fails on VoIP incoming call in iOS 13

I have implemented CallKit for audio and video call with VoIP PushKit in iOS and it is working fine in iOS 12 and prior versions, and also it is working fine normally in iOS 13 and 13.1.
But it is failing in 2 scenarios:
1) Our App is in foreground state. When cellular call is running and VoIP push is received, then Call kit incoming call screen is showing for 5 - 10 seconds, and then both Cellular and VOIP calls are failing with Alert "Call Failed".
2) Our App is in Background or Killed state. When cellular call is running and VoIP push is received, then both Cellular and VOIP calls are failing with Alert "Call Failed". No incoming call UI is showing this time.
I am showing my code here:
- (void)registerAppForVOIPPush {
PKPushRegistry *pushRegistry = [[PKPushRegistry alloc] initWithQueue:dispatch_get_main_queue()];
pushRegistry.delegate = self;
pushRegistry.desiredPushTypes = [NSSet setWithObject:PKPushTypeVoIP];
}
Then Push delegates
#pragma mark PKPushRegistryDelegate ----
- (void)pushRegistry:(PKPushRegistry *)registry didUpdatePushCredentials: (PKPushCredentials *)credentials forType:(NSString *)type {
NSString *newToken = [self hexadecimalStringFromData:credentials.token];
//Make a note of this token to a server to send VOIP for a particular device
NSLog(#"VOIP token ::: %#", newToken);
_voipToken = newToken;
}
- (void)pushRegistry:(PKPushRegistry *)registry didReceiveIncomingPushWithPayload:(PKPushPayload *)payload forType:(PKPushType)type {
//available(iOS, introduced: 8.0, deprecated: 11.0)
[self pushRegistryDidReceivedPushWithPayload:payload forType:type withCompletionHandler:NULL];
}
- (void)pushRegistry:(PKPushRegistry *)registry didReceiveIncomingPushWithPayload:(PKPushPayload *)payload forType:(PKPushType)type withCompletionHandler:(void (^)(void))completion {
//available(iOS 11.0, *)
[self pushRegistryDidReceivedPushWithPayload:payload forType:type withCompletionHandler:completion];
}
- (void)pushRegistryDidReceivedPushWithPayload:(PKPushPayload *)payload forType:(PKPushType)type withCompletionHandler:(void (^)(void))completion {
//Call kit configration
CXProviderConfiguration *providerConfig = [[CXProviderConfiguration alloc] initWithLocalizedName:#"my app Call"];
providerConfig.supportsVideo = NO;
providerConfig.maximumCallGroups = 1;
providerConfig.maximumCallsPerCallGroup = 1;
providerConfig.supportedHandleTypes = [[NSSet alloc] initWithObjects:[NSNumber numberWithInteger:CXHandleTypeGeneric], nil];
providerConfig.iconTemplateImageData = UIImagePNGRepresentation([UIImage imageNamed:#"IconMask"]);
CXProvider *provider = [[CXProvider alloc] initWithConfiguration:providerConfig];
[provider setDelegate:self queue:nil];
//generate token
NSUUID *callbackUUIDToken = [NSUUID UUID];
//Display callkit
NSString *uniqueIdentifier = #"Max test";
CXCallUpdate *update = [[CXCallUpdate alloc] init];
update.remoteHandle = [[CXHandle alloc] initWithType:CXHandleTypeGeneric value:uniqueIdentifier];
update.supportsGrouping = FALSE;
update.supportsUngrouping = FALSE;
update.supportsHolding = FALSE;
update.localizedCallerName = uniqueIdentifier;
update.hasVideo = NO;
[provider reportNewIncomingCallWithUUID:callbackUUIDToken update:update completion:^(NSError * _Nullable error) {
NSLog(#"reportNewIncomingCallWithUUID error: %#",error);
}];
if (completion) {
dispatch_async(dispatch_get_main_queue(), ^{
completion();
});
}
}
I have implemented CXProvider delegate method perfectly
- (void)provider:(CXProvider *)provider performAnswerCallAction:(CXAnswerCallAction *)action{
[action fulfill];
}
- (void)provider:(CXProvider *)provider performEndCallAction:(CXEndCallAction *)action{
[action fulfill];
}
and also managed other delegate methods to manage call and everything, and it is working perfectly in all conditions.
I have checked these two scenarios with other apps like Google Duo, Whatsapp and FaceTime and it's showing CallKit properly without failing, but in my app it is failing. I have no clue where it is failing.
So, I have this 2 stated issues for iOS 13 and later versions. Any help will be appreciated.
Thanks.
This is probably an iOS 13 bug and, if you haven't already done it, you should report it to Apple.
I think that the reason why apps like Whatapp (and the one I develop) are working, is that we build the app against the iOS 12 SDK. We do this because of the limitations of VoIP push notifications introduced in iOS 13. So, you can try to work around the issue—at least until April 2020—building against the iOS 12 SDK. Hopefully, Apple we'll soon fix this issue.
#Max I have faced the same issue that you faced in iOS version 13.0 to 13.2.0.
As many developers have reported this issue to Apple. The latest iOS version that released last week(iOS 13.2.2) has this bug resolved. So, now instead of building from older SDK, you can start working with latest SDK and xCode 11.2.1.

OSX 10.10.3 crashes WebView on dealloc

After updating to 10.10.3 the WebView component started to crash after dealloc
- (void)dealloc {
[self.webView.windowScriptObject setValue:nil forKey:#"CocoaApp"];
[[self.webView mainFrame] stopLoading];
[self.webView setUIDelegate:nil];
[self.webView setEditingDelegate:nil];
[self.webView setFrameLoadDelegate:nil];
[self.webView setPolicyDelegate:nil];
[self.webView removeFromSuperview];
}
The crash happens somewhere deep in WebView
EXC_BAD_ACCESS
1 0x7fff910bae9e WebDocumentLoaderMac::detachFromFrame()
2 0x7fff920288c0 WebCore::FrameLoader::detachFromParent()
3 0x7fff910d0e55 -[WebView(WebPrivate) _close]
4 0x7fff910d0c49 -[WebView dealloc]
5 0x7fff8b1cf89c objc_object::sidetable_release(bool)
6 0x7fff8b1b5e8f (anonymous namespace)::AutoreleasePoolPage::pop(void*)
7 0x7fff912b26f2 _CFAutoreleasePoolPop
8 0x7fff8830e762 -[NSAutoreleasePool drain]
9 0x7fff8e3f0cc1 -[NSApplication run]
10 0x7fff8e36d354 NSApplicationMain
11 0x1000ebb12 main
12 0x7fff8c81e5c9 start
13 0x3
Any ideas? Is this a Apple bug? It started AFTER 10.10.3?
It doesn't crash when NSZombie is enabled!
I noticed you're using your own policy delegate:
[self.webView setPolicyDelegate:nil];
There's a known bug related to policy delegates in WebKit (only very recently fixed):
https://bugs.webkit.org/show_bug.cgi?id=144975
The short version is that you're probably hitting this assertion (which crashes the process with an intentional segfault):
https://github.com/WebKit/webkit/blob/24b1ae89efc10a4e6a6057b429c8e1d8d138a32f/Source/WebCore/loader/DocumentLoader.cpp#L935
because your policy handler (i.e. decidePolicyForMIMEType:request:frame:decisionListener:) is failing to make a policy decision (i.e not use, ignore, or download). The decision hangs around unmade, and when the loader eventually detaches it asserts that there are no pending policy decisions, which fails since the view is still waiting for a decision.
The fix i made, is not to release the webview, but hold a static reference into it (this is far from solving it and i contacted Apple regarding this issue)
#warning HOTFIX
{
//this is because of http://stackoverflow.com/questions/29746074/osx-10-10-3-crashes-webview-on-dealloc
static NSMutableArray * LIVE_FOR_EVER_WEBVIEW;
if (LIVE_FOR_EVER_WEBVIEW == nil) {
LIVE_FOR_EVER_WEBVIEW = [NSMutableArray new];
}
if (self.webView) {
[LIVE_FOR_EVER_WEBVIEW addObject:self.webView];
}
}

Multipeer Connectivity Disconnect

I'm having trouble with staying connected using the Multipeer Connectivity Framework in iOs7. Currently my app is programmatically handling the browsing and advertising using MCNearbyServiceAdvertiser and MCNearbyServiceBrowser. I have an alert view that asks the user if he is a browser or an advertiser. On the return from that view I instantiate either an MCNearbyServiceAdvertiser or Browser accordingly.
#pragma - Alert Delegate
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (buttonIndex == 0)
{
_browser = [[MCNearbyServiceBrowser alloc]initWithPeer:_peerID serviceType:#"Context-xl"];
[_browser setDelegate:self];
[self.detailViewController setRemote:YES];
[_browser startBrowsingForPeers];
} else
{
_advertiser = [[MCNearbyServiceAdvertiser alloc]initWithPeer:_peerID discoveryInfo:nil serviceType:#"Context-xl"];
[_advertiser setDelegate:self];
[self.detailViewController setRemote:NO];
[_advertiser startAdvertisingPeer];
}
[self.detailViewController configureView];
}
My session delegate method peer:...DidChangeState... is getting called twice, once for the connect and again for the disconnect. I'm not stopping the advertiser or browser at all after the session is started. Should I stop browsing/advertising?
EDIT Used a support ticket with Apple and they confirmed that calling sendData with too much data or too often can cause disconnects.
EDIT My hypothesis is that Apple has a thread or queue that is polling to check if peers are connected. If this thread / queue stalls (i.e. a breakpoint is hit or the app pegs the CPU or does something that takes a while on the main thread) it appears that this causes a disconnect.
Creating my session without encryption seems to have helped performance and with the disconnects, although they still happen.
MCPeerID* peerId = [[MCPeerID alloc] initWithDisplayName:self.displayName];
self.peer = [[MultiPeerPeer alloc] initWithDisplayName:peerId.displayName andPeer:peerId];
self.session = [[MCSession alloc] initWithPeer:peerId securityIdentity:nil encryptionPreference:MCEncryptionNone];
In addition, I have found calling sendData too often (more than 30-60 times a second) can cause the framework to get in a bad state and cause freezes and disconnects.

Changing music files auto next giving error and crashes the application?

I have set the songs array to play one by one.And I call a method
described below.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlayerPlaybackStateChanged:)
name:MPMoviePlayerPlaybackStateDidChangeNotification
object:player];
-(void) moviePlayerPlaybackStateChanged:(NSNotification*) sender
{
NSLog(#"in state changed = %d and isPause = %d", player.playbackState, isPause);
if (player.playbackState == MPMoviePlaybackStatePlaying) {
[activityIndicator stopAnimating];
}
if (player.playbackState == MPMoviePlaybackStateInterrupted) {
isPause =YES;
}
}
playing 5 or 6 songs the app get crashed and last log values are as follows:
2012-04-18 15:54:45.026 SymphonyProject[2896:207] in state changed = 1 and isPause = 0
2012-04-18 15:54:45.027 SymphonyProject[2896:207] in state changed = 2 and isPause = 0
[Switching to process 2896 thread 0x603b]
[Switching to process 2896 thread 0x603b]
sharedlibrary apply-load-rules all
and go to the file objc_mesgSend and pointing the line:
0x0164a09b <+0015> mov 0x8(%edx),%edi
I m not getting the error whatever it is? Please help me.
One question, you access player object in moviePlayerPlaybackStateChanged direct - is it class property? Because you send the object with this notification, so you should get the player object by retrieving it from sender.userInfo dictionary.

Mac Screensaver with WebView crashes

Hy everybody,
I have a screensaver made with obj-c and cocoa. Everything works fine under OsX 10.6.2 except the following.
Within my screensaver I have a WebView with some application running. When I try to call my objective-c app (the screensaver) via javascript, I get an error and the screensaver and the system preferences panel crash.
System Preferences[86666]
*** Terminating app due to uncaught exception 'NSInvalidArgumentException'
reason: '-[NSCFArray drain]: unrecognized selector sent to instance 0x20049b1e0'
*** Call stack at first throw:(
0 CoreFoundation 0x00007fff8123a444 __exceptionPreprocess + 180
1 libobjc.A.dylib 0x00007fff81f130f3 objc_exception_throw + 45
2 CoreFoundation 0x00007fff812931c0 +[NSObject(NSObject) doesNotRecognizeSelector:] + 0
3 CoreFoundation 0x00007fff8120d08f forwarding + 751
4 CoreFoundation 0x00007fff812091d8 _CF_forwarding_prep_0 + 232
5 WebCore 0x00007fff847adee0 _ZN3JSC8Bindings12ObjcInstance10virtualEndEv + 48
6 WebCore 0x00007fff8470d71d _ZN3JSC16RuntimeObjectImp18getOwnPropertySlotEPNS_9ExecStateERKNS_10IdentifierERNS_12PropertySlotE + 397
7 JavaScriptCore 0x00007fff80862b66 NK3JSC7JSValue3getEPNS_9ExecStateERKNS_10IdentifierERNS_12PropertySlotE + 486
)
I know this looks like some memory leak, but as you will see in the code, I really have nearly no objects allocated.
This only happens, when I start the screensaver with the "Test" button from the screensaver system prefs.
When I start the screensaver via terminal or if it starts automatically, the same action (calling obj-c from javascript) works fine.
Maybe someone has any idea, where the error could come from. Here is some code from the implementation:
#implementation ScreensaverView
- (id)initWithFrame:(NSRect)frame isPreview:(BOOL)isPreview {
self = [super initWithFrame:frame isPreview:isPreview];
if (self) {
[self setAnimationTimeInterval:-1];
[self setAutoresizesSubviews:YES];
// ::::::::::::::::::::::: Init stuff ::::::::::::::::::
// init
quitFlag = false;
previewMode = isPreview;
// find out the path the screensaver bundle
pMainBundle = [NSBundle bundleForClass:[self class]];
pBundlePath = [pMainBundle bundlePath];
// read Info.plist
infoDict = [pMainBundle infoDictionary];
}
return self;
}
- (void)startAnimation
{
[super startAnimation];
// combine: bundle path + filename for screensaver file
NSString *pathToScreensaver = [NSString stringWithString:pBundlePath];
NSString *valueScreensaverFile;
if(!previewMode)
{
valueScreensaverFile = [infoDict objectForKey:#"ScreensaverFile"];
}
else
{
valueScreensaverFile = [infoDict objectForKey:#"PreviewFile"];
}
// add filename to bundle path
pathToScreensaver = [pathToScreensaver stringByAppendingString:valueScreensaverFile];
// complete NSURL to the screensaver file
NSURL *screensaverUrl = [NSURL fileURLWithPath: pathToScreensaver];
webView = [WebView alloc];
[webView initWithFrame:[self frame]];
[webView setDrawsBackground:NO];
// delegation policy for interactive mode
[webView setPolicyDelegate: self];
[webView setUIDelegate:self];
// load screensaver
[[webView mainFrame] loadRequest:[NSURLRequest requestWithURL:screensaverUrl]];
scriptObject = [webView windowScriptObject];
[scriptObject setValue:self forKey:#"screensaver"];
[self addSubview:webView];
}
- (void)stopAnimation
{
[[webView mainFrame] stopLoading];
[webView removeFromSuperview];
[webView release];
[super stopAnimation];
}
+ (BOOL)isSelectorExcludedFromWebScript:(SEL)selector
{
if (selector == #selector(quitScreenSaver)) {
return NO;
}
if(selector == #selector(gotoUrl:) ){
return NO;
}
return YES;
}
+(NSString *)webScriptNameForSelector:(SEL)selector
{
if(selector == #selector(quitScreenSaver))
{
return #"quitNoOpen";
}
if(selector == #selector(gotoUrl:))
{
return #"openAndQuit";
}
return nil;
}
- (void) quitScreenSaver
{
quitFlag = true;
[super stopAnimation];
}
- (void) gotoUrl:(NSString *) destinationURL
{
if(destinationURL == NULL)
{
return;
}
NSString * path = destinationURL;
NSURL * fileURL = [NSURL URLWithString:path];
[[ NSWorkspace sharedWorkspace ] openURL:fileURL];
[self quitScreenSaver];
}
#end
I hope that's enough code for you to see some problems / solutions.
I would really appreciaty any answers.
Somehow an NSCFArray (NSMutableArray) is being sent a "drain" message that's meant for an NSAutoreleasePool.
You might be able to get a bit more info on what the array is by implementing the drain method for NSMutableArray, so you can trap the now-recognized selector and print out the contents of the array object. Try adding this somewhere in your code:
#interface NSMutableArray (drain)
- (void) drain;
#end
#implementation NSMutableArray (drain)
- (void) drain
{
NSLog(#"drain message received by object: %#", self);
}
#end
If you don't see any messages show up in the Console, try changing the "NSMutableArray" in the above code to "NSObject".
One thing to be aware of is that when you start the screensaver via the "Test" button in System Prefs, you actually have 2 instances of your screensaver view running in the same process' address space on different threads. One (with isPreview==YES) is the little preview in the SysPrefs window (which continues running even when the full-screen version is started), and the other one is the full-screen version. They are both running in the SysPrefs.app process. So, you have to be careful to check all Notifications/etc. to see if they are coming from the view instance you expect.
I don't see any obvious problems from a quick glance at the code you posted, but it may be somewhere else. Do you use Notifications anywhere?
I put a similar webview-in-a-screensaver project on github at http://github.com/kelan/WikiWalker, where I initially had some similar problems (though I wasn't using any javascript stuff). It's not perfect code, but might help. I also did some tricks to forward notifications to the main thread (for drawing) in a . See the "Threaded Notification Support" parts of WWScreenSaverView.{h,m}.
Something to try:
Open up a terminal window and enter the following line to run System Preferences with NSZombieEnabled:
env NSZombieEnabled=YES "/Applications/System Preferences.app/Contents/MacOS/System Preferences"
Perform the steps that lead to the crash.
Run the Console app, set the filter in the upper right to "System Preferences", and look for NSZombie messages.
Hope this helps!
Just to troubleshoot, did you try not releasing the WebView?
Also, maybe set the WebView's delegates to nil before releasing it first?