I have two UIAlertViews in same view controller and I want to use the delegate method
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger) buttonIndex
This method will get called when a button in an alert view is pressed. However both alert views will call the same method.
How can I different the two alert views?
Set the tag property to different values when you display the alert. It's just an integer and can be queried in the callback/delegate method.
Here's an example (using an ActionSheet rather than an AlertView, but the principle is exactly the same):
UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:#"Title"
delegate:self
cancelButtonTitle:#"Cancel"
destructiveButtonTitle:nil
otherButtonTitles:#"Some option", nil];
actionSheet.actionSheetStyle = UIActionSheetStyleDefault;
actionSheet.tag = 10;
[actionSheet showInView:self.view];
[actionSheet release];
Then in your selector:
-(void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
switch (actionSheet.tag) {
case 10:
// do stuff
break;
case 20:
// do other stuff
break;
}
}
Of course, you'd use constants rather than literal values, localised strings, etc, but that's the basic idea.
Related
I have several view controllers that need to make Parse services calls, which is therefore handled in a class for every "Parse" related work.
Now I have a case where the parse response will (if no errors comes up obviously) instantiate the MFMessageComposeViewController with certain parameters.
The text body comes from parse, the recipients comes from the class.
My problem is : I have copy/pasted code that I can't get rid off because I don't know what to do
In my controller class, I do this :
- (void)showSMS:(NSString*)reciever { //This is the phone number
if(![MFMessageComposeViewController canSendText]) {
UIAlertView *warningAlert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(#"ALERT_ERROR_Title", nil) message:NSLocalizedString(#"ALERT_ERROR_NOSMS", nil) delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles:nil];
[warningAlert show];
return;
}
[[ParseService sharedInstance]sendSMSOfType:SMS_TYPE_INSIST toRecipient:reciever andBlock:^(NSError *error, NSString *body) {
if (!error){
MFMessageComposeViewController *messageController = [[MFMessageComposeViewController alloc] init];
messageController.messageComposeDelegate = self;
NSArray *recipents = [[NSArray alloc]initWithObjects:reciever, nil];
[messageController setRecipients:recipents];
[messageController setBody:body];
[self presentViewController:messageController animated:YES completion:nil];
}else{
UIAlertView *warningAlert = [[UIAlertView alloc] initWithTitle:#"Error getting sms" message:#"Couldn't get the text online" delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles:nil];
[warningAlert show];
return;
}
}];
}
and I have this exact same block of code in 3 different places, except for ONE difference, the SMS_TYPE parameter.
How should I tweak this so I don't have to create and assign the parameters in every controller, have one neat line that would look like this [??? setUpMessageControllerWithParam:recipients:body];
Pretty much the whole completion block here troubles me, but I can't really put it somewhere else because I'll have trouble presenting a view on self if self isn't a VC, same goes for delegates and alerts.
This is probably simple for most of you, I'm just OOP-retarded. Any help is much appreciated :)
There are several ways to do the this ... like creating a base view controller with this method passing the custom parameters and inheriting your other view controllers from it, or you can make a Category with this method and import this category and use wherever you need ...
In my iOS 7 app, I need to verify the user wants to deleta a selected record from Cord Data. I have the UIAlertViewDelegate defined in the .h file. This is the code to display the alert:
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Warning"
message:#"Are you sure you want to delete this record?"
delegate:self
cancelButtonTitle:#"Cancel"
otherButtonTitles:#"Delete", nil];
[alert show];
if(alertButtonTapped == 0)
return;
// remainder of code to delete record follows (was omitted)
This is the code to check which button was tapped:
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
alertButtonTapped = [NSNumber numberWithInteger:buttonIndex];
return;
}
The problem is the alert is displayed and then immediately falls through the remainder of the code in that method. I have never seen this before; usually it blocks until the user has responded by tapping one of the buttons (at least I thought it did). What do I need to do to make this alert block until the user responds? (I was looking at UIAlertView blocks, but not sure that would do the job since it appears to use a different thread)
This is how UIAlertView works -- it doesn't block, thus why it has the UIAlertViewDelegate methods for actually implementing a response.
If the "remainder of code" is what should happen after they tap a button (e.g. the "Delete" button), then move all of that code into the delegate method, like:
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
if (buttonIndex != alertView.cancelButtonIndex) {
// code to delete record
}
}
EDIT - adding example to answer a comment
So if you have multiple UIAlertViews in the same class, you could differentiate between them using the tag attribute of UIView (UIAlertView is-a UIView). So it could be something like this:
const NSInteger kDeleteAlertTag = 100; // declared at the top of your .m file, perhaps.
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Warning"
message:#"Are you sure you want to delete this record?"
delegate:self
cancelButtonTitle:#"Cancel"
otherButtonTitles:#"Delete", nil];
alert.tag = kDeleteAlertTag;
[alert show];
Then your delegate response might look like this:
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
if (alertView.tag == kDeleteAlertTag) {
if (buttonIndex != alertView.cancelButtonIndex) {
// code to delete record
}
}
else if (alertView.tag = kDoSomethingElseAlertTag) {
DoSomethingElse();
}
}
I have an action sheet which works like this:
- (void)Method1 {
UIActionSheet *photoSourceSheet=[[UIActionSheet alloc]
initWithTitle:#"Options"
delegate:self
cancelButtonTitle:#"Exit"
destructiveButtonTitle:nil
otherButtonTitles:#"opt1",#"opt2", #"opt3", nil];
photoSourceSheet.tag=1;
photoSourceSheet.delegate=self;
[photoSourceSheet showInView:self.view];
}
- (void)Method2 {
UIActionSheet *photoSourceSheet1=[[UIActionSheet alloc]
initWithTitle:#"Select Video"
delegate:self
cancelButtonTitle:#"Cancel"
destructiveButtonTitle:nil
otherButtonTitles:#"Take New Video", #"Choose Existing Video", nil];
// photoSourceSheet.delegate=self;
photoSourceSheet1.tag=2;
photoSourceSheet1.delegate=self;
[photoSourceSheet1 showInView:self.view];
}
then in my delegate i have:
- (void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex: NSInteger)buttonIndex {
if (actionSheet.tag==1) {
if (buttonindex==2) {
[self method2];
}
} else if (actionSheet.tag==2) {
// some code
}
}
My delegate method gets called for the first action sheet i.e. photoSourceSheet but not for photoSourceSheet1.
Is there something special I need to do, like manually dismissing the sheet?
My second UIActionSheet (photoSourceSheet1) appears but it crashes the app as soon as I select an option on the sheet.
It throws EXEC_BAD_ACCESS
There is nothing wrong with the above code.
EXEC_BAD_ACCESS is basically due to ill Memory Management.Sometimes you unintentionally remove the object that is being used.
Try enable Zombies it will tell you the exact problem area.
Steps: Go to Edit Scheme
Memory Management
Check the option enable Zombie Objects
I have code setting up a UIAlertView:
-(IBAction)showMessage
{
//NSInteger *buttonIndex = NULL;
UIAlertView *message = [[UIAlertView alloc] initWithTitle:nil
message:nil
delegate:nil
cancelButtonTitle:#"Cancel"
otherButtonTitles:#"Email",#"SMS",#"Facebook",#"Twitter", nil];
[message show];
}
and code explaining what to do once the user makes a choice:
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (buttonIndex == 1){
[self openMail];
}
else if (buttonIndex == 2)
//etc.
}
But what I can't figure out is how to connect the two. The obvious answer is to add a line to the first piece of code calling alertView: clickedButtonAtIndex on UIAlertView *message, but how do you assign buttonIndex? How do you tell alertView whether the user has chosen Facebook, Email, etc?
Add to the header file if you haven't already:
#interface YourClass : UIViewController <UIAlertViewDelegate>
{
}
...etc
and in your AlertView code change delegate:nil to delegate:self
For more information have a look at the Apple Docs:
http://developer.apple.com/library/ios/#DOCUMENTATION/UIKit/Reference/UIAlertViewDelegate_Protocol/UIAlertViewDelegate/UIAlertViewDelegate.html
From the docs:
The button indices start at 0. If this is the cancel button index, the alert view is canceling. If -1, the cancel button index is not set.
(1) You want to set delegate:self when you initialize the message. Also, in your interface declaration, do something like:
#interface myClass: UIViewController <UIAlertViewDelegate>
This way, your handler function automatically gets called when the user makes a selection.
(2) Buttons are indexed in the order you listed them.
(3) Since you have a lot of options for the user to choose from, it is better to use UIActionSheet instead of UIAlertView. Alerts are generally used for simple Yes/No-type selections.
Hope this helps!
Using Xcode I have View A that navigates to View B.
Upon pressing the Back UIBarButtonItem, I'm trying present the user with a UIActionSheet to confirm navigation to move back to View A.
What do I need to do in code to stop the view from navigating back and then (depending on user input) move back or stay on the current screen?
add a backbutton programmatically.
eg.
UIButton *backBtn= [[UIButton alloc] initWithFrame:CGRectMake(0,0,54,30)];
[backBtn addTarget:self action:#selector(backButtonPressed:)forControlEvents:UIControlEventTouchUpInside];
UIBarButtonItem *backBarButton = [[UIBarButtonItem alloc] initWithCustomView:backBtn];
[backBtn release];
[[self navigationItem] setLeftBarButtonItem:backBarButton];
[backBarButton release];
//backButtonPressed is the selector for backBtn
Then present you ActionSheet from that selector and based on user either navigate to previous viewController or dont.
To navigate to previous page, use popViewMethod.
`
You should not present UIActionSheet for every other action.It would be better to use UIAlertView for this purpose. According to Apple UIActionsheet Guidelines :-
Provide alternate ways a task can be completed. An action sheet allows you to provide a range of choices that make sense in the context of the current task, without giving these choices a permanent place in the user interface.
Get confirmation before completing a potentially dangerous task. An action sheet prompts users to think about the potentially dangerous effects of the step they’re about to take and gives them some alternatives. This type of communication is particularly important on iOS-based devices because sometimes users tap controls without meaning to.
for UIAlertView :-
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Alert View"
message:#"Do You want to go back to previous screen?"
delegate:self
cancelButtonTitle:#"NO"
otherButtonTitles:#"YES",nil];
[alertView show];
[alertView release];
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (buttonIndex == 0) {
NSLog(#"THE 'NO' BUTTON WAS PRESSED");
}
if (buttonIndex == 1) {
NSLog(#"THE 'YES' BUTTON WAS PRESSED");
}
}
Implement this on action of back button of UINavigationController.According to the buttons pressed "YES" or "NO" , you can allow navigation.Also conform to UIAlerrtVIewDelegate protocol.