How to control other buttons' actions? - iphone

Hi so say I have this code:
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle: #"Yay"
message: msg
delegate: self
cancelButtonTitle: #"Proceed..."
otherButtonTitles: #"1", #"2", nil];
How do I control the other buttons "1" and "2"? (Suppose all other necessary code is in place, such as the undefined variable msg)
Thanks!

You need to set the delegate property of your UIAlertView instance (i.e. alert) and implement the method alertView:clickedButtonAtIndex:.
Let's assume that you want the current class to be the delegate of the UIAlertView. You would use the following line of code:
alert.delegate = self;
Next, you would setup the current class to implement the UIAlertViewDelegate protocol in the .h file. For example:
#interface MyClass : NSObject <UIAlertViewDelegate>
Then you would simply implement the alertView:clickedButtonAtIndex: method in the .m file:
- alertView:a clickedButtonAtIndex:i {
NSLog(#"You clicked %d.", i);
}

Related

Failing compile on a class in the UIKit, its got to be an easy one

I'm sure there is an easy answer to this issue, but.....
I get the message "Receiver type "UIAlertView' for instance message does not declare method initWithName
.H looks like this
#import1 <UIKit/UIKit.h>
#interface LoginUIViewController : UIViewController <UIAlertViewDelegate>
-(IBAction) LoginButton;
#end
.M looks like this
#import "LoginUIViewController.h"
#implementation LoginUIViewController
-(IBAction) LoginButton {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Title"
delegate:self
message:#"message"
CancelButtonTitle:#"Cancel"
otherButtonTitles:#"Cancel",nil];
[alert show];
}
The method is initWithTitle:message:delegate:cancelButtonTitle:otherButtonTitles:. The parts need to be specified in that order and spelled correctly, including capitalization.

UIAlertView crash by adding clickedButtonAtIndex

I create a class to call UIAlertview show on my screen. I write the UIAlert function in another class. Both these two classes are not my viewController class.
I use this UIAlert, which is a UITextfield inside, to store texts into a plist file.
here is the class to call UIAlert:
#import "Story.h"
#implementation Story
...
+ (void)stage1
{
AlertClass *pointer = [AlertClass new];
[pointer doAlert];
}
here is the class AlertClass.m file:
- (void)doAlert
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Title" message:#"Message" delegate:self cancelButtonTitle:#"Done" otherButtonTitles:nil];
alert.alertViewStyle = UIAlertViewStylePlainTextInput;
[alert show];
}
//this makes crash!
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
self.storyFlow.text = [alertView textFieldAtIndex:0].text;
}
Before I add UIAlertViewDelegate in the .h and override the method "clickedButtonAtIndex", it works great. However, I need to store some data from the UITextfield inside the alert view. I get crash and don't know the message it responds as following.
Please help me to solve this problem. Thanks.
[crash pic] https://dl.dropbox.com/u/47381923/crash.tiff
do an NSLog on the text you get back from the Alert View to see whether that is the crash or the subsequent 'self.storyFlow.text = ' is causing it. Perhaps self.storyFlow has not been created yet (with alloc/init)

How do you pass a variable to the UIAlertView delegate?

How do you pass a variable to the UIAlertView delegate?
I have a variable that I want to use in the alert view delegate. It is only used in the function that shows the UIAlertView and the UIAlertView delegate, so i don't think it should be a property on the controller. Is there a way to attach the variable to UIAlertView and retrieve it in the delegate?
- (void) someUserCondition:(SOCode *)userCode {
if ([userCode warrentsConfirmation] > 0) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Title" message:#"Are you sure?" delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:#"OK",nil];
[alert setAlertViewStyle:UIAlertViewStyleDefault];
//TODO somehow store the code variable on the alert view
[alert show];
}
}
- (void) alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
NSString *title = [alertView buttonTitleAtIndex:buttonIndex];
if ([title isEqualToString:#"OK"]){
SOCode *userCode = //TODO somehow get the code from the alert view
[self continueWithCode:code];
}
}
in .h before interface:
extern const char MyConstantKey;
#interface ViewController...
in .m import:
import <objc/runtime.h>
in .m before implementation
const char MyConstantKey;
in .m implementation
-(void)viewDidAppear:(BOOL)animated{ //or wherever
NSString *aString = #"This is a string";
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Testing" message:#"test is test" delegate:self cancelButtonTitle:#"Okay" otherButtonTitles:nil];
[alert show];
[alert release];
objc_setAssociatedObject(alert, &MyConstantKey, aString, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
in .m alertview callback
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
NSString *associatedString = objc_getAssociatedObject(alertView, &MyConstantKey);
NSLog(#"associated string: %#", associatedString);
}
Use Associated Objects. It is described in more detail here: Your New Friends: Obj-C Associated Objects
To set the object you use use:
objc_setAssociatedObject(alert, &key, userCode, OBJC_ASSOCIATION_RETAIN);
And then to get it back:
SOCode *userCode = objc_getAssociatedObject(alertView, &key);
You also need to add static char key; so that it is in the scope of moth methods.
Update
I have wrapped this into a category on UIAlertView. You can use Cocoapods to bring it in:
pod 'HCViews/UIAlertViewHCContext', '~> 1.2'
The source is available here: https://github.com/hypercrypt/HCViews/blob/master/Categories/UIAlertView%2BHCContext.h
A lot of posts talk about the concepts behind associated objects (which is good!) but sometimes you just want to see the code. Here's a clean and quick category that you can either put in a separate file or above the interface of one of your existing .m files (you could even replace UIAlertView with NSObject and effectively add a context property to any object):
#import <objc/runtime.h>
#interface UIAlertView (Private)
#property (nonatomic, strong) id context;
#end
#implementation UIAlertView (Private)
#dynamic context;
-(void)setContext:(id)context {
objc_setAssociatedObject(self, #selector(context), context, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
-(id)context {
return objc_getAssociatedObject(self, #selector(context));
}
#end
And then you'll be able to do something like:
NSObject *myObject = [NSObject new];
UIAlertView *alertView = ...
alertView.context = myObject;
IMPORTANT:
And don't forget to nil the context in dealloc!!
UIAlertView is a subclass of UIView which has a tag property you can set to an integer. Unfortunately if you need something other than an integer to identify/pass info to the delegate than you will need to set some properties (or set up an array with the tag indexing into it) on the delegate itself. Advaith's way will probably work but is technically not supported by Apple.
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Title" message:#"Are you sure?" delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:#"OK",nil];
[alert setAlertViewStyle:UIAlertViewStyleDefault];
alert.tag = SOMEINTEGER;
[alert show];
I suspect the most straight-forward way is a property in the alert view's delegate class. An alert view doesn't have any provision for "user info" and doesn't support sub-classing, which removes the only shortcuts that come to mind.
Subclass UIAlertView, add a property called userInfo with type of your choice. Set the user info value at the time you create an instance of Subclassed UIAlertView, and retrieve it from within the delegate method. (There you will get the subclassed instance which holds the userInfo)

Display a UIAlertView in NSObject Class

I'm building a login system within my app that will be called several times. So instead of copying and pasting the code into several spots, I'm of course making an NSObject class so I can call the class when needed, instead.
The login system will display a UIAlertView, and when "OK" is tapped, the system will attempt to log in. I can call the class and the UIAlertView will show, but I cannot tell which buttons are tapped. Here is my code:
//Calling the login system
Login *login = [[Login alloc] init];
Login.h:
#import <Foundation/Foundation.h>
#interface Login : NSObject <UIAlertViewDelegate> {
}
#end
Login.m:
#import "Login.h"
#implementation Login
+(void)initialize {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Login" message:nil delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:#"OK", nil];
[alert show];
[alert release];
NSLog(#"Testing");
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
NSLog(#"Here");
NSString *title = [alertView buttonTitleAtIndex:buttonIndex];
if([title isEqualToString:#"OK"]) {
NSLog(#"Tapped");
}
}
#end
For now, before I put UITextFields in the view, I just want to get the app to know which button was tapped. Testing appears in the log, but neither Here nor Tapped appear. Thanks!
Your alert view should not be called by the class method +(void)initialize but by the instance -(id)init method that's why your instance doesn't get the notifications.
the class method "+(void)initialize" is called when the class first load.
the instance method "-(id)init" has its name beginning by init, and is called when you create (instantiate) your object.
-(id)init {
//alert view
self = [super init];
return self;
}
Just
switch(buttonIndex){
case 0:
NSLog(#"Tapped First Button");
break;
case 1:
break;
default:
break;
}
When you use self in a class method you're referring to the class itself, rather than an instance of the class. However, your delegate method is an instance method. You probably want the caller to create a Login instance and have the instance create the alert, plus be its delegate.
It's Simple :
Create a property for your NSObject class in your view controller class :
in h file :
#property (nonatomic , retain) LoginCheckNSObject *LoginCheckerObject;
in m file :
self.LoginCheckerObject=[[LoginCheckNSObject alloc] init];
[self.LoginCheckerObject setDelegate:self];
[self.LoginCheckerObject TrackNowLogin];

Using UIAlertView in an NSObject

I'm having a terrible time getting a UIAlertView to work within my custom NSObject class. In the research I've done it appears it should be possible but here's what I've run into.
First, here's my code:
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
NSLog(#"clickedButtonAtIndex: %d", buttonIndex);
}
-(void)testAlertView {
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"List Contains Items"
message:#"List contains items. Remove all items & delete?"
delegate:self
cancelButtonTitle:#"No"
otherButtonTitles:#"Yes", nil];
[alertView show];
}
If I set the delegate to self this code crashes as soon as I tap a button. If I set it to nil clickedButtonAtIndex is never called. I've tried with and without using the <UIAlertViewDelegate>.
I know someone will ask 'why are you doing this in NSObject instead of in your UIViewController?'. Primarily because I want to separate this code out so I can use it from multiple places in my app. But also because this is a small piece of a larger block of logic that makes sense to be on it's own.
Any ideas what I'm doing wrong?
Thanks,
Rich
I had the same problem using ARC. The root of the problem was the same. I solved it by putting my custom NSObject into a "strong" property to make sure the object exists as long as the calling object (an UIVIewCOntroller in my case) exists, so when the delegate of my alert view is called I still have my custom object around and the delegate method works fine.
Add the NSObject as strong property:
#import "Logout.h" // is NSObject
.
.
.
#property (nonatomic, strong) Logout *logout;
Then you will get the delegatemethods called in your NSObject.
Don´t forget to register the delegate for the UIAlertView:
#interface Logout () <UIAlertViewDelegate>
and in your method:
UIAlertView *a = [[UIAlertView alloc] initWithTitle:#"title"
message:#"message" delegate:self cancelButtonTitle:#"cancel"
otherButtonTitles:#"ok", nil];
[a show];
How To Present An Alert View Using UIAlertController When You Don't Have A View Controller. Detail description.
Yes, you can only use UIAlertController only in UIViewController classes. So how can we do it in NSObject classes. If you see the description link given above you will get to the answer. To summarise in a line for the above description: Create a new window above the the current window. This new window will be our viewController where we display alert. So using this viewController you can call the method [presentViewController: animated: completion:].
Answer:
dispatch_async(dispatch_get_main_queue(), ^{
UIWindow* window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
window.rootViewController = [UIViewController new];
window.windowLevel = UIWindowLevelAlert + 1;
NSString *msg=#“Your mssg";
UIAlertController* alertCtrl = [UIAlertController alertControllerWithTitle:#“Title" message:msg preferredStyle:UIAlertControllerStyleAlert];
[alertCtrl addAction:[UIAlertAction actionWithTitle:NSLocalizedString(#"Yes",#"Generic confirm") style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
// do your stuff
// very important to hide the window afterwards.
window.hidden = YES;
}]];
UIAlertAction *cancelAction= [UIAlertAction actionWithTitle:#"cancel" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
window.hidden = YES;
}];
[alertCtrl addAction:cancelAction];
//http://stackoverflow.com/questions/25260290/makekeywindow-vs-makekeyandvisible
[window makeKeyAndVisible]; //The makeKeyAndVisible message makes a window key, and moves it to be in front of any other windows on its level
[window.rootViewController presentViewController:alertCtrl animated:YES completion:nil];
});