I would like to know if we can actually redirect the alert box to a specific view. Meaning that when they clicked on "View" which is on the notification alert, it will redirect them to a particular view, just like the text message notification pop up. Is there any idea on how this works?
From your question, you could mean two types of alert dialogs:
The generic "alert box" you mention, or UIAlertView
A UILocalNotification alert dialog, shown when the application is in the background ("just like the text message notification pop up")
I will address them in order.
First, how to handle a UIAlertView "View" button click.
Implement the alertView:didDismissWithButtonIndex: method of the UIAlertViewDelegate protocol in your controller class, and when you init the UIAlertView set its delegate to self. Then when the user clicks a button marked e.g. "View", do this:
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
{
if([[alertView buttonTitleAtIndex:buttonIndex] isEqualToString:#"View"])
{
// take the user to a specific view
} else { // handle other cases if you have any
}
}
Secondly, how to handle a UILocalNotification which triggers an application launch.
Apple docs on UILocalNotification state:
If the notification is an alert and the user taps the action button (or, if the device is locked, drags open the action slider), the application is launched. In the application:didFinishLaunchingWithOptions: method the application delegate can obtain the UILocalNotification object from the passed-in options dictionary by using the UIApplicationLaunchOptionsLocalNotificationKey key. The delegate can inspect the properties of the notification and, if the notification includes custom data in its userInfo dictionary, it can access that data and process it accordingly.
On the other hand, if the local notification only badges the application icon, and the user in response launches the application, the application:didFinishLaunchingWithOptions: method is invoked, but no UILocalNotification object is included in the options dictionary.
You need to write code for handling this launch case in your app delegate class, in the application:didFinishLaunchingWithOptions: method.
IF you happen to get a UILocalNotification while the app is running, Apple docs state:
If the application is foremost and visible when the system delivers the notification, no alert is shown, no icon is badged, and no sound is played. However, the application:didReceiveLocalNotification: is called if the application delegate implements it. The UILocalNotification instance is passed into this method, and the delegate can check its properties or access any custom data from the userInfo dictionary.
EDIT: To take the user to a specific view straight away, you can manually push something onto a UINavigationController stack (if your app usually operates with navigation controllers, it makes sense to do this), or present a modal view controller. I've linked there to guides for both.
Related
In app delegate, I have written some code in the didRecieveLocalNotification Method which firstly determines which local notification was triggered, and then generates a UIAlert once the app re opens after clicking the notification banner.
If my app is closed, the local notification is still received, and clicking on it does re open the app from its terminated state, however the code inside of the didRecieveLocalNotification method is not triggering at all. I can't even get a NSLog to work.
Anything I can do to fix this?
Have a look at https://developer.apple.com/library/ios/documentation/iphone/Reference/UILocalNotification_Class/Reference/Reference.html
You can get this information in application:didFinishLaunchingWithOptions, but only if user taps the local notification.
When the system delivers a local notification, several things can happen, depending on the application state and the type of notification. If the application is not frontmost and visible, the system displays the alert message, badges the application, and plays a sound—whatever is specified in the notification. If the notification is an alert and the user taps the action button (or, if the device is locked, drags open the action slider), the application is launched. In the application:didFinishLaunchingWithOptions: method the application delegate can obtain the UILocalNotification object from the passed-in options dictionary by using the UIApplicationLaunchOptionsLocalNotificationKey key. The delegate can inspect the properties of the notification and, if the notification includes custom data in its userInfo dictionary, it can access that data and process it accordingly. On the other hand, if the local notification only badges the application icon, and the user in response launches the application, the application:didFinishLaunchingWithOptions: method is invoked, but no UILocalNotification object is included in the options dictionary.
If the application is foremost and visible when the system delivers the notification, no alert is shown, no icon is badged, and no sound is played. However, the application:didReceiveLocalNotification: is called if the application delegate implements it. The UILocalNotification instance is passed into this method, and the delegate can check its properties or access any custom data from the userInfo dictionary.
When you app is neither running nor in the background, your notification is received in application:didFinishLaunchingWithOptions: method in your app delegate.
You can use the below code to access the notification object.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
UILocalNotification *localNotif = [launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey];
if (localNotif) {
// Show Alert Here
}
}
Im new to Objective-C & iOS programming so Im very confused about event and action handling. I don't really understand what is the difference between connecting a button in Interface builder with its files owner method (for instance connecting button action pressed with my personal method buttonClicked) and on the other hand creating a delegate which will respond to button events? I am confused because I come from C# (.NET) and there you only handling events via delegation.
Let's create event handling programmatically first. Some assumptions ...
you have class MyViewController
this class does contain property myButton (UIButton *)
you do want to handle events in this class
First step is to create method to handle your button taps:
-(void)onMyButtonTap:(UIButton *)sender {
// My button was tapped, whoa, which one is in sender argument
}
Add tap event handling:
-(void)loadView {
[super loadView];
[self.myButton addTarget:self action:#selector(onMyButtonTap:) forControlEvents: UIControlEventTouchUpInside];
}
What this code does? self in this case is instance of MyViewController class, which is going to handle touch up inside event (addTarget). action is method which will be called when UIControlEventTouchUpInside fires.
So the addTarget:... line adds event handling and when the control event fires, this ...
[self onMyButtonTap:self.myButton];
... will be called automatically.
It's simplified example, it can be more complicated in the real world:
you can have UIButton in separate UIView (good practice, I dislike when people put them in UIViewController)
you can handle multiple buttons taps in one method (distinguish between them by sender argument)
you can create more tap handling methods, one method for one button,
...
And now back to outlets. Outlet is just an automatic glue for addTarget:....
UIButton is subclass of UIControl and here you can see how other events can be handled and what events you can handle.
Delegation is also common practice, but not for UIControl. There's no delegate, etc. You have to do it in this way.
Or you can enhance UIButton to handle events via blocks for example. Here's one way https://gist.github.com/2468899 or you can Google for more.
What is the best way to display a view (in my case a login screen) on app resume. From looking around, I've been playing with the applicationDidBecomeActive event in my AppDelegate, but I cannot seem to get my head around how to properly display a view from here.
I've tried to grab the current window by using self.window and/or it's subviews, but from the AppDelegate self.window is nil.
So far this application seems to be wired up correctly, but I am baffled by two things.
A) why is self.window nil from within my AppDelegate's applicationDidBecomeActive event handler.
B) what is the correct/normal way of display a login view (or the like) on application resume.
Implement a custom UIViewController for all of your applications to inherent from. In this view controller implement logic in the viewWillAppear message to determine and show the login screen if necessary.
//CustomViewController.h
#interface CustomViewController : UIViewController
#end
//CustomerViewController.m
#implementation CustomViewController
-(void)viewWillAppear:(BOOL)animated{
if(login_required){
LoginViewController *loginView = [[LoginViewController alloc] initWithNibName:#"LoginView" bundle:nil];
[self presentModalViewController:loginView animated:false];
}
}
#end
Then, simply, in your login view controller make sure you call:
[self dismissModalViewControllerAnimated:false];
The benefits of this approach are two fold. Firstly, it's a very simple implementation. However, most compellingly, having a base class for an application's view controller presents the opportunity to extract common logic.
Jason,
I have worked on a security tutorial provided by Chris Lowe on raywenderlich.com that was intended to demonstrate how to use basic iOS security to lock the application.
The premise behind this tutorial though was that the application would prompt for login upon first launch and if application was resumed upon unlocking the device through the use of NSNoftificationCenter in viewDidLoad and subscribe the the notifications: deviceWillLock and deviceWillUnlock. All of this assumes the device is set to lock.
Basic iOS Security Tutorial Part 2 - This is the part that has the NSNotification registration.
Basic iOS Security Tutorial Part 1 - This is the first part of the tutorial for clarity.
I also ran into this problem and came across this question whilst researching a solution. I didn't want to create the intermediate super class for my views and I wasn't sure how it would work out with navigation controllers. I have come up with another solution that works well for me - so thought I would share it. It is based around the use of NSNotificationCenter .
In your app delegate create a property to hold a reference to the currently displayed view controller - say currentViewController.
Then in the applicationDidFinishLaunching method, register a block observer to update the currentViewController property like this:
[[NSNotificationCenter defaultCenter] addObserverForName:#"CurrentViewChanged"
object:nil
queue:nil
usingBlock:^(NSNotification *note)
{self.currentViewController = (UIViewController *)note.object;} ];
In your view controller implementations, update the viewDidAppear methods to notify the observer that a new view controller is being displayed by adding the following line
[[NSNotificationCenter defaultCenter] postNotificationName:#"CurrentViewChanged" object:self];
Finally, include code in the applicationDidBecomeActive method in your app delegate to force the modal display of your login screen.
UIStoryboard *mainStoryBoard = self.window.rootViewController.storyboard;
UnlockViewController *uvc = [mainStoryBoard instantiateViewControllerWithIdentifier:#"modalUnlockView"];
uvc.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self.currentViewController presentViewController:uvc animated:YES completion:NULL];
A couple of additional items to note :-
You can disable the login screen display at anytime by posting a notification where the view controller passed is nil.
You only need to post the notification once for a navigation view controller at the top level. All view controllers in the navigation controller stack will be covered. I haven't checked, but I suspect the same is true for a tab view controller.
If you want to display the login screen the first time you enter the app after startup then include the following line in the applicationDidFinishLaunching method.
self.currentViewController = self.window.rootViewController;
I hope this is of some use.
Thanks
I have a navigation controller I created in a storyboard. The forward and back functions work fine...The part I am struggling with is how I can save state of the application when the back button is pressed. Is there a way I can have my current view controller be notified when the back button is pressed?
How can I use viewWillDisappear in this case:
ReaderViewController *readerViewController = [[ReaderViewController alloc] initWithReaderDocument:document];
readerViewController.title = model.title;
readerViewController.delegate = self;
[self.navigationController pushViewController:readerViewController animated:YES];
[readerViewController release];
(I am using a pdf reader library)
Well, the view controller that is on the top of the stack (presently on screen) will get the viewWillDisappear: and viewDidDisappear: messages.
viewWillDisappear: is a good place to save anything the user may have been editing or manipulating on that screen.
Edit to address your followup:
So when the user taps "back", you'll get these messages (I'm going to call the presenting view controller 'rootViewController')
readerViewController will get viewWillDisappear:
rootViewController will get viewWillAppear:
readerViewController will get viewDidDisappear:
rootViewController will get viewDidAppear:
So if you have access to the ReaderViewController source, you can add/edit methods for those events. You can also set a delegate on the navigation controller, and that delegate will get navigationController:willShowViewController:animated: and navigationController:didShowViewController:animated: as the user comes back.
But if you tell us more about this "ReaderViewController", maybe it has delegate methods you can implement to save whatever state it manipulates. What "pdf reader library" is this? And what state exactly are you trying to save?
i have a button in my app a button that submit score to gamecenter and works.
this is the code:
-(void)subScore{
GKScore *scoreRepoter = [[[GKScore alloc] initWithCategory:#"123456"] autorelease];
scoreRepoter.value=100;
[scoreRepoter reportScoreWithCompletionHandler:^(NSError *error) {
if (error!=nil) {
NSLog(#"errr submitting");
}else
NSLog(#"ok!");
}];
now i'd like to submit score before app is closed with home button.
i thought to customize an action of home button (if it is possible)
or perhaps i make the same line of code in viewDidUload...or something like that...
will i be sure that that action will be performed before unloading the app?
i should make that code in dealloc method?
thanks
You can't customize behaviour of Home button directly, but iOS provides some methods in your application's delegate, by which you can control lifecycle of the application.
Method called right before the application goes to background is applicationWillResignActive: in your application's delegate (usually this method is located in AppDelegate.m file).
I think you can get needed effect by calling your method like that:
- (void)applicationWillResignActive:(UIApplication *)application {
[mygame subScore];
}
Also please note that iOS has time limit of execution for this method: you must do all saving-the-game work in less that five seconds or your application will be killed.