Using Array from ViewController in AppDelegate - ios

I have an array stored in the ViewController.m. But when the app enters background, i want to post notifications from the array.
so my NSMutableArray "list" was created in ViewController.m but i need to use in AppDelegate.m
- (void)applicationDidEnterBackground:(UIApplication *)application
for (NSString *thing in list) {
UILocalNotification *notif = [[UILocalNotification alloc] init];
notif.alertBody = thing.text;
[[UIApplication sharedApplication] presentLocalNotificationNow:notif];

If ViewController.m is your main VC:
ViewController *yourVC = (ViewController*)self.window.rootViewController;
yourVC.yourMutableArray = whateverYouWant;
I recommend saving the data inside of NSUserDefaults however, then you can just easily access it and read/write anywhere. BTW the presenting of localNotifications from that method in the appDelegate is a bad idea. The app store will not be a fan of immediate notifications when someone tries to leave an app..if you're even able to.

Related

How to manage state in ios objective c

I’m new in iOS development. My question is, I’ve two view controllers.
viewController - A viewController - B
Now, if i killed the app from the viewController - A and than relaunch the app. than app must be open the viewController - A. and if i killed the app from the viewController - B and than relaunch the app. than app must be open the viewController - B.
Can anyone help me, I’ve done the RND but can not find the proper solution.
Thanks
Create a sharedDelegate in AppDelegate.m file
+(AppDelegate *)sharedDelegate {
return (AppDelegate *) [UIApplication sharedApplication].delegate;
}
in AppDelegate.h
+ (AppDelegate *)sharedDelegate;
#property (nonatomic, strong) NSString *currentViewContoller;
when push to any contoller then set AppDelegate's currentViewContoller to new VC
YourViewController *vc=[[YourViewController alloc] init];
[self.navigationController pushViewController:vc animated:YES];
[AppDelegate sharedDelegate].currentViewContoller = NSStringFromClass([YourViewController class]);
now when app is terminated
- (void)applicationWillTerminate:(UIApplication *)application {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
[[NSUserDefaults standardUserDefaults]setObject:[AppDelegate sharedDelegate].currentViewContoller forKey:#"currentVC"];
}
now when app launched first time check previous controller when app terminated
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSString *string=[[NSUserDefaults standardUserDefaults] valueForKey:#"currentVC"];
and push this class
UIViewController *object = [[NSClassFromString(string) alloc] init...];
}
applicationWillTerminate you can use but it will only get called if user quit app from forground If your app is in background and then user quit app then applicationWillTerminate will not get called.
So, you have to take care of applicationDidEnterBackground.
So, when app enter in background (i.e call applicationDidEnterBackground ) or call applicationWillTerminate save state(your current VC) in your user defaults.
Now in your didFinishLaunchingWithOptions set that view controller as rootviewcontroller or whatever way that you want to manage it.
reference : Apple documentation for applicationWillTerminate
PS : You should not manage app like this. It is horrible way!! If possible then run your app as normal flow!
If you're using Storyboards you can use the Restoration Identifier to communicate the App which controller to launch as first
https://developer.apple.com/library/ios/featuredarticles/ViewControllerPGforiPhoneOS/PreservingandRestoringState.html

iOS : Handle all the uilocalnotification on click of one notification or app icon

How do i handle (open alert for) all the UILocalNotification on click of one notification since apple clears other notification from notification center on click of one notification...also if the user opens the app ignoring the notifications in notification center, how do i handle(open UIAlertView for) them as well? i have seen this working perfectly in Calminder app
You can use [[UIApplication sharedApplication] scheduledLocalNotifications]; to get all the notifications that are previously scheduled. This method returns an NSArray instance so you can run a for loop to handle these:
for (UILocalNotification *notification in [[UIApplication sharedApplication] scheduledLocalNotifications]) {
// Handling codes goes here.
}
If you wants to have some extra informations in the notification you can use the userInfo property. It is a dictionary to store additional informations along the notification. You can set it like this:
notification.userInfo = // The dictionary goes here.
So now you can do this:
for (UILocalNotification *notification in [[UIApplication sharedApplication] scheduledLocalNotifications]) {
NSDictionary *userInfo = notification.userInfo;
// Handling codes goes here. Now you can use the user info dictionary to
// get what you stored into the userInfo dictionary when you are
// initializing the user info.
}
After this you can get all the informations and you can present it in an UIAlertView.
To call these codes above at app's launch you can use two methods:
-application:didFinishLaunchingWithOptions:
or
-applicationDidBecomeActive:
Hope this helps.

NSUSer defaults and swiping the application off ios

All,
I just cannot find an answer to this question. The settings View Controller needs to shown once on startup ONLY. So when you download the app from the App Store / test flight.
I have it correct, so it runs it first, thats fine.
when you have finished with the settings page it goes to the main page and when you move the app to the background it carries on from where it left off. thats fine.. But... When you swipe the app away by double pressing the home button and pushing the app up to remove (ios7) it goes back to the settings screen again but it should carry on from where it left off.
So in my App Delegate, I have :
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
NSString *savedValue = [[NSUserDefaults standardUserDefaults] stringForKey:#"SettingsShown"];
NSLog(#"%#", savedValue);
Reachability *reachability = [Reachability reachabilityWithHostname:#"www.outtonightapp.com"];
[reachability startNotifier];
NSUserDefaults *settingsscreen = [NSUserDefaults standardUserDefaults];
[settingsscreen registerDefaults:[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES],#"firstTime", nil]];
//BOOL firstTime = [settingsscreen boolForKey:#"firstTime"];
BOOL firstTime = [settingsscreen boolForKey:#"SettingsShown"];
if (!firstTime) {
//if ( firstTime==YES) {
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:#"SettingsShown"];
[[NSUserDefaults standardUserDefaults] synchronize];
self.window.rootViewController = [self.window.rootViewController.storyboard instantiateViewControllerWithIdentifier:#"SetUpNav"];
}
else
{
return YES;
}
This did work until I had to recreate my settings VC.. any advice would be great.
In similar situation I used delegation pattern.
Assume you have your initial view controller initialVC. And special settings view controller (SetUpNav) which is meant to be run only first time when defaults is not set. Then you could do the following:
You define SetUpNavdelegate protocol in SetUpNavViewController.h and property "initiator" conforming to that protocol
#protocol SetUpNavDeleagte;
#interface SetUpNavViewController : UIViewController
#property (strong,nonatomic) id <SetUpNavdelegate> initiator;
// the rest
#end
#protocol SetUpNavdelegate <NSObject>
-(void)setupFinished;
#end
In your InitialVC' viewDidLoad you do:
Check Your defaults are set properly or not by determine "firstTime" BOOL value
and fire setUpNav controller in code
-(void)viewDidLoad
{
// Check your defaults for consistency
if (firstTime){
UIStoryboard *sb = [UIStoryboard storyboardWithName:#"Main OR you SB name" bundle:nil];
UIViewController *setUpNavVC = [loginStoryboard instantiateViewControllerWithIdentifier:#"SetUpNav"];
setUpNavVC.initiator = self;
YouAppDelegateClass *appDelegate = [[UIApplication sharedApplication] delegate];
appDelegate.window.rootViewController = setUpVC;
// Here you don't need animation as I assume it is the very first screen
}
// ... the rest
}
-(void)setupFinished
{
// Here You animately restoring your initial vc.
YouAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
appDelegate.window.rootViewController = self; // This line is for device orientation sync
[UIView transitionWithView:appDelegate.window
duration:FINISH_DURATION
options:UIViewAnimationOptionTransitionCrossDissolve | UIViewAnimationOptionCurveEaseInOut
animations:^{ appDelegate.window.rootViewController = self; }
completion:nil];
// setUpNav controller will be dealloced by ARC
}
In your setUpNavViewController after you finished all defaults job you set notification for your delegation:
[self.initator setupFinished];
In may app this setting work is actually a separate storyboard with it's own workflow in it. By the way using this approach you are able not only show it first time but whenever your app's user defaults is not set properly (like if you using settings bundle). You can show it modally, in navigation stack or in pop over (iPad case). It is a more generic approach.
Summary: The one who starts, he finishes.

Calling UILocalNotification from Main.m

I'm not sure if this is possible but I'm trying to fire a UILocalNotification from a function running on Main.m. So far I tried a couple of different ways but I'm a bit confused on who must present the notification because the simple way doesn't seem to work:
I call this code from a static function called by an Observer (defined in Main.m) on CTTelephonyCenter
UILocalNotification *localNotif = [[UILocalNotification alloc] init];
if (localNotif) {
NSLog(#"Ciao");
localNotif.alertBody = [NSString stringWithFormat:
#"La telefonata é finitá!!!!!"];
localNotif.alertAction = NSLocalizedString(#"Read Message", nil);
localNotif.soundName = #"alarmsound.caf";
localNotif.applicationIconBadgeNumber = 1;
[[UIApplication sharedApplication] presentLocalNotificationNow:localNotif];
}
Now, the Log shows up but localNotif doesn't.
Is it just how I'm afraid, and I just can't do it from a static function called by Main because the window is not defined?
I know I shouldn't mess around with main.m
Try implementing:
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification;
http://developer.apple.com/library/ios/#documentation/uikit/reference/UIApplicationDelegate_Protocol/Reference/Reference.html
in your application delegate.
If your app is open you can log things here, but notification center wont present anything. Notifications only show up in notification center if your app is in the background.

Dismiss an already delivered UILocalNotification?

Is it possible to do this? UIApplication's scheduledLocalNotifications doesn't seem to return notifications that have already been delivered to the user's notification center, so I think this may be by design, but I can't find any documented evidence of this.
Anyone know?
Thanks!
EDIT: Found this:
You can cancel a specific scheduled notification by calling
cancelLocalNotification: on the application object, and you can cancel
all scheduled notifications by calling cancelAllLocalNotifications.
Both of these methods also programmatically dismiss a currently
Here: http://developer.apple.com/library/mac/#documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/IPhoneOSClientImp/IPhoneOSClientImp.html
However, how do I get a reference to an already-delivered notification, if scheduledLocalNotifications doesn't give me notifications that have already been delivered?
EDIT 2:
Here's what I'm trying to do, after I've registered some notifications:
UIApplication *app = [UIApplication sharedApplication];
for (UILocalNotification *localNotification in app.scheduledLocalNotifications)
{
if (someCondition) {
[app cancelLocalNotification:localNotification];
}
}
}
The problem is that once they're delivered, they're no longer in 'scheduledLocalNotifications'.
You can solve this by adding your newly created notifications to your own NSMutableArray of notifications and check that array instead of app.scheduledLocalNotifications.
Something like this:
Add a NSMutableArray to your Viewcontrollers .h file:
NSMutableArray *currentNotifications;
Initiate it when initiating your ViewController
currentNotifications = [[NSMutableArray alloc] init];
When initiating a notification, also add it to your array:
UILocalNotification *notification = [[UILocalNotification alloc] init];
...
[currentNotifications addObject:notification];
[[UIApplication sharedApplication] presentLocalNotificationNow:notification];
Later when you want to cancel that notification, look for it in your array instead.
Also remove it from your array:
for (UILocalNotification *notification in currentNotifications) {
if (someCondition) {
[[UIApplication sharedApplication] cancelLocalNotification:notification];
[currentNotifications removeObject:notification];
}
}
Since iOS10 there is now native support for this if you have transitioned to using UNUserNotificationCenter.
The Apple docs state:
func getDeliveredNotifications(completionHandler: #escaping ([UNNotification]) -> Void)
Provides you with a list of the app’s notifications that are still displayed in Notification Center.
func removeDeliveredNotifications(withIdentifiers: [String])
Removes the specified notifications from Notification Center.
func removeAllDeliveredNotifications()
Removes all of the app’s notifications from Notification Center.
I've been looking for an answer to this as well. My problem was that I wanted to 'clean up' all app-related notifications sitting in the notification center just in case the user opens the app from its dock icon (since that does nothing to the previously fired notifications...)
Fortunately, it would appear that cancelAllNotifications doesn't just cancel scheduled ones, but EVERYTHING. So I simply held on to a reference of the existing scheduled notifications before blasting them, and then rescheduled them accordingly:
UIApplication *app = [UIApplication sharedApplication];
NSLog(#"\nScheduled notif count (prior) = %d", app.scheduledLocalNotifications.count);
NSArray *scheduledNotifs = app.scheduledLocalNotifications; // hold on to a reference
[[UIApplication sharedApplication] cancelAllLocalNotifications]; // blast everything
NSLog(#"\nScheduled notif count (post-wipeout) = %d", app.scheduledLocalNotifications.count);
for (UILocalNotification *notif in scheduledNotifs) {
[app scheduleLocalNotification:notif]; // put them back
}
NSLog(#"\nScheduled notif count (post-repopulation) = %d", app.scheduledLocalNotifications.count);
Not sure if that helps anyone but this worked great for my situation.
Try this links:
Apple doc
Some tutorial
And local notification is registering to device notification center, not in your app.
But, if your app is running, and is a notification time, then you can get notification parameters in game in:
-(void) application:(UIApplication*)app didReceiveLocalNotification:(UILocalNotification*) notification
{
// local notification is geted
}
You can do it when you schedule the notification if you also save it in NSUserDefaults, using NSKeyedArchiver to convert it to NSData.
To get it back as UILocalNotification you use NSKeyedUnarchiver. Then you're able to delete it using the cancelLocalNotification method.
Fully explained here (Swift version + link to original Obj-C solution)
After seeing your updated code, it seems you are interested in cancel all the notifications with-in for loop, so you can use -
[[UIApplication sharedApplication] cancelAllLocalNotifications];

Resources