Wait UIAlertView Button - iphone

I have this code in my Application:
if (self.uiSwtichState == TRUE)
{
if ([CLLocationManager locationServicesEnabled])
{
[self.textString stringByAppendingString:[[[SMSLocationModel alloc] init] getLocation]];
}
}
MFMessageComposeViewController *sms = [[MFMessageComposeViewController alloc] init];
sms.messageComposeDelegate = self;
sms.body = self.textString;
sms.recipients = self.arrayOfNumbers;
[self presentModalViewController:sms animated:YES];
this code is into a method called "send".
As you can imagine, the method getLocation get the current user location and, the first time the Application run, a UIAlertView appear on the screen asking the user if he want to allow the application to get his location.
The problem is that when this UIAlertView appear, she is immediately replaced by the sms Vie Controller (MFMessageComposeViewController) and in this way the user doesn't have enough time for answer YES or NO in the UIAlertView.
There is a way for wait that the user press a button in the UIAlertView and THEN present the ModalViewController?
Thanks!

you could use the CLLocationManagers delegate method to wait until the authorization state changes. Save the sms viewController to an instance variable if you are not authorized to use location services. then ask the location manager to authorize you. If the authorization state changes present that view controller.
// somewhere else
self.locationManager.delegate = self;
- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status {
NSLog(#"New Authorization State: %d", status);
if (self.viewControllerToPresentAfterLocationDidChange) {
if (status == kCLAuthorizationStatusAuthorized) {
// set location of viewController
[self presentViewController:self.viewControllerToPresentAfterLocationDidChange animated:YES completion:NULL];
}
else {
// user did not authorize you to use location services
}
self.viewControllerToPresentAfterLocationDidChange = nil;
}
}
- (IBAction)buttonPressed:(id)sender {
UIViewController *vc = [[UIViewController alloc] init];
if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusAuthorized) {
// authorized already, no alert will appear.
// set location of vc
[self presentViewController:vc animated:YES completion:NULL];
}
else if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusNotDetermined){
self.viewControllerToPresentAfterLocationDidChange = vc;
// access location so alert will show
}
else {
// not authorized or restricted.
}
}

Maybe you can use this delegate:
- (void)didPresentAlertView:(UIAlertView *)alertView{
}
For example, initializing a boolean which can prevent of presenting this modal view controller. Then if dismissed change the boolean to allow presenting this view controller.

Yes, you can implement the AlertViewDelegate.
See UIAlertViewDelegate Documentation for further information.
Then you can use the alertView:clickedButtonAtIndex: method and present your MessageComposer when the user has clicked the alert view.

Related

Alert View Click not calling instantly like iOS 6 in iOS 7

In my application while user go to the next view controller I am showing indicator with cancel button. On cancel button click i m setting value -2 for one variable like appDel.Val = -2; And before push to next controller i m checking that if appDel.Val = -2; then return. So no need further process.
this is working fine with iOS6 devices. When user tap on cancel in UIAlertView Delegate method for Alert click calls immediately and value set for appDel.Val=-2. So it will return without any further process.
Bit With iOS7 it creating issue like when user tap on cancel in alert, alertview delegate method is calling after completing current process for push view controller. So appDel.Val=-2 will be set after push controller from alert click method as alert delegate method is not calling immediately same like iOS 6
Can any one please suggest, How can i fix this for iOS 7?
Here is my code.
-(void)goToNextViewController:(NSDictionary*)outputDictionary
{
myViewController *mtvc=[appDel.myDict valueForKey:[outputDictionary valueForKey:#"id"]];
if (mtvc) {
[appDel showindicator:#"Please Wait..."];
}else{
[appDel showindicator:#"Connecting..."];
}
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1]];
self.rootDict = [[NSMutableDictionary alloc] initWithDictionary:outputDictionary];
appDel.activeId = [outputDictionary valueForKey:#"id"];
if(!mtvc)
{
myViewController *mtvc = [[myViewController alloc]initWithNibName:#"myViewController" bundle:nil];
appDel.tempViewController=mtvc;
appDel.tempViewController.isVeryFirst = YES;
[mtvc release];
}
else
{
appDel.tempViewController=mtvc;
appDel.tempViewController.isVeryFirst = NO;
#try {
[self.navigationController pushViewController: mtvc animated: YES];
}
#catch (NSException * e) {
NSLog(#"Exception: %#", e);
}
[appDel performDismiss];
return;
}
if (appDel.Val==-2)
{
[appDel.newConnections removeObjectForKey:appDel.activeId];
appDel.tempViewController.isNewConnection = NO;
appDel.Val = 0;
[appDel performDismiss];
return;
}
[appDel.newConnections setObject:appDel.tempViewController forKey:[outputDictionary valueForKey:#"id"]];
[self.navigationController pushViewController: appDel.tempViewController animated: YES];
[appDel performDismiss];
}
Alert click
- (void)alertView:(UIAlertView *)alert clickedButtonAtIndex:(NSInteger)buttonIndex
{
if(alert.tag==654)
{
self.Val = -2;
[baseAlert dismissWithClickedButtonIndex:0 animated:YES];
baseAlert=nil;
}
}
Thanks for any help.

MBProgressHUD activity indicator doesn't show in viewDidAppear after segue is performed

I have two UITableViewControllers A and B, and this is what I'm trying to do when I click on a table view cell in A:
Prepare to segue from A to B by setting some of B's variables from A.
Perform segue from A to B.
B appears.
Display a "Loading" activity indicator with [MBProgressHUD][1].
In a background task, retrieve data from a URL.
If an error occurs in the URL request (either no data received or non-200 status code), (a) hide activity indicator, then (b) display UIAlertView with an error message
Else, (a) Reload B's tableView with the retrieved data, then (b) Hide activity indicator
However, this is what's happening, and I don't know how to fix it:
After clicking a cell in A, B slides in from the right with an empty plain UITableView. The MBProgressHUD DOES NOT SHOW.
After a while, the tableView reloads with the retrieved data, with the MBProgressHUD appearing very briefly.
The MBProgressHUD immediately disappears.
There doesn't seem to be an error with the way the background task is performed. My problem is, how do I display the MBProgressHUD activity indicator as soon as my B view controller appears? (And actually, how come it's not showing?) Code is below.
A's prepareForSegue
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
B *b = (B *)[segue destinationViewController];
// Set some of B's variables here...
}
Relevant methods in B
- (void)viewDidAppear:(BOOL)animated {
[self startOver];
}
- (void)startOver {
[self displayLoadingAndDisableTableViewInteractions];
[self retrieveListings];
[self.tableView reloadData];
[self hideLoadingAndEnableTableViewInteractions];
}
- (void)displayLoadingAndDisableTableViewInteractions {
MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
hud.labelText = #"Loading";
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
self.tableView.userInteractionEnabled = NO;
}
- (void)hideLoadingAndEnableTableViewInteractions {
[MBProgressHUD hideHUDForView:self.view animated:YES];
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
self.tableView.userInteractionEnabled = YES;
}
- (void)retrieveListings {
__block NSArray *newSearchResults;
// Perform synchronous URL request in another thread.
dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
newSearchResults = [self fetchNewSearchResults];
});
// If nil was returned, there must have been some error--display a UIAlertView.
if (newSearchResults == nil) {
[[[UIAlertView alloc] initWithTitle:#"Oops!" message:#"An unknown error occurred. Try again later?" delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil] show];
} else {
// Add the retrieved data to this UITableView's model. Then,
[self.tableView reloadData];
}
}
- (NSArray *)fetchNewSearchResults {
// Assemble NSMutableArray called newSearchResults from NSURLConnection data.
// Return nil if an error or a non-200 response code occurred.
return newSearchResults;
}
I think you have to call [self hideLoadingAndEnableTableViewInteractions]; after newSearchResults = [self fetchNewSearchResults]; You are retrieving data in another thread which means -startOver will continue executing after calling [self retrieveListings]; and will hide the HUD right away. Also because you are updating the display you have to make sure you are doing that on the main thread. See example
dispatch_async(dispatch_get_main_queue(), ^{
//update UI here
});
When B appears, it displays a plain and empty UITableView, but does not display the MBProgressHUD even if the task does begin in the background (and yet, the MBProgressHUD is called to show before that). Hence, my solution is to show the MBProgressHUD in viewDidLoad, which precedes viewWillAppear.
- (void)viewDidLoad {
// ...
[self displayLoadingAndDisableUI];
}
I set up two additional boolean properties to B--one in .h, called shouldStartOverUponAppearing, and one in a class extension in .m, called isLoadingAndDisabledUI. In startOver, I added the following lines:
- (void)startOver {
if (!self.isLoadingAndDisabledUI) {
[self displayLoadingAndDisabledUI];
}
}
The check is done so that startOver doesn't display another MBProgressHUD when it has already been displayed from viewDidLoad. That is because I have a third view controller, called C, that may call on B's startOver, but doesn't need to call viewDidLoad just to display the MBProgressHUD.
Also, this is how I defined viewDidAppear:
- (void)viewDidAppear:(BOOL)animated {
if (self.shouldStartOverUponAppearing) {
[self startOver];
self.shouldStartOverUponAppearing = NO;
}
}
This way, startOver will only be invoked IF B appeared from A. If B appears by pressing "Back" in C, it will do nothing and only display the old data that was there.
I think that this solution is FAR from elegant, but it works. I guess I'll just ask for a better approach in a separate SO question.
I have used a common method for MBProgressHUD.
#import "MBProgressHUD.h" in AppDelegate.h also following methods.
- (MBProgressHUD *)showGlobalProgressHUDWithTitle:(NSString *)title;
- (void)dismissGlobalHUD;
In AppDelegate.m add following methods.
- (MBProgressHUD *)showGlobalProgressHUDWithTitle:(NSString *)title {
[MBProgressHUD hideAllHUDsForView:self.window animated:YES];
MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.window animated:YES];
hud.labelText = title;
return hud;
}
- (void)dismissGlobalHUD {
[MBProgressHUD hideHUDForView:self.window animated:YES];
}
How to use?
AppDelegate *appDel = (AppDelegate *)[[UIApplication sharedApplication]delegate];
//Show Indicator
[appDel showGlobalProgressHUDWithTitle:#"Loading..."];
//Hide Indicator
[appDel dismissGlobalHUD];
Hope this helps.

EKEditviewController keeps showing the title in the navigationbar

I'm working with the EventKit Framework. It is working almost perfect but I have still some issues. When I push my on an Event, it goes to the details of that Event. It shows correctly the details and I can also edit and save it. The problem is with the navigation bar.
It shows the titles inside the navigation bar.These titles are Event Details and Edit. Also it is not showing a backbutton, to go back to my calendar. What I also should mention is that I'm using the Kal Calendar framework.
I'm pushing to de detailsViewController like this.
Appointment *appointment = [dataSource appointmentAtIndexPath:indexPath];
// Upon selecting an event, create an EKEventViewController to display the event.
self.detailViewController = [[EKEventViewController alloc] initWithNibName:nil bundle:nil];
self.detailViewController.title = #"";
detailViewController.event = appointment.event;
// Allow event editing.
detailViewController.allowsEditing = YES;
[calendar.navigationController pushViewController:detailViewController animated:YES];
And this is how my delegate looks like
// Overriding EKEventEditViewDelegate method to update event store according to user actions.
- (void)eventEditViewController:(EKEventEditViewController *)controller
didCompleteWithAction:(EKEventEditViewAction)action {
NSError *error = nil;
EKEvent *thisEvent = controller.event;
controller.title = #"";
switch (action) {
case EKEventEditViewActionCanceled:
// Edit action canceled, do nothing.
break;
case EKEventEditViewActionSaved:
// When user hit "Done" button, save the newly created event to the event store,
// and reload table view.
// If the new event is being added to the default calendar, then update its
// eventsList.
if (self.defaultCalendar == thisEvent.calendar) {
[self.eventsList addObject:thisEvent];
}
[controller.eventStore saveEvent:controller.event span:EKSpanThisEvent error:&error];
//[calendar reloadData];
break;
case EKEventEditViewActionDeleted:
// When deleting an event, remove the event from the event store,
// and reload table view.
// If deleting an event from the currenly default calendar, then update its
// eventsList.
if (self.defaultCalendar == thisEvent.calendar) {
[self.eventsList removeObject:thisEvent];
}
[controller.eventStore removeEvent:thisEvent span:EKSpanThisEvent error:&error];
//[calendar reloadData];
break;
default:
break;
}
// Dismiss the modal view controller
[controller dismissModalViewControllerAnimated:YES];
}
// Set the calendar edited by EKEventEditViewController to our chosen calendar - the default calendar.
- (EKCalendar *)eventEditViewControllerDefaultCalendarForNewEvents:(EKEventEditViewController *)controller {
EKCalendar *calendarForEdit = self.defaultCalendar;
return calendarForEdit;
}
I came up with this solution:
EKEventEditViewController * controller = [[EKEventEditViewController alloc] init];
controller.eventStore = self.eventStore;
controller.event = result;
controller.title = #"";
controller.navigationItem.title = #"";
controller.navigationItem.titleView = [UIView new];
NSArray * array =controller.navigationBar.items;
UINavigationItem * titleItem = array.firstObject;
titleItem.title = #"";
controller.editViewDelegate = (id)self;
[self presentViewController:controller animated:YES completion:NULL];
The EKEventEditViewController is not embedded in a navigation controller, it has its own UINavigationBar, I keep the navigation item if Apple will change this in the future and embed it in a navigation controller.
i think you have added navigation item on the storyboard or nib file. remove it.
make self.title=nil; or self.title=#"";

SMS option not working properly

I am using xcode 4.2 and i am developing an iphone APP , part of this app is sending SMSs
here is the code that I typed:
-(IBAction)SMSbutton{
MFMessageComposeViewController *sms = [[MFMessageComposeViewController alloc] init];
if ([MFMessageComposeViewController canSendText]) {
sms.body= [NSString stringWithFormat: #"text"];
sms.messageComposeDelegate = self;
[self presentModalViewController:sms animated:YES];
}
I can open the SMS application and send SMS but the problem is whether I click on the "cancel" or the "send" button the message application does not go away . how to do that ?
thanks
Set your calling class to be a delegate of the message composer, then catch the cancel and send events to dismiss the modal view controller as needed.
Set your header file to adhere to the MFMessageComposeViewControllerDelegate, and when you initialize the composer, set the message delegate to self:
MFMessageComposeViewController *george = [MFMessageComposeViewController alloc] init];
george.messageComposeDelegate = self;
Then implement the delegate method...easiest way is:
- (void)messageComposeViewController:(MFMessageComposeViewController *)controller didFinishWithResult:(MessageComposeResult)result
{
[self dismissModalViewControllerAnimated:YES];
}
...but you can catch and deal with errors and events as necessary.
Implement messageComposeViewController:didFinishWithResult: in your delegate"
-(void)messageComposeViewController:(MFMessageComposeViewController *)controller didFinishWithResult:(MessageComposeResult)result {
if(result == MessageComposeResultCancelled) {
//Message cancelled
} else if(result == MessageComposeResultSent) {
//Message sent
}
[self dismissModalViewControllerAnimated:YES];
}
Have you tried dismissViewControllerAnimated:completion: or dismissModalViewControllerAnimated:?
[self dismissModalViewControllerAnimated: YES];

Cancel and done button does not work in new contact view

I am trying to integrate new contact control in my app. Here is my code:
- (BOOL) personViewController:(ABPersonViewController*)personView shouldPerformDefaultActionForPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifierForValue
{
return YES;
}
-(IBAction)addcontact:(id)sender{
ABNewPersonViewController *picker = [[ABNewPersonViewController alloc] init];
UINavigationController *navigation = [[UINavigationController alloc] initWithRootViewController:picker];
[self presentModalViewController:navigation animated:YES];
[picker release];
[navigation release];
}
It pops up new contact view but when I click Cancel or Done button nothing happens.
Can anyone help me?
Thanks in advance!
//Make sure your VC is an <ABNewPersonViewControllerDelegate>
-(void) newPersonViewController:(ABNewPersonViewController *)newPersonView
didCompleteWithNewPerson:(ABRecordRef)person {
if (person != nil) //nil = Cancel button clicked
{
//do something
}
//iOS6
[self dismissViewControllerAnimated:YES completion:nil];
}
You need to add methods that should be called when the cancel or done button is tapped and that method should call [self.navigationController dismissModalViewController