I have a selector to show UIAlertView asking user if want to retry upload images after NotificationCenter post a notification with observename.
[[NSNotificationCenter defaultCenter] postNotificationName:kNOTIFICATION_PHOTOS_UPLOAD_RETRY object:nil];
But because of the notification received more than one, so will show as many as notifications received. Is there a best practice to show alert view only once?
Yeah, you can do something like:
#interface MyClass
{
UIAlertView *_myAlertView;
}
#end
#implementation MyClass
...
- (void)myNotificationSelector:(NSNotification *)notification
{
if (!_myAlertView) {
_myAlertView = [[UIAlertView alloc] init ...]
_myAlertView.delegate = self;
[_myAlertView show];
}
}
...
#end
and in the UIAlertViewDelegate handlers, just release and set _myAlertView to NO.
Related
Alright, so I've been toying around with this for a couple days now and I haven't gotten this to work, looking to you for help!
Basically I want to "Unlock" a feature once an IAP is done. I've got the IAP code to work, but I want to change the button "sendMail" ('disabled' in Interface Builder) so that the user can interact with it.
//InputViewController.h
#import "IAPStore.h"
#interface InputViewController : UIViewController <MFMailComposeViewControllerDelegate, UIAlertViewDelegate>
#property(strong,nonatomic)IBOutlet UIButton *sendMail;
-(void)enableMail;
....
#end
//InputViewController.m
#import "InputViewController.h"
#import "IAPStore.h"
-(void)enableMail
{
[_sendMail setEnabled:YES];
NSLog(#"Unlocking Button");
}
//IAPStore.h
#import "InputViewController.h"
#interface IAPHelper : NSObject <UIAlertViewDelegate>
-(void)purchaseComplete;
...
#end
//IAPStore.m
#import "InputViewController.h"
-(void)purchaseComplete
{
UIAlertView *purchased = [[UIAlertView alloc]initWithTitle:#"In-App Purchase" message:#"Purchase complete! Thank you!" delegate:nil
cancelButtonTitle:#"OK" otherButtonTitles:nil];
GROWInputViewController *viewController = [[GROWInputViewController alloc] init];
[viewController enableMail];
[purchased show];
NSLog(#"button enabled");
}
So it prints out too the log but nothing is changed on the other view controller, but nothing is changed, any idea to what I'm doing wrong?
You could use NSNotificationCenter
In the viewDidLoad: method of InputViewController.m add this line of code:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(enableMail) name:#"purchaseCompleteNotification" object:nil];
And in the purchaseComplete method of IAPStore.m, replace this:
GROWInputViewController *viewController = [[GROWInputViewController alloc] init];
[viewController enableMail];
with this:
[[NSNotificationCenter defaultCenter] postNotificationName:#"purchaseCompleteNotification" object:nil];
This will cause a notification to be posted when the purchase is complete. Meanwhile, InputViewController has an 'observer' that is set to call your 'enableMail' method when that notification is posted.
Also, you'll want to add this method to your InputViewController.m, so that he is removed as an observer when deallocated.
-(void)dealloc{
[[NSNotificationCenter defaultCenter] removeObserver:self name:#"purchaseCompleteNotification" object:nil];
}
I would like to refresh a UIWebView whenever my app comes to the foreground. All I really have in my ViewController.m is a method that checks for internet access (hasInternet) and viewDidLoad.
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize webview;
-(BOOL)hasInternet{
Reachability *reach = [Reachability reachabilityWithHostName:#"www.google.com"];
NetworkStatus internetStats = [reach currentReachabilityStatus];
if (internetStats == NotReachable) {
UIAlertView *alertOne = [[UIAlertView alloc] initWithTitle:#"You're not connected to the internet." message:#"Please connect to the internet and restart the app." delegate:self cancelButtonTitle:#"Dismiss" otherButtonTitles:nil];
[alertOne show];
}
return YES;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self hasInternet];
[webView loadRequest: [NSURLRequest requestWithURL:[NSURL URLWithString:#"http://warm-chamber-7399.herokuapp.com/"]] ];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
Any advice on how to enable this functionality? Does it go in AppDelegate or do I create another method within ViewController.m?
You should register a UIApplicationWillEnterForegroundNotification in your ViewController's viewDidLoad method and whenever app comes back from background you can do whatever you want to do in the method registered for notification. ViewController's viewWillAppear or viewDidAppear won't be called when app comes back from background to foreground.
-(void)viewDidLoad{
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(doYourStuff)
name:UIApplicationWillEnterForegroundNotification object:nil];
}
-(void)doYourStuff{
[webview reload];
}
Don't forget to unregister the notification you are registered for.
-(void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
Note if you register your viewController for UIApplicationDidBecomeActiveNotification then your method would be called everytime your app becomes active, It would not be appropriate to register for this notification.
Register for the UIApplicationDidBecomeActiveNotification or the UIApplicationWillEnterForegroundNotification.
I like to show the latest Push Notification in a label in my main StoryBoard I use this code to display the alert message in my AppDelegate.m:
-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
NSDictionary *test =(NSDictionary *)[userInfo objectForKey:#"aps"];
NSString *alertString =(NSString *) [test objectForKey:#"alert"];
NSLog(#"String recieved: %#",alertString);
UIApplicationState state = [[UIApplication sharedApplication] applicationState];
if (state == UIApplicationStateActive) {
UIAlertView *alertmessage=[[UIAlertView alloc]initWithTitle:#"Geier"
message:alertString delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alertmessage show];
AudioServicesPlaySystemSound(1002);
}
}
i tried this in my ViewController.m file latestpush.text = #"%#",alertString; but it doesn't work.
Can someone help me?
Thanks:)
You need to make the text available to the view controller.
You could do this by sending a custom NSNotification with the alert message, from inside application:didReceiveRemoteNotification:
[[NSNotificationCenter defaultCenter]
postNotificationName:#"PushAlertNotification"
object:self
userInfo:#{#"alertString":alertString}];
In your view controller's viewDidLoad method, register as an observer:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(updateStoryboard:)
name:#"PushAlertNotification"
object:nil];
and create the updateStoryboard: method in the view controller:
- (void) updateStoryboard:(NSNotification *) notification {
self.latestpush.text = notification.userInfo[#"alertString"];
}
An alternative solution is to create a property in your AppDelegate that takes in the ViewController as an observer.
AppDelegate.h (change ViewController to the actual type of your VC).
#property (nonatomic, weak) ViewController *observer;
Inside the ViewController create a method that accepts the NSString and have that method update your Storyboard.
ViewController.m
-(void)updateStoryboard(NSString *alertString) {
self.latestpush.text = alertString;
}
Also, in your ViewContoller's viewDidLoad method, register yourself with the appDelegate:
- (void)viewDidLoad {
[super viewDidLoad];
AppDelegate *delegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
delegate.observer = self;
}
Call updateStoryboard inside your application:didReceiveRemoteNotification: method:
[self.observer updateStoryboard:alertString];
why do I get "wait_fences: failed to receive reply" for this code? Is it the way I'm using notification to communicate back to the main thread?
#import "ViewController.h"
#implementation ViewController
#synthesize alert;
#pragma mark - Background Thread Test Methods
- (void) ConfigTasksForBackground:(id)sender{
NSLog(#"ConfigTasksForBackground - Starting");
[NSThread sleepForTimeInterval:6];
[[NSNotificationCenter defaultCenter] postNotificationName:#"ModelChanged" object:self];
NSLog(#"ConfigTasksForBackground - Ending");
}
#pragma mark - Callbacks
- (void) ModelChangedHandler:(NSNotification *) notification {
if ([[notification name] isEqualToString:#"ModelChanged"]) {
NSLog(#"ModelChangedHandler");
[self.alert dismissWithClickedButtonIndex:0 animated:false];
}
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(ModelChangedHandler:)
name:#"ModelChanged"
object:nil];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
self.alert = [[[UIAlertView alloc] initWithTitle:#"Title"
message:#"viewDidAppear"
delegate:nil
cancelButtonTitle:nil
otherButtonTitles:nil] autorelease];
[alert show];
[self performSelectorInBackground:#selector(ConfigTasksForBackground:) withObject:nil];
}
#end
Output is:
2011-11-07 15:15:42.730 test_background[6876:13603] ConfigTasksForBackground - Starting
2011-11-07 15:15:48.734 test_background[6876:13603] ModelChangedHandler
2011-11-07 15:15:49.236 test_background[6876:13603] ConfigTasksForBackground - Ending
wait_fences: failed to receive reply: 10004003
There is an obvious problem here. You are posting the notification from the background thread (which is fine) which means the notification handler ModelChangedHandler is being called on the background thread. The handler is then dismissing an alert view which must be done on the main thread. Try changing your code to:
- (void) ModelChangedHandler:(NSNotification *) notification {
if (![NSThread isMainThread]) {
[self performSelectorOnMainThread:#selector(ModelChangedHandler:) withObject:notification waitUntilDone:NO];
}
else if ([[notification name] isEqualToString:#"ModelChanged"]) {
NSLog(#"ModelChangedHandler");
[self.alert dismissWithClickedButtonIndex:0 animated:false];
}
}
EDIT: was typing too fast, changed answer to reflect the correct UI objects.
Here's how to get rid of the wait_fences error. Change the line where you dismiss the alertView to use animation as follows:
[self.alert dismissWithClickedButtonIndex:0 animated:YES];
I think wait_fences has something to do with view animation states with alert views but it's hard to know for sure. I do think this should eliminate the error msg though. My other answer doesn't directly get rid of the error but I still recommend it. UI actions should be done on the main thread.
Hi there I currently I have a warning on a line of code where I am trying to push a new view onto the screen.
Outline // my NSObject receives a code=1 from my server I have set up. Everything works fine the code comes through which then initializes an AlertView where I have set up an if statement to catch the button click of my AlertView message. When that button is pressed my application falls over.
I have declared my ViewController of the view I am trying to push in its header file and there are no errors just the warning when compiled.
this is my NSObject I have made
/////.h
#import <Foundation/Foundation.h>
#interface alerts : NSObject {
}
- (void)pleaseRegisterDevice;
#end
/////.m
#import "alerts.h"
#import "instaCode1_3AppDelegate.h"
#import "RegisterDeviceViewController.h"
#implementation alerts
//use this alert when phone falls out of sync
- (void)pleaseRegisterDevice {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Please Register Device"
message:#"click OK to register"
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert autorelease];
[alert show];
}
//Catch pleaseRegisterDevice method
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex {
NSString *buttonTitle=[alertView buttonTitleAtIndex:buttonIndex];
if ([buttonTitle isEqualToString:#"OK"]) {
NSLog(#"msg from alertView method");
//open new wndow
RegisterDeviceViewController *regViewController = [[RegisterDeviceViewController alloc] init];
//Push it onto the top pf the navigation controller's stack
**[[self navigationController] pushViewController:regViewController animated:YES];**
}
else {
NSLog(#"was not able to push view");
}
}
- (void)dealloc {
[super dealloc];
}
#end
I have bolded the line of code where I get the warning 'alerts' may not respond to -navigationController
any help would be greatly appreciated.
I dont think an NSObject subclass has a UINavigationController...
You need to get a pointer to your app delegate's navigation controller like so
MyAppDelegate *appDelegate = (MyAppDelegate *)[[UIApplication sharedApplication] delegate];
[appDelegate.navigationController pushViewController:regViewController animated:YES];
navigationController is a property defined on a UIViewController. A NSObject does not have this method.
You don't have any instance member or method called navigationController, hence the warning.