Dismissing a UIViewController from a UIActionSheet Class - ios

I created a UIActionSheet Class that will allow me to log out from anywhere within my app. the issue that I am having is once I hit logout button it should also dismiss the current viewController and go back to the login viewController. Below is a snippet of my code.
NSObject.h file
#interface constants : NSObject<UIActionSheetDelegate>{
UIActionSheet *msg;
}
-(void)presentMyActionSheet;
#property (nonatomic, strong) UIView *viewForActionSheet;
NSObject.m file
-(void)presentMyActionSheet{
msg = [[UIActionSheet alloc] initWithTitle:nil delegate:self cancelButtonTitle:#"Cancel" destructiveButtonTitle:#"Log Out" otherButtonTitles:nil, nil];
[msg showInView:self.viewForActionSheet];
}
// actionsheet delegate protocol item
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex: (NSInteger)buttonIndex{
NSLog(#"button index = %ld", (long)buttonIndex);
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if(buttonIndex == 0){
[defaults setObject:nil forKey:#"acctInfo"];
[defaults setBool:NO forKey:#"isLoggedOn"];
NSLog(#"You logged out");
This is what I tried.
viewController *controller = [[viewController alloc]init];
[controller.navigationController popViewControllerAnimated:NO];
[controller dismissViewControllerAnimated:NO completion:nil];
it does not work.
}else{
NSLog(#"You canceled logout");
}
}
viewController.h file
#interface viewController : UIViewController<UIActionSheetDelegate>
#property(nonatomic, retain)constants *obj;
viewController.m file
#synthesize obj;
{
self.obj = [[constants alloc] init];
self.obj.viewForActionSheet = self.view;
[self.obj presentMyActionSheet];
if([defaults boolForKey:#"isLoggedOn"]){
If I try it from here it crashes.
// [self.navigationController popViewControllerAnimated:NO];
// [self dismissViewControllerAnimated:NO completion:nil];
}
}
Any suggestions as to why it is not working?
Thanks

You should use NSNotification o your own delegate in the object class.

Try something like this:
[self.viewForActionSheet.navigationController popToRootViewControllerAnimated:YES];

you could use the UIActionSheetDelegate Method -(void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex
For example:
-(void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex{
if (buttonIndex == 1) {
[self.navigationControllerler dismissModalViewControllerAnimated:YES];}}

Related

UIAlertController reuse more times with NSObject

In my app, UIAlertController uses much time.So, I create NSObject Helper.
Here is Helper.h
#import <Foundation/Foundation.h>
#import "PrefixHeader.pch"
#import "LectureViewController.h"
#interface Helper : NSObject
+(void) showNotice:(NSString *) message;
+(void) showNoticeWithAction;
#end
Here is Helper.m
#import "Helper.h"
#import "AppDelegate.h"
#implementation Helper
+(void) showNotice:(NSString *) message{
NSArray *versionArray = [[[UIDevice currentDevice] systemVersion] componentsSeparatedByString:#"."];
if ([[versionArray objectAtIndex:0] intValue] >= 9) {
//ver.IOS >= 9
UIAlertController* alert = [UIAlertController alertControllerWithTitle:nil
message:message
preferredStyle:UIAlertControllerStyleAlert];
alert.view.backgroundColor = [UIColor grayColor];
// [self presentViewController:alert animated:YES completion:nil];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[alert dismissViewControllerAnimated:YES completion:^{
}];
});
} else {
//ver.IOS < 9
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil message:message delegate:nil cancelButtonTitle:nil otherButtonTitles:nil, nil];
[alert performSelector:#selector(show) withObject:nil afterDelay:5];
}
}
#end
This line cant run in Helper: [self presentViewController:alert animated:YES completion:nil]; because of presentViewController. Please help me
You are getting this error because the base class is NSObject and self represent the object of that class and NSObject does'nt have any method named presentViewController.
To resolve it you need to pass an object of UIViewController in that method and on that object use presentViewController like this
+(void) showNotice:(NSString *) message andViewController : (UIViewController *) controller;
And use it like this
[controller presentViewController:alert animated:YES completion:nil];
the batter way create c function in #end of the class nsobject
void showAlertView( NSString *title,NSString *message) {
[[[UIAlertController alloc]initWithTitle:title message:message delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles: nil] show];
}
and call in any class like this
showAlertView(#"Done", [NSString stringWithFormat:#"%#",responseObject[#"message"]]);
Try this while your controller is pushed and presented .
UIViewController *vc = [[[[UIApplication sharedApplication] delegate] window] rootViewController];
[[vc presentedViewController] ? vc.presentedViewController : vc presentViewController:alert animated:YES completion:nil];

I can not change a label text by tag objective c

I am working on app with a login. What i want to do is that after the login a label displays the username.
Here is my code:
#import "ViewController.h"
#interface ViewController ()
#property (strong, nonatomic) IBOutlet UITextField *userNameTextField;
#property (strong, nonatomic) IBOutlet UITextField *passwordTextField;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)Login:(id)sender {
if ([_userNameTextField.text isEqualToString:#""] || [_passwordTextField.text isEqualToString:#""]) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"alert" message:#"Please Fill all the field" delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
[alert show];
return;
}
NSString *strURL = [NSString stringWithFormat:#"http://192.168.1.11:8888/swift/login.php?userName=%#&password=%#",_userNameTextField.text, _passwordTextField.text];
NSData *dataURL = [NSData dataWithContentsOfURL:[NSURL URLWithString:strURL]];
NSString *strResult = [[NSString alloc] initWithData:dataURL encoding:NSUTF8StringEncoding];
if ([strResult isEqualToString:#"1"])
{
NSString *username = _userNameTextField.text;
UILabel *myLabel = (UILabel *)[self.view viewWithTag:100];
myLabel.text = [NSString stringWithFormat:#" Label %#",username];
UIStoryboard *sb = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
UIViewController *vc = [sb instantiateViewControllerWithIdentifier:#"logedIn"];
vc.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentViewController:vc animated:YES completion:NULL];
}
else if ([strResult isEqualToString:#"0"])
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"alert" message:#"Wrong username / password" delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
[alert show];
return;
}
else {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"alert" message:#"Server Error" delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
[alert show];
return;
}
}
#end
Here is a image of my storyboard
In the image you see my first seen in the bottom left corner. the second screen is in the upper right corner. The both have the class ViewController
I am using xcode 7.0
U have 2 different instances of ViewController which means the UITextField that changes in the first one won't be visible to the second one.
U need to have an object (let's call it Model) which will hold the data and change on demand.
Any way, change your architecture to have a Model layer which will hold your data.
If u want to make things works specific here but in bad practice way, create NSString in the AppDelegate and set the data there when changed. And get the data from there on demand.
But again,
change your architecture to have a Model-View-Controller
Set the property for your label in your .h and link it on your storyboard.
#property (nonatomic, strong) IBOutlet UILabel *label;
Then, before presenting your new view controller, you can just set the text for that label.
UIStoryboard *sb = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
UIViewController *vc = [sb instantiateViewControllerWithIdentifier:#"logedIn"];
vc.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
vc.label.text = [NSString stringWithFormat:#" Label %#",username];
[self presentViewController:vc animated:YES completion:NULL];

UIAlertView button action not working

I have one alert view and when I click on yes button it is supposed to produce another alert view and a toast message,but it is not happening. I couldn't figure it out. Here is my code:
-(void)myMethod {
UIAlertView *saveAlert = [[UIAlertView alloc] initWithTitle:#"First Message"
message:#"My First message"
delegate:nil
cancelButtonTitle:#"No"
otherButtonTitles:#"Yes", nil];
saveAlert.tag=0;
[saveAlert performSelectorOnMainThread:#selector(show) withObject:nil waitUntilDone:NO];
}
This is the method I am using to provide the functionality for different alert views.
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if(alertView.tag==0) {
if (buttonIndex == 0)
{
//Code for Cancel button
}
if (buttonIndex == 1)
{
//code for yes button
MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.navigationController.view animated:YES];
hud.mode = MBProgressHUDModeText;
hud.labelText = #"Successfully displayed First Message";
hud.margin = 10.f;
hud.yOffset = 150.f;
hud.removeFromSuperViewOnHide = YES;
[hud hide:YES afterDelay:3];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Second Message"
message:#"My second message"
delegate:nil
cancelButtonTitle:#"No"
otherButtonTitles:#"Yes",nil];
alert.tag=1;
[alert performSelectorOnMainThread:#selector(show) withObject:nil waitUntilDone:YES];
}
}
if (alertView.tag==1) {
if (buttonIndex == 0)
{
//Code for Cancel button
}
if (buttonIndex == 1)
{
//Code for yes Button
MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.navigationController.view animated:YES];
hud.mode = MBProgressHUDModeText;
hud.labelText = #"Succesfully displayed Second Message";
hud.margin = 10.f;
hud.yOffset = 150.f;
hud.removeFromSuperViewOnHide = YES;
[hud hide:YES afterDelay:3];
}
}
}
Can anyone help in finding the issue. Why I cannot get my second alert after clicking yes button in first alert?
You have not set the delegate for your UIAlertView and also make sure your delegate conforms to UIAlertViewDelegate protocol. Find the code snippet below.
You controller conforms to UIAlertViewDelegate protocol:
#interface YourViewController : UIViewController <UIAlertViewDelegate>
Create UIAlertView and set the deleagte:
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"First Message"
message:#"Show second message"
delegate:self
cancelButtonTitle:#"No"
otherButtonTitles:#"Yes", nil];
[alertView show];
Implement UIAlertViewDelegate delegate method:
- (void) alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if( 0 == buttonIndex ){ //cancel button
[alertView dismissWithClickedButtonIndex:buttonIndex animated:YES];
} else if ( 1 == buttonIndex ){
[alertView dismissWithClickedButtonIndex:buttonIndex animated:YES];
UIAlertView * secondAlertView = [[UIAlertView alloc] initWithTitle:#"Second Message"
message:#"Displaying second message"
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[secondAlertView show];
}
}
You are specifying nil as the delegate for your alert views. You need to specify an object so the alertView:clickedButtonAtIndex: method can be called!
If you'd like to handle this more clear, you could use a block-based AlertView.
Create new file->Subclass of->UIAlertView
SuperAlertView.h
#import <UIKit/UIKit.h>
#class MySuperAlertView;
typedef void (^MySuperAlertViewBlock) (MySuperAlertView *alertView);
#interface MySuperAlertView : UIAlertView
- (instancetype) initWithTitle:(NSString *)title message:(NSString *)message;
- (void) addButtonWithTitle:(NSString *)buttonTitle block:(MySuperAlertViewBlock) block;
#end
SuperAlertView.m
#import "MySuperAlertView.h"
#interface MySuperAlertView()<UIAlertViewDelegate>
#property NSMutableArray *blocks;
#end
#implementation MySuperAlertView
- (instancetype)initWithTitle:(NSString *)title message:(NSString *)message
{
if (self = [super initWithTitle:title message:message delegate:self cancelButtonTitle:nil otherButtonTitles:nil])
{
self.blocks = [NSMutableArray array];
}
return self;
}
- (void)addButtonWithTitle:(NSString *)buttonTitle block:(MySuperAlertViewBlock)block
{
[self addButtonWithTitle:buttonTitle];
[self.blocks addObject:block ? [block copy] : [NSNull null]];
}
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
{
MySuperAlertViewBlock block = self.blocks[buttonIndex];
if ((id) block != [NSNull null]){
block(self);
}
}
#end
Usage:
MySuperAlertView *alertView = [[MySuperAlertView alloc] initWithTitle:#"Info" message:NSLocalizedString(#"EMAIL_SENT_SUCCESSFULL", nil)];
[alertView addButtonWithTitle:#"Ok" block:^(MySupertAlertView *alertView) {
// handle result from ok button here
}];
[alertView addButtonWithTitle:#"cancel" block:NULL];
dispatch_async(dispatch_get_main_queue(), ^{
[alertView show];
});

Retrieving index path from table view

i am trying to replace an object at in an array by replacing it with the text returned from an alert view.
so far i have:
int selected = indexPath.row;
and for my alertview delegate method.
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
if (alertView.tag == 1) {
[myMutableArray replaceObjectAtIndex:selected withObject:[[alertView textFieldAtIndex:0] text]];
[_tableView reloadData];
}
}
i keep getting an error of
Incompatible integer to pointer conversion assigning to 'NSInteger *' (aka 'long *') from 'NSInteger' (aka 'long')
The error you see comes from the fact that you put a * somewhere before the NSInteger variable.
Without knowing what the rest of your code looks like, you could try this in your ViewController.m file. It sets the text of a label and replaces an object in a mutable array with the text from the alert view when the "OK" button is pressed.
#import "ViewController.h"
#interface ViewController () <UIAlertViewDelegate>
#property (strong,nonatomic) NSMutableArray *mutArray;
#property (weak,nonatomic) IBOutlet UILabel *label;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSArray *array = #[#"item1",#"item2",#"item3"];
self.mutArray = [[NSMutableArray alloc] init];
self.mutArray = [array mutableCopy];
}
- (IBAction)showAlert:(id)sender {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"My Alert Example"
message:#"message here"
delegate:self
cancelButtonTitle:#"Cancel"
otherButtonTitles:#"OK",nil];
alert.alertViewStyle = UIAlertViewStylePlainTextInput;
[alert show];
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
int selected = 1;
if (buttonIndex != alertView.cancelButtonIndex) {
NSLog(#"ok button");
UITextField *textField = [alertView textFieldAtIndex:0];
self.label.text = textField.text;
[self.mutArray replaceObjectAtIndex:selected withObject:textField.text];
NSLog(#"mutArray is %#",self.mutArray);
} else {
NSLog(#"cancel button");
}
}
#end
Since it looks like you're using a UITableView, in your case you would have int selected = indexPath.row instead of int selected = 1.

Pass data to root controller

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!!

Resources