"Unable to monitor event loop" crash - ios

I add breakpoint and find that it block in the method that
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
// init local data
[[PDKeychainBindings sharedKeychainBindings] setObject:#"0" forKey:kNEED_GESTURE_LOGIN];
// register notification to notice switching RootVC
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(switchRootControllerWithType:)
name:kNoti_SwitchRootView
object:nil];
// init the third part SDK
[self setupShareSDK];
[self setupBugly];
[self setupUMeng];
[self setupIQKeyBoard];
[self setupZhugeIOWithOptions:launchOptions];
[self setupTrusfort];
// register push service
[self setupJPushWithOptions:launchOptions];
[self dealWithRemoteNotification:launchOptions];
// set local flag
[KXUserIntroManager setupFlag];
if (self.remoteNotification) {
if ([AccountStateManager isLogin])
[self.loginNavigationController showGesturePDViewController];
self.window.rootViewController = self.loginNavigationController;
} else {
self.window.rootViewController = self.launchController;
}
return YES;
}
i also try the way in stackOverFlow ,Add the following code to the above method
NSArray *args = [NSProcessInfo processInfo].arguments;
for(NSString *arg in args){
if ([arg isEqualToString:#"NoAnimations"]) {
[UIView setAnimationsEnabled:false];
}
}
Image link
it is the detail of didFinishLaunching method. it just init some data and create a notification

While this is not a direct answer to your question, it may well be that your issue is symptomatic of the very evident fact that you are doing much too much work, on the main thread, in didFinishLaunchingWithOptions. Your main job in this method is to get out of the way and let the runtime launch the app. You are doing the exact opposite of that.

Related

Methods not called after openURL function ONLY if app is not active

After visiting a share url on a website, viewers are prompted to open the link in my application. If the application is running, it works perfectly.
However, if the application is closed, the viewDidLoad and viewWillAppear methods are not called on my ViewController, so I am not able to open the desired ViewController.
Does anyone know how to allow to get the viewDidLoad function to run if the app is launched from the openURL function?
I currently have:
AppDelegate:
-(BOOL) application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
if (!url) { return NO; }
NSString *party_url = [NSString stringWithFormat:#"%#%#/", PARTYURL, url.lastPathComponent];
[[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:#"WebViewNotification" object:party_url]];
return YES;
}
ViewController:
- (void)viewDidLoad {
[super viewDidLoad];
appDelegate = [AppDelegate getDelegate];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(webViewNotification:) name:#"WebViewNotification" object:nil];
}
- (void)webViewNotification:(NSNotification *)notification {
NSString *url = [notification object];
PartyViewController *partyViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"PartyViewController"];
partyViewController.partyUrl = url;
[self.navigationController pushViewController:partyViewController animated:YES];
}
Again, this works fine if the app was previously opened. However, if it is closed, this does not work. Thank you!
When your app launched from a link without any other operation you don't have a presented ViewController contains this code in your views stacks. so this code will never been executed. consider directly present partyViewController in your CustomTabBarController.

Selector don't getting notification from NSNotificationCenter (iOS)

I am sending a notification from a class inherits from NSObject using NSNotificationCenter.
The notification should be sent to 2 viewController but it's being sent just to one of them.
My Code:
fetchFromParse:
-(void)sendAllStores
{
[[NSNotificationCenter defaultCenter]postNotificationName:#"getStoresArrays" object:nil userInfo:self.storesDict];
}
firstVC.m (working):
- (void)viewDidLoad {
[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(getStoresArrays:) name:#"getStoresArrays" object:nil];
}
-(void)getStoresArrays:(NSNotification*)notification
{
NSLog(#“Working”); //Working
}
secondVC.m (not working):
-(void)prepareArrays
{
[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(getStoresArrays:) name:#"getStoresArrays" object:nil];
}
-(void)getStoresArrays:(NSNotification*)notification
{
NSLog(#“Not Working”); //Not working
}
AppDelegate.m:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
secondVC *secVC=[[secondVC alloc] init];
[secVC prepareArrays];
fetchFromParse *fetchFromParseObj=[[fetchFromParse alloc] init];
[fetchFromParseObj getStoresFromParse];
Return YES;
}
Note: Xcode shows me an error message that "firstVC is not registered as an observer".
The firstVC is never used so it cannot add an observer then.
It adds the observer in the viewDidLoad, but if the view controller is never used it cannot load a view and therefore not add an observer.
The logic for your code is not correct. You are posting a notification and have made two classes as observer, so this will lead to unpredictable results. You should have one class as observer for a notification.
From what i see only one notification listener should be called here and that should be your SecondVC because your first view controller is not loaded yet so no observer is registered for first view controller.

presentViewController is not working when the first time application launch

I am facing this weird problem. I have a simple piece of code that is supposed to work fine but it doesn't work when first time launching the app. It works perfectly fine when I run the application second time.
And by the way the following code is used to open the application and display a viewController when i tap the today view widget:
- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url
{
OverviewDetailVC *overViewDetail = (OverviewDetailVC *)initViewController;
overViewDetail.productDetail = [self.managedObjectContext executeFetchRequest:FetchRequest error:nil];
overViewDetail.productName = [overViewDetail.productDetail[0] valueForKey:#"generic"];
[self.window.rootViewController presentViewController:overViewDetail animated:YES completion:NULL];
}
Try this:
(BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url
{
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter] postNotificationName:#"secondshowPushNotification" object:nil];
});
}
FirstView controller:
(void)viewDidLoad
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(showCompanyFromPushNotification:) name:#"secondshowPushNotification" object:nil];
}
-(void)showCompanyFromPushNotification:(NSNotification*)notification
{
[self.rootController presentViewController:secondViewController animated:YES completion:nil];
}
// it open's secondViewController.

UIWindow's makeKeyAndVisible and background task

I've add the background task feature to my application. Here is my app delegate
// AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[self setWindow:[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]];
[self.window setBackgroundColor:[UIColor blackColor]];
if (application.applicationState != UIApplicationStateBackground) {
// Application is launch in because user tap the app icon or from springboard
if ([application respondsToSelector:#selector(setMinimumBackgroundFetchInterval:)]) {
[application setMinimumBackgroundFetchInterval:UIApplicationBackgroundFetchIntervalMinimum];
}
} else {
// Application is launch in background mode
}
RootViewController *rootViewController = [[RootViewController alloc] initByDevice];
[self.window setRootViewController:rootViewController];
[self.window makeKeyAndVisible];
return YES;
}
- (void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
[[DataManager instance] updateDataWithMaxAttempt:5 block:^(BOOL success, NSArray *newData) {
if (success) {
if ([newData count] > 0) {
completionHandler(UIBackgroundFetchResultNewData);
} else {
completionHandler(UIBackgroundFetchResultNoData);
}
} else {
completionHandler(UIBackgroundFetchResultNoData);
}
}];
}
And this is my root view controller
// RootViewController.m
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
NSLog(#"Did appear");
// Do something that I want it to happen only when the application is visible to user
}
When the user tap the app icon, application works like what I expected. I see "Did appear" in console and stuff is happening after that like I expected.
But when the application awake to perform background task (which not visible to user) the RootViewController's viewDidAppear still getting call because of this line
[self.window makeKeyAndVisible];
By calling makeKeyAndVisible, it makes RootViewController visible even though it's only awake for background task. To fix this, I have to move this line to applicationDidBecomeActive
- (void)applicationDidBecomeActive:(UIApplication *)application {
[self.window makeKeyAndVisible];
}
As a result, the RootViewController's viewDidAppear now being call only when the application is in foreground (visible to user). But, my concern is, when application is in device memory (either active or inactive) applicationDidBecomeActive will be call several times.
user launch app
application become active again from springboard
device unlock
finish call
Is there any issue if I call UIWindow's makeKeyAndVisible several times during the application life cycle?
You can easily ensure that makeKeyAndVisible only happens once: wrap it.
if (!self.window.keyWindow) {
[self.window makeKeyAndVisible;
} else if (self.window.hidden) {
self.window.hidden = NO;
}

NSKeyedArchiver saving iOS

I'm trying to save for the first time. Made my application, and now going to save data and load on startup and close. Looked into NSKeyedArchiver and added the two methods from the NSCoding to all my custom classes:
-(void)encodeWithCoder:(NSCoder *)aCoder{
// Encode Stuff
}
-(id)initWithCoder:(NSCoder *)aDecoder{
if (self = [super init])
// Decode Stuff
return self;
}
But now i'm finding a problem, where and how do i need to call my saveFile and loadFile? My data is stored in 2 arrays in my FirstViewController. And i wanted to save the data with the AppDelegate's - (void)applicationWillTerminate:(UIApplication *)application and load data with - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions But how is this possible to reach the FirstViewController class with the Arrays in it to store from the AppDelegate method's?
Is the thinking right, or do i need to do it on an other way?
Kind Regards
Loading data should be "lazy". This means the data should be loaded the first instant that you actually need to read the data. Also, if it's a lot of data, you should be prepared to free it while your app is running so other apps can use the RAM, this means your app is more likely to still be running next time the user launches your app.
So, make a class that provides access to the data, and the first time anything needs data it checks if the internal NSCoding object is nil, and if it is then that is where you should load the data.
As for saving, you should save before terminating but more importantly you should also save within a second or so of any data being modified by the user. Your app should crash at any moment due to a software bug, or it could be terminated for some other reason, or the battery could simply run out.
Lets say your internal data storage is an NSMutableDictionary saved using NSKeyedArchiver. It has a value with the key #"value", with a "getter" and "setter" implemented like this:
- (NSString *)value
{
if (!self.data)
self.data = [NSKeyedUnarchiver unarchiveObjectWithFile:self.dataFile];
return self.data[#"value"];
}
- (void)setValue:(NSString *)value
{
if (!self.data)
self.data = [NSKeyedUnarchiver unarchiveObjectWithFile:self.dataFile];
self.data[#"value"] = value;
self.needsSave = YES;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self save];
});
}
- (void)save
{
if (!self.needsSave)
return;
[NSKeyedArchiver archiveRootObject:self.data toFile:self.dataFile];
self.needsSave = NO;
}
Finally, your class should also register for UIApplicationDidReceiveMemoryWarningNotification, UIApplicationWillResignActiveNotification, UIApplicationWillTerminateNotification, where you want to save to disk and free the RAM so other apps can use it:
- (id)init
{
if (!(self = [super init]))
return nil;
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(saveAndFreeMemory:) name:UIApplicationDidReceiveMemoryWarningNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(saveAndFreeMemory:) name:UIApplicationWillResignActiveNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(saveAndFreeMemory:) name:UIApplicationWillTerminateNotification object:nil];
return self;
}
- (void)saveAndFreeMemory:(NSNotification *)notif
{
[self save];
self.data = nil;
}
When a UIApplication launches in the normal way, you can always call [[UIApplication sharedApplication] delegate] from any object in the app, and you will thus obtain a reference to the application's delegate.
This is how view controller code generally gets ahold of the app delegate, you establish the connection in the view controllers in their respective -awakeFromNib methods -- it's generally less gotcha-prone to have the view controllers make the first contact with the app delegate, than having the app delegate reach out to the view controllers.
Have your app delegate decode the saved data into a model object hierarchy, have your view controllers connect with the app delegate and begin KV observing the model in -awakeFromNib.
Or just use Core Data.

Resources