I created one NSObject class in which I created some common functions. I created function which show UIAlertView. It works fine. But when I click on alert button, didDismissWithButtonIndex delegate method not called.
+ (void)showMessage:(NSString *)message
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:JMESSAGETITLE message:message delegate:self cancelButtonTitle:#"Ok" otherButtonTitles:nil];
[alert postHideAlertNotification:0];
[alert show];
}
#pragma mark - UIAlertView Delegate
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
{
NSLog(#"Hello");
}
I don't know what the problem is.
The self in this line
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:JMESSAGETITLE message:message delegate:self cancelButtonTitle:#"Ok" otherButtonTitles:nil];
indicates the NSObject class not an object. You have to change the class method to instance method or create an object of NSObject class and set this object as delegate.
For object creation you can use singleton pattern.
+ (YourClass *)sharedInstance {
static dispatch_once_t once;
static YourClass *sharedMyClass;
dispatch_once(&once, ^ {
sharedMyClass = [[self alloc] init];
});
return sharedMyClass;
}
+ (void)showMessage:(NSString *)message
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle: JMESSAGETITLE message:message delegate:[YourClass sharedInstance] cancelButtonTitle:#"Ok" otherButtonTitles:nil];
[alert show];
}
Try this:
Confirm to UIAlertViewDelegate protocol in the NSObject class like this:
#interface yourClass : NSObject <UIAlertViewDelegate>
Make UIAlertView *alert object as instance variable of the class or
property. Like this:
#interface yourClass : NSObject <UIAlertViewDelegate>
#property (nonatomic, strong) UIAlertView *alert;
#end
In the method where you are using the alert object, set the delegate self.alert.delegate = self
Related
I have a simple class like this
.h
#interface DJMyClass : NSObject
+ (void)someFunction;
#end
.m
#import "DJJavaFunction+UIAlert.h"
#interface DJMyClass ()
#property (nonatomic, strong) NSString* someString;
#end
#implementation DJMyClass
+(void)functionWithName:(NSString *)functionName
callbackId:(int)callbackId
args:(NSArray *)args
{
DJMyClass *newFunction = [[DJMyClass alloc] init];
newFunction.function = functionName;
newFunction.callbackId = callbackId;
newFunction.args = args;
[newFunction processFunction];
}
- (void)processFunction
{
[self showAlertWithTitle:title message:message buttons:buttons inputField:inputField callbackId:_callbackId];
}
#end
Now I have created different extensions of this class, which I import and use within this class.
.h
#interface DJMyClass (UIAlert) <UIAlertViewDelegate>
- (void)showAlertWithTitle:(NSString *)title
message:(NSString *)message
buttons:(NSArray *)buttons
inputField:(NSDictionary *)inputField
callbackId:(int)callbackId;
#end
.m
#implementation DJJavaFunction (UIAlert)
- (void)showAlertWithTitle:(NSString *)title
message:(NSString *)message
buttons:(NSArray *)buttons
inputField:(NSDictionary *)inputField
callbackId:(int)callbackId
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:title
message:message
delegate:self
cancelButtonTitle:nil
otherButtonTitles:nil];
// Add the buttons
for (NSString *btn in buttons)
{
[alert addButtonWithTitle:btn];
}
// Add text field
if (!inputField)
{
alert.alertViewStyle = UIAlertViewStyleDefault;
}
else
{
alert.alertViewStyle = UIAlertViewStylePlainTextInput;
UITextField *textField = [alert textFieldAtIndex:0];
textField.placeholder = inputField[#"placeholder"];
textField.text = inputField[#"text"];
}
alert.delegate = self;
alert.tag = 44;
[alert show];
}
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
{
NSLog(#"%s", __PRETTY_FUNCTION__);
}
#end
This all works well, except that the UIAlertViewDelegate methods are never called.
Is it even possible to respond to UIAlertViewDelegate calls from within a category?
Thanks
I have UIAlertView working as expected in simulator, and earlier in my App's development it worked well on the device, but as of now it doesn't show up. I am however certain the code is running. Help would be greatly appreciated.
MacroEditViewController.h:
#interface MacroEditViewController : UIViewController <UIAlertViewDelegate>
MacoEditViewController.m:
- (IBAction)saveDatabase:(UIButton *)sender
{
[self alertStatusWithTitle:[NSString stringWithFormat:#"Are you sure you want to override %# for %#? This cannot be undone (But you can Reset All Overrides on Macros screen).", macroMeal[1], macroMeal[0]] :#"Update Macros"];
}
- (void) alertStatus:(NSString *)msg :(NSString *)title
{
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:title
message:msg
delegate:self
cancelButtonTitle:#"Ok"
otherButtonTitles:#"Cancel", nil];
[alertView show];
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (buttonIndex == 0) {
[self saveUpdatesToDatabase];
}
}
Why did you call your function like this
[self alertStatus:[#"Are you sure you want to override?"] :#"Update Macros"];
Call it like this
[self alertStatus:#"Are you sure you want to override?" :#"Update Macros"];
without the square brackets, it may be the problem
create a CIAlert.h
void CIAlert(NSString* title, NSString* alert);
void CIError(NSString* error);
and in CIAlert.m
#import "CIAlert.h"
void CIAlert(NSString* title, NSString* alert) {
UIAlertView* alertView = [[UIAlertView alloc] initWithTitle:title message:alert delegate:nil
cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alertView show];
}
void CIError(NSString* error) {
CIAlert(#"Error", error);
}
import the class CIAlert.h and call it just like this...
CIAlert(#"Title", #"Enter your message");
I have six methods, in which I'm calling alert function.
Is it possible to call only the alert function only once, so to optimize my code will be?
This is my code:
// #import "ViewController.h"
//.h file
.m file
#interface ViewController ()
#end
#implementation ViewController
#synthesize usernameText;
#synthesize emailText;
#synthesize passwordText;
#synthesize `repasswordTex`t;
#synthesize postalText;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
//for keyboard hide on textfield return
- (BOOL)textFieldShouldReturn:(UITextField *)theTextField {
[theTextField resignFirstResponder];
return YES;
}
//function for Name validation
- (BOOL) validatename:(NSString *) candidate{
[postalText setKeyboardType:UIKeyboardTypeAlphabet];
NSString *nameRegex = #"[A-Za-z]+";
NSPredicate *codeTest = [NSPredicate predicateWithFormat:#"SELF MATCHES %#",nameRegex];
return [codeTest evaluateWithObject:candidate];
}
// email validation
- (BOOL) validateEmail: (NSString *) candidate {
NSString *emailRegex = #"[A-Z0-9a-z._%+-]+#[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}";
NSPredicate *emailTest = [NSPredicate predicateWithFormat:#"SELF MATCHES %#", emailRegex];
return [emailTest evaluateWithObject:candidate];
}
// password code validation
- (BOOL)paswordvalidation:(NSString *) candidate
{
}
// postal code validation
- (BOOL) validatecode: (NSString *) candidate {
NSString *codeRegex = #"^\d{5}(?:[-\s]\d{4})?$";
NSPredicate *codeTest = [NSPredicate predicateWithFormat:#"SELF MATCHES %#", codeRegex];
return [codeTest evaluateWithObject:candidate];
}
//method call on submit button
- (IBAction)submitButn:(id)sender{
//user name method call
if(![self validatename:usernameText.text])
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error" message:#"Please Ensure that you have insert character only"delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
return;
}
//Email Method Call
else if(![self validateEmail:emailText.text])
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error" message:#"Please Insert Valid Email Address"delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
return;
}
//Password validate Method Call
else if([passwordText.text length] <6)//&& [repasswordText.text length] <= 6)
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error" message:#"Password should contain minimun 6 "delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
return;
}
else if (![passwordText.text isEqualToString:repasswordText.text])
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error" message:#"confirm password should be same"delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
return;
}
//Postal Code Method Call
else if(!([self validatecode:postalText.text] ||[postalText.text length] <6))
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error" message:#"postal Code should cotain 5 "delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
return;
}
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
Write this method and call where ever you want.
-(void)showAlert :(NSString *)alertTitleString WithAlertMessage :(NSString *)alertMessage{
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:alertTitleString alertMessage delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles:nil, nil];
[alert show];
}
It is possible, add this method name in AppDelegate.h
-(void)alertFuction:(NSString *)title message:(NSString *)message
Then add this function to AppDelegate.m
-(void)alertFuction:(NSString *)title message:(NSString *)message
{
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:title message:message delegate:self cancelButtonTitle:#"Done" otherButtonTitles:nil, nil];
[alert show];
[alert release];
alert = nil;
[delegate.window setUserInteractionEnabled:YES];
}
Then in any other view controller put this
.h file
#class AppDelegate
.m file
#import AppDelegate
in viewDidload method
AppDelegate *delegate = (AppDelegate *)[[UIApplication sharedApplication]delegate];
then you can call the alert method by
[delegate alertFuction:#"title" message:#"message"];
How about a generalised helper class with class methods which cover a number of common scenarios (which you may obviously want to reconfigure / add to):
#implementation AlertHelper
+ (UIAlertView *)showAlertWithMessage:(NSString *)message
{
[AlertHelper showAlertWithTitle:nil message:message delegate:nil cancelButton:NSLocalizedString(#"OK", nil) otherButton:nil];
}
+ (UIAlertView *)showAlertWithTitle:(NSString *)title message:(NSString *)message
{
[AlertHelper showAlertWithTitle:title message:message delegate:nil cancelButton:NSLocalizedString(#"OK", nil) otherButton:nil];
}
+ (UIAlertView *)showAlertWithTitle:(NSString *)title message:(NSString *)message delegate:(id < UIAlertViewDelegate >)delegate cancelButton:(NSString *)cancel otherButton:(NSString *)other
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:title message:message delegate:delegate cancelButtonTitle:cancel otherButtonTitles:(other ? #[ other ] : nil)];
[alert show];
}
#end
Note that the alert view is returned just in case it is required (say you need to automatically remove the alert view once an operation is complete).
Surely you can, you even should! You just need to refactor it to a separate methods witch will receive a few attributes or (better option) an object with variables from which you could set a required values for the alert you want to show.
- (void)showAlertWithTitle:(NSString *)alertTitle andMessage:(NSString *)alertMessage {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:alertTitle message:alertMessage delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
}
It could be than a way better but according to your case that will do what you want. It is just extracting a method from your code.
I am developing a contacts app. I want to add a contact, by opening a new view like this:
RootViewController.m...
it has a NSMutableArray called contacts
- (IBAction)addContact:(id)sender {
AddContViewController *cont = [[AddContViewController alloc]init];
[self.navigationController presentViewController:cont animated:YES completion:nil];
}
And then come back and add the contact to the array of the root view controller:
AddContViewController.m
- (IBAction)acceptAction:(id)sender {
if ([[firstName text] length] < 1 && [[lastName text] length] < 1)
{
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"Oh no!" message:#"Invalid contact information!" delegate:self cancelButtonTitle:#"Ok" otherButtonTitles: nil];
[alert show];
}
else{
// create the contact and put it in the root view controller's array
Contact *cont = [[Contact alloc]initWithFirstName:[firstName text] lastName:[lastName text] andDOB:[dobPicker date]];
// and now I don't know what to do....
[self dismissViewControllerAnimated:YES completion:^{
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"Success!" message:#"Contact added successfully!" delegate:self cancelButtonTitle:#"Ok" otherButtonTitles: nil];
[alert show];
}];
}
}
You should use a delegate to communicate the new Contact object back to your RootViewController.
Define the protocol
#protocol AddContDelegate
-(void)didAddnewContact:(Contact *)contact;
#end
On Your AddContViewController have a delegate property :
#property (nonatomic, assign) id<AddContDelegate> delegate;
In your addContact: method assign the delegate :
- (IBAction)addContact:(id)sender {
AddContViewController *cont = [[AddContViewController alloc]init];
cont.delegate = self;
[self.navigationController presentViewController:cont animated:YES completion:nil];
}
Implement the delegate method in RootViewController :
-(void)didAddnewContact:(Contact *)contact {
[contacts addObject:contact];
}
Call the delegate from AddContViewController :
- (IBAction)acceptAction:(id)sender {
if ([[firstName text] length] < 1 && [[lastName text] length] < 1)
{
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"Oh no!" message:#"Invalid contact information!" delegate:self cancelButtonTitle:#"Ok" otherButtonTitles: nil];
[alert show];
}
else{
Contact *cont = [[Contact alloc]initWithFirstName:[firstName text] lastName:[lastName text] andDOB:[dobPicker date]];
if([self.delegate respondsToSelector:#selector(didAddnewContact:)]) {
[self.delegate didAddnewContact:cont];
}
[self dismissViewControllerAnimated:YES completion:^{
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"Success!" message:#"Contact added successfully!" delegate:self cancelButtonTitle:#"Ok" otherButtonTitles: nil];
[alert show];
}];
}
}
There are several ways to pass the data back. I'd suggest setting up a delegate method.
Add this to the top of your AddContViewController.h after any imports:
#class addContViewController
#protocol addContViewControllerDelegate <NSObject>
-(void)addContViewController:(addContViewController *)controller didAddContact:(Contact *)contact;
#end
And after the interface section add
#property (nonatomic, weak) id <addContViewControllerDelegate> delegate;
Then in your RootViewController.h add the protocol to the interface line <addContViewControllerDelegate>
Now in your RootViewController.m method addContact just before you push the new view, add:
cont.delegate = self;
Now in your AddContViewController.m instead of dismissing the view, call:
[self.delegate addContViewController:self didAddContact:cont];
This will call a new method in your RootViewController which it'll pass the Contact and in here you can do with it want you want, but first dismiss the view:
-(void)addContViewController:(addContViewController *)controller didAddContact:(Contact *)contact {
self dismissViewControllerAnimated:YES;
}
You may want to use delegate for this action so that you can communicate to the rootviewcontroller to have contact object.
The same can be achieved using the stack of navigationViewController using [navigationViewController viewControllers] and of the last object is of type of your class you can perform certain selector of your root and dismiss your AddContViewController with a success message.
Hope this will help!!
This question already has answers here:
UIAlertView fails to show and results in “EXC_BAD_ACCESS” error
(6 answers)
Closed 8 years ago.
I add a function to dismiss the UIAlertView after several seconds.The whole code is like:
- (void)netWorkAlert
{
UIAlertView *netWork = [[UIAlertView alloc] initWithTitle:#"error" message:#"network has problems" delegate:self cancelButtonTitle:nil otherButtonTitles: nil];
[netWork show];
[self performSelector:#selector(dismissAlert:) withObject:netWork afterDelay:2];
}
- (void)dismissAlert:(UIAlertView *)alert
{
if(alert)
{
[alert dismissWithClickedButtonIndex:0 animated:YES];
[alert release];
}
}
the netWorkAlert is invoked when the network is unavailable.
Now the problem I met is when the netWorkAlert is invoked at the second time, the app is broken and the Xcode shows error in
int main(int argc, char *argv[])
{
#autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([ZJAppDelegate class]));
//Thread 1 :EXC_BAD_ACCESS(code=1,address=xc0000004)
}
}
I didn;t use ARC and I don't know why it crashes. Even I comment the [alert release];, it still has the same problem at the second time.
Could anyone help me to check it?
thanks!
The EXC_BAD_ACCESS is caused by accessing a released object. To avoid this make your call to UIAlertView kind of modal:
Function body:
-(void)checkSaving
{
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle:#"Do you want to add these results to your database?"
message:#"\n\n"
delegate:self
cancelButtonTitle:#"No"
otherButtonTitles:#"Save", nil];
alert.alertViewStyle = UIAlertViewStyleDefault;
[alert show];
//this prevent the ARC to clean up :
NSRunLoop *rl = [NSRunLoop currentRunLoop];
NSDate *d;
d= (NSDate*)[d init];
while ([alert isVisible]) {
[rl runUntilDate:d];
}
}
Your choice result:
- (void)alertView:(UIAlertView *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
// the user clicked one of the OK/Cancel buttons
if (buttonIndex == 1)//Save
{
//do something
}
if (buttonIndex == 0)//NO
{
//do something
}
}
Register the functions in the interface declaration:
#interface yourViewController ()
-(void)checkSaving
- (void)alertView:(UIAlertView *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
//...
#end
To call:
[self checkSaving];
I wish this will help you.
The UIAlertView could be out of scope by the time the dismissAlert method is called (your checking for alert being nil will prevent this code crashing. There is, however, a better way of implementing this where alert will never be out of scope.
Your class that defines the networkAlert method should implement the <UIAlertViewDelegate> protocol. The code below allows you to intercept the user clicking the 'cancel' button and perform a custom action. The default action of pressing cancel is to close the UIAlertView.
#interface YourClassName : UIViewController <UIAlertViewDelegate> {}
#implementation YourClassName
-(void) networkAlert
{
UIAlertView *netWork = [[UIAlertView alloc] initWithTitle:#"error"
message:#"network has problems"
delegate:self
cancelButtonTitle:#"cancel"
otherButtonTitles:nil];
[netWork show];
}
- (void) alertViewCancel:(UIAlertView*)alertView
{
what ever it is you want to do when the cancel button is pressed here
}