UIAlerController Action Sheet does not respond the second time it's called - ios

I have something like the following code. The Action sheet runs doSomething OK when it appears for the first time (in a button IBAction), but when it appears the second time, nothing happens the Action sheet just disappear without calling do something. Any idea?
#implementation ...
- (void) setActions {
UIAlertAction *opt1 = [UIAlertAction actionWithTitle:#"Option 1" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
[self doSomething:#"opt1"];}];
UIAlertAction *opt2 = [UIAlertAction actionWithTitle:#"Option 2" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
[self doSomething:#"opt2"];}];
UIAlertAction *opt3 = ...
self.opt1 = opt1;
self.opt2 = opt2;
self.opt3 = opt3;
- (void) showActionSheet {
...
UIAlertController *selectAS = [UIAlertController alertControllerWithTitle:#"Select Options"
message:#"msg" preferredStyle:UIAlertControllerStyleActionSheet];
if (xyz) {
[selectAS addAction:self.opt1];
[selectAS addAction:self.opt2];
}
else{
[selectAS addAction:self.opt1];
[selectAS addAction:self.opt3];
}
[self presentViewController:selectqAS
animated:YES completion:nil];
}
- (void) doSomething: (NSString *) opt{
....
}

Glad we got you up and running. My guess is your methods are getting lost in translation. You have methods intertwining each other which can be causing the confusion, specifically with self.opt1. per my comment, now that iOS8 has introduced UIAlertController, it comes with completion handlers, you should plan accordingly to that: something like the following :
-(IBAction)showActionSheet {
UIAlertController *selectAS = [UIAlertController alertControllerWithTitle:#"Select Options" message:#"msg" preferredStyle:UIAlertControllerStyleActionSheet];
UIAlertAction *opt1 = [UIAlertAction actionWithTitle:#"Option 1" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
//Don't have to call another method, just put your action 1 code here. This is the power of completion handlers creating a more structured outline
}];
UIAlertAction *opt2 = [UIAlertAction actionWithTitle:#"Option 2" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
//Don't have to call another method, just put your action 2 code here. This is the power of completion handlers creating a more structured outline
}];
UIAlertAction *opt3 = ...
if (xyz) {
[selectAs addAction:opt1];
[selectAs addAction:opt2];
} else {
[selectAs addAction:opt1];
[selectAs addAction:opt3];
}
[self presentViewController:selectAs animated:YES completion:nil];
}
Much more cleaner and actually uses the UIAlertController for it's intended purposes, no other method calls needed.

Related

Show dialog to rotate iOS app upside down

I am developing an app which has to be upside down.
I would like to show a dialog to the user, which he can accept (which shall result in a auto rotation) or decline.
How to display such a dialog using objective-c?
I need to check the portrait modes both in the info.plist as well as programatically in the supportedInterfaceOrientations. Right?
Thank you very much in advance for helping!
Use UIAlertController for this.
UIAlertController * alert=[UIAlertController
alertControllerWithTitle:#"Title" message:#"Message"preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* yesButton = [UIAlertAction
actionWithTitle:#"Yes, please"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action)
{
**//What we write here????????**
NSLog(#"you pressed Yes, please button");
// call method whatever u need
}];
UIAlertAction* noButton = [UIAlertAction
actionWithTitle:#"No, thanks"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action)
{
**//What we write here????????**
NSLog(#"you pressed No, thanks button");
// call method whatever u need
}];
[alert addAction:yesButton];
[alert addAction:noButton];
[self presentViewController:alert animated:YES completion:nil];`

UIAlertAction - Edit UIAlertAction after it was set

I have a class named ManagerClass.
Manager Class has a function showUIAlertController:
- (UIAlertController*)showUIAlertController:(NSString *)title message:(NSString *)message actions:(NSArray<UIAlertAction*>* )actions
This function should show alert controller with the parameters received.
So far so good...
Now i would like to take these actions and edit them somehow. Something like:
UIAlertAction *action = actions.firstObject;
UIAlertAction *actionCopyWithAdditionalAction = [UIAlertAction actionWithTitle:action.title style:action.style handler:^(UIAlertAction * _Nonnull action) {
[action "performTheAction"]; //perform the original action
[ManagerClass doSomething];
}];
"performTheAction" does not exist - it is just for you to understand what i am trying to achieve.
Does anyone has an idea how this task can be achieved ?
Did not find a way to do that while looking at Apple's UIAlertAction API
https://developer.apple.com/reference/uikit/uialertaction
Do you mean to perform a method provided by your code. Then use:
[self performSelector:#selector(aMethod:)];
or when sending an object with:
[self performSelector:#selector(aMethod:)
withObject:(id)object];
Note, the self here is referencing to the same class, it could be somewhere else as well.
Edit *
UIAlertController* alert = [UIAlertController alertControllerWithTitle:#"My Alert"
message:#"This is an alert."
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:#"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) {
NSLog(#"42.");
}];
[alert addAction:defaultAction];
[self presentViewController:alert animated:YES completion:nil];
The console logs out 42. Put instead every action do you need.
Why you want to call a second alert which only displays the first alert and execute some of your code? You can do that in the first alert, too.
//Create the UIAlertController
UIAlertController *theAlertController = [UIAlertController alertControllerWithTitle:#"Your Title" message:#"Your Message" preferredStyle:UIAlertControllerStyleAlert];
//Add an UIAlertAction which the user can click at
[theAlertController addAction:[UIAlertAction actionWithTitle:#"Ok" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
//Execute your own code
//[self myOwnCode];
//Close the AlertController after your code
[self dismissViewControllerAnimated:YES completion:nil];
}]];
dispatch_async(dispatch_get_main_queue(), ^{
[self presentViewController:theAlertController animated:YES completion:nil];
});
Hope i understand you right.
You could pass a alert action model instead of a UIAlertAction.
so your method would look something like this:
- (UIAlertController*)showUIAlertController:(NSString *)title message:(NSString *)message actions:(NSArray<MyActionModel*>* )actions
where MyActionModel is a class with 3 properties
#interface MyActionModel: NSObject {
#property NSString * title;
#property UIAlertActionStyle * style;
#property ((void)^(UIAlertAction *)) action;
}
Then you can create your UIAlertActions when you need them and also add in your manager callbacks.
P.S. Sorry if my Objective-C is not quite right, I'm a bit rusty.

Action Sheet picker on Button IOS

HeyI want to do that This my button and in button there is textfield I want to do that when I pressed on button the action sheet picker become appear and give 4 to 5 list of string whatever I select it will apear on textfield which is in button. please help me
Start by adding a target for your button. In Objective-C, that would be like this:
[myButton addTarget:self
action:#selector(buttonPressed:)
forControlEvents:UIControlEventTouchUpInside];
Then create the method buttonPressed. An example of that would be:
- (void)buttonPressed:(id)sender {
if ([sender isEqual:self.myButton]) {
//This is where you can create the UIAlertController
}
}
Then, to create the UIAlertController:
UIAlertController *myAlertController = [UIAlertController alertControllerWithTitle:#"Title"
message:#"Message"
preferredStyle:UIAlertControllerStyleActionSheet];
Then you create actions for what each button you want to have appear on the action sheet. You need to have a title for the button and an action for them, though the action block can be empty.
UIAlertAction *action1 = [UIAlertAction actionWithTitle:#"Action 1"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction *action) {
//Whatever you want to have happen when the button is pressed
}];
[myAlertController addAction:action1];
//repeat for all subsequent actions...
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:NSLocalizedString(#"Cancel", nil)
style:UIAlertActionStyleCancel
handler:^(UIAlertAction *action) {
// It's good practice to give the user an option to do nothing, but not necessary
}];
[myAlertController addAction:cancelAction];
Lastly, you present the UIAlertController:
[self presentViewController:myAlertController
animated:YES
completion:^{
}];
NOTE:
If you're building for iPad and using an Action Sheet style for the UIAlertController, then you will need to set a source for the UIAlertController to present from. This can be done like this:
if ([sender isKindOfClass:[UIView class]]) {
if ([myAlertController.popoverPresentationController respondsToSelector:#selector(setSourceView:)]) { // Check for availability of this method
myAlertController.popoverPresentationController.sourceView = self.myButton;
} else {
myAlertController.popoverPresentationController.sourceRect = self.myButton.frame;
}
}

UIAlertController is nil when handler block executes

Here's the problem up front: I have a UIAlertController that has a textfield. I want to save the content of that textfield as an NSString when the user touches a "Confirm" button in the alert. When the Confirm action block is executed, however, the alert is nil (presumably already dismissed and deallocated at that point), and thus so is its textfield, meaning I cannot save the textfield's text.
I am using a series of UIAlertControllers to allow a user to create a passcode for my app, such that any time the app comes to the foreground, the user is prompted for the code before the app can be used.
I created a category of UIAlertController with several convenience methods that return preconfigured alerts that I need to use. Here's one of them:
+ (UIAlertController*)passcodeCreationAlertWithConfirmBehavior:(void(^)())confirmBlock andCancelBehavior:(void(^)())cancelBlock {
UIAlertController *passcodeCreationAlert = [UIAlertController alertControllerWithTitle:#"Enter a passcode"
message:nil
preferredStyle:UIAlertControllerStyleAlert];
[passcodeCreationAlert addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
textField.keyboardType = UIKeyboardTypeNumberPad;
}];
UIAlertAction* cancelAction = [UIAlertAction actionWithTitle:#"Cancel"
style:UIAlertActionStyleCancel
handler:^(UIAlertAction * action) {
if (cancelBlock) {
cancelBlock();
}
}];
UIAlertAction* confirmAction = [UIAlertAction actionWithTitle:#"Confirm"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
if (confirmBlock) {
confirmBlock();
}
}];
[passcodeCreationAlert addAction:cancelAction];
[passcodeCreationAlert addAction:confirmAction];
passcodeCreationAlert.preferredAction = confirmAction;
confirmAction.enabled = NO;
return passcodeCreationAlert;
}
This method returns a UIAlertController that allows the user to enter their desired passcode into a textfield. When I call this method in my view controller, I pass blocks as parameters which are used as the UIAlertAction handlers:
- (void)presentCreatePasscodeAlert {
UIAlertController *alert = [UIAlertController passcodeCreationAlertWithConfirmBehavior:^{
firstPasscode = alert.textFields[0].text;
[self presentConfirmPasscodeAlert];
} andCancelBehavior:^{
[self presentEnablePasscodeAlert];
}];
alert.textFields[0].delegate = self;
[self presentViewController:alert animated:YES completion:nil];
}
To reiterate the problem now that there is more context: When the action block is entered at the line:
firstPasscode = alert.textFields[0].text;
the alert is nil, and so is its textfield, meaning I cannot save the textfield's text.
In a separate project, however, I tried getting the same functionality without using the category and custom convenience methods, and that works as desired:
- (void) createPassword {
UIAlertController *createPasswordAlert = [UIAlertController alertControllerWithTitle:#"Enter a password"
message:nil
preferredStyle:UIAlertControllerStyleAlert];
__weak ViewController *weakSelf = self;
[createPasswordAlert addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
textField.delegate = weakSelf;
textField.keyboardType = UIKeyboardTypeNumberPad;
}];
UIAlertAction* confirmAction = [UIAlertAction actionWithTitle:#"Confirm"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
self.password = createPasswordAlert.textFields[0].text;
[self confirmPassword];
}];
UIAlertAction* cancelAction = [UIAlertAction actionWithTitle:#"Cancel"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
[self promptPasswordCreation];
}];
[createPasswordAlert addAction:confirmAction];
[createPasswordAlert addAction:cancelAction];
confirmAction.enabled = NO;
[self presentViewController:createPasswordAlert animated:YES completion:nil];
}
Sure enough, in the above code the alert exists when the Confirm block is entered, and I can save the text just fine.
Have I done something screwy by passing blocks as parameters to my convenience methods?
One of your problems is that when you create the block and send it into the initializer you are referencing a nil object inside the block. Then the block is saved with that nil reference and passed as a block to your handler.
UIAlertController *alert = [UIAlertController passcodeCreationAlertWithConfirmBehavior:^{
firstPasscode = alert.textFields[0].text;
[self presentConfirmPasscodeAlert];
} andCancelBehavior:^{
[self presentEnablePasscodeAlert];
}];
In there alert is not initialized yet when you create that block and send it to be saved. An option to fix that would be to use a standard initializer and then categorize a method to add the block functions that you want. Another option might be to try to add the __block modifier to the alert object, although I don't think that will help.

How to have a global UIAlertView

I have an app that consists of several view controllers, in each view controllers I could load a UIAlertView.
What would be the best way of having a global alert view function? So I could effectively have a function bit like
[GlobalAlertVIew alertview : 2];
the 2 referring to what alert it is (bit like a enum).
I have tried adding an NSObject file and calling that, however on the return function
- (void) alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
how do I get from this file in the NSObject to the original view controller?
Thanks
You either need to configure the delegate on the configured UIAlertView
UIAlertView *alertView = [GlobalAlertView alertView:2];
alertView.delegate = self;
or expose the delegate in the factory method
[GlobalAlertView alertView:2 withDelegate:self];
I don`t know if you still need, but I did like this:
+ (void)alert: (UIViewController *) view title: (NSString *) title message: (NSString *) message;
+ (void)alert: (UIViewController *) view title: (NSString *) title message: (NSString *) message {
UIAlertController * alert= [UIAlertController
alertControllerWithTitle:title
message:message
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:#"OK" style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {}];
[alert addAction:defaultAction];
[view presentViewController:alert animated:YES completion:nil];
}
You can add the following code to your constants header file and import this header at .pch file to be able to see this file at app ,
#define SHOW_ALERT(title,msg){ UIAlertController *noDataFoundAlert = [UIAlertController alertControllerWithTitle:title message:msg preferredStyle:UIAlertControllerStyleAlert];UIAlertAction *okAction = [UIAlertAction actionWithTitle:#"OK" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action){}]; [noDataFoundAlert addAction:okAction]; [self presentViewController:noDataFoundAlert animated:YES completion:nil];}
And you can call this method at any class like the following call ,
SHOW_ALERT(#"Please select any section", #"Please select any section");
Nada Gamal

Resources