Delegate Method not Working - objective-c

I'm trying to implement a delegate method for my button ... I think I did everything correctly but do not understand why I can not make it work ... My button does not respond to any commands looks dead ... ...
My button is located in the ViewController "B" and the function it has to perform is located in the ViewController "A"
This is my code
viewControllerB.h
#protocol UNI_TableLoginDelegate <NSObject>
-(void)showPassw;
#end
#interface viewControllerB : UITableViewController
#property (nonatomic, weak) id <UNI_TableLoginDelegate> delegate;
#end
viewControllerB.m (here I connected the action button via my storyboard)
#implementation viewControllerB
#synthesize delegate;
- (void)viewDidLoad {
[super viewDidLoad];
}
- (IBAction)showReset:(id)sender {
[delegate showPassw];
}
viewControllerA.m
#import "viewControllerB.h"
#interface viewControllerA () <UNI_TableLoginDelegate>
- (void)viewDidLoad {
[super viewDidLoad];
viewControllerB *tableLogin = [[viewControllerB alloc] init];
tableLogin.delegate = self;
}
//Delegate Method
-(void)showPassw {
if (containerTable.frame.origin.y == 56) {
NSLog(#"ssss");
}
else {
NSLog(#"hdhdh");
}
}

You need to set the delegate in your ViewController A.
Let's say you have this method that calls right before dismissing the ViewController A:
-(void)dismissThisController{
// you need to set the delegate value
[self.delegate yourDelegateMethod:withValueYouWantToSend];
[self dismissViewControllerAnimated:YES completion:^{
}];
}
and in your View Controller B, you have this delegate method:
#pragma mark ViewController A delegate
-(void)yourDelegateMethod:(someType)value{
//receive your delegate value here
}

Related

How to continouse pass value from one ViewController to second Viewcontroller and automatic close, dismiss 2nd ViewController

I try to pass data from one ViewController to secondControler however seem it not work. I use NSNotification.
- 2 Controller have same class "ViewController"
In viewcontroller.m
- (void)viewDidLoad {
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(ProcessBarLoading) name:#"buttonPressed" object:nil];
}
-(void)ProcessBarLoading{
_labelTest.stringValue = #"TESTING";
}
- (IBAction)test:(id)sender {
[[NSNotificationCenter defaultCenter] postNotificationName:#"buttonPressed" object:self];
NSStoryboard *storyboard = [NSStoryboard storyboardWithName:#"Main" bundle: nil];
NSViewController * vc = [storyboard instantiateControllerWithIdentifier:#"SheetViewController"];
[self presentViewControllerAsSheet:vc];
}
When run program and press button, there're no update Label Text at all. Do you know why and how I can fix.
New Code:
In SecondViewController.m
#interface SencondViewController ()
#end
#implementation SencondViewController
#synthesize progressValue;
#synthesize labelView;
- (void)viewDidLoad {
[super viewDidLoad];
// Do view setup here.
labelView.stringValue =progressValue;
}
In FirstViewCOntroller:
- (IBAction)test:(id)sender {
self->uide = #"0";
[self performSegueWithIdentifier:#"showRecipeDetail" sender:self->uide];
NSStoryboard *storyboard = [NSStoryboard storyboardWithName:#"Main" bundle: nil];
NSViewController * vc = [storyboard instantiateControllerWithIdentifier:#"SheetViewController"];
[self presentViewControllerAsSheet:vc];
- (void)prepareForSegue:(NSStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"showRecipeDetail"]) {
SencondViewController * secondVC = segue.destinationController;
secondVC.progressValue = uide;
}
}
- (IBAction)test2:(id)sender {
uide = #"80";
[self performSegueWithIdentifier:#"showRecipeDetail" sender:uide];
[self.view displayIfNeeded];
}
So whether I press Button 1(test) other Button2 (test2) alway show new view with update value. What I need is only show 1 view.
Why do you need use a nsnotification the easy way is use a prepareForSegue or Delegation
This is an examample
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
if ([segue.identifier isEqualToString:#"myId"]) {
SecondViewController *vc = segue.destinationViewController;
vc.myDataToPass = self.myValueInMyFirstViewController;
}
}
Notification pattern is not recommended for doing this. Use notification
when you want to pass some data to multiple objects on some event.
To solve this problem:
Step 1:
You should change your View Controller names to FirstViewController and SecondViewController, and have a property declared in your SecondViewController whose value you want to set from the FirstViewController.
Step 2:
Finally, in the prepare for Segue method of the FirstViewController, set the data.
In Objective-C, you can try this code:
#import "FirstViewController.h"
#import "SecondViewController.h"
#interface FirstViewController ()
#end
#implementation FirstViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
//This will trigger the prepareForSegue method
-(IBAction) someButtonClick {
[self performSegueWithIdentifier:#"YourSequeId" sender:nil];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
SecondViewController * secondVC = segue.destinationViewController;
secondVC.someValue = #"PassYourValueHere";
}
#end
and in the header file of the SecondViewController, declare the property:
#import <UIKit/UIKit.h>
#interface SecondViewController : UIViewController
#property (nonatomic,strong) NSString *someValue;
#end
In the implementation file of the SecondViewController, write:
#import "SecondViewController.h"
#interface SecondViewController ()
#property (nonatomic,weak) IBOutlet UITextField *yourTextField;
#end
#implementation SecondViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.yourTextField.text = self.someValue
// Do any additional setup after loading the view.
}
#end

delegation and passing data back from childViewController

I have been struggling with this for a few days and have received valuable help on the way from S.O. I have made the simplest possible project to reduce the possibilities of it being a typo.
All my project is, is a ViewController that holds a container view hooked to a childViewController. The "parent" ViewController is set as the delegate of the childViewController. In the viewDidLoad of the child I am passing a value which is just a string. This string should be passed on to the parent and printed on the console. Here are the files.
ViewController.h
#import <UIKit/UIKit.h>
#import "ChildViewController.h"
#interface ViewController : UIViewController <ChildViewControllerDelegate>
#end
ViewController.m
#import "ViewController.h"
#interface ViewController ()
#property NSString *myValueRetrieved;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
ChildViewController *controller = [self.storyboard instantiateViewControllerWithIdentifier:#"ChildVC"];
controller.delegate = self;
NSLog(#"Here is my value: %#",self.myValueRetrieved);
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
- (void) passValue:(NSString *)theValue{
self.myValueRetrieved = theValue;
}
#end
ChildViewController.h
#import <UIKit/UIKit.h>
#protocol ChildViewControllerDelegate;
#interface ChildViewController : UIViewController
#property (weak)id <ChildViewControllerDelegate> delegate;
#end
#protocol ChildViewControllerDelegate <NSObject>
- (void) passValue:(NSString*) theValue;
#end
ChildViewController.m
#import "ChildViewController.h"
#interface ChildViewController ()
#property NSArray *colors;
#end
#implementation ChildViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self.delegate passValue:#"Hello"];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
#end
Am I right to think that when the app is launched, the console should log the following message: "here is my value: hello". Am I doing something wrong in terms of logically not getting delegation or is it just a silly typo somewhere? tx
You're assuming that the view is loaded when the view controller is instantiated. That's now how it works. The view gets loaded when it's needed (like to add to the parent view).
But you can force the view to load and make this work. Call -loadViewIfNeeded on the child view controller right after setting the delegate. That will probably get you what you want:
controller.delegate = self;
[controller loadViewIfNeeded];
NSLog(#"Here is my value: %#",self.myValueRetrieved);
Or, if you do want to call back the delegate in viewDidLoad, then you'd need to move the NSLog to the -passValue: method, since the primary view controller's viewDidLoad method will have already finished running.
To do this make ParentController a delegate of ChildController. This allows ChildController to send a message back to ParentController enabling us to send data back.
For ParentController to be delegate of ChildController it must conform to ChildController's protocol which we have to specify. This tells ParentController which methods it must implement.
In ChildController.h, below the #import, but above #interface you specify the protocol.
#class ChildController;
#protocol ViewControllerBDelegate <NSObject>
- (void)addItemViewController:(ChildController *)controller didFinishEnteringItem:(NSString *)item;
#end
next still in the ChildController.h you need to setup a delegate property and synthesize in ChildController.h
#property (nonatomic, weak) id <ChildControllerDelegate> delegate;
In ChildController we call a message on the delegate when we pop the view controller.
NSString *itemToPassBack = #"Pass this value back to ParentController";
[self.delegate addItemViewController:self didFinishEnteringItem:itemToPassBack];
That's it for ChildController. Now in ParentController.h, tell ParentViewController to import Child and conform to its protocol.
import "ChildController.h"
#interface ParentController : UIViewController
In ParentController.m implement the following method from our protocol
- (void)addItemViewController:(ChildController *)controller didFinishEnteringItem:(NSString *)item
{
NSLog(#"This was returned from ChildController %#",item);
}
The last thing we need to do is tell ChildController that ParentController is its delegate before we push ChildController on to nav stack.
ChildController *ChildController = [[ChildController alloc] initWithNib:#"ChildController" bundle:nil];
ChildController.delegate = self
[[self navigationController] pushViewController:ChildController animated:YES];

OS X Delegate set label from other window (Xcode)

I'm quite new to Mac programming (not to Objective C).
I'm developing a small application, that shows some data and opens a second window on button press.
In the second window is a textfield and a submit button. If the submit button is pressed, the window should close + the value of the textfield needs to be passed to the first window.
I think the best method for that is a simple Delegate. I tried that but i can't change the label in the first window using the second window..
The delegate however seems to work as i can call methods from the other class and send data to it. It just won't change the label.
As this is my first try on Delegates, im pretty sure I've done something stupid here^^
or is there a better solution? Can't be to complicated to change a label from an second window.. right?
ViewController.h (FirstController)
#import <Cocoa/Cocoa.h>
#class ViewController;
#protocol ViewControllerDelegate
-(void)sayHello:(ViewController *)ViewController;
#end
#interface ViewController : NSViewController
{
IBOutlet NSTextField *txtlabel;
}
#property (nonatomic, assign) id delegate;
-(void)helloDelegate;
-(void)reciveVar:(NSString*)strvar;
#end
ViewController.m (FirstController)
#import "ViewController.h"
#implementation ViewController
#synthesize delegate;
-(id)init {
self = [super init];
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
txtlabel.stringValue=#"TEST";
}
-(void)helloDelegate
{
[delegate sayHello:self];
}
-(void)reciveVar:(NSString*)strvar
{
NSLog(#"recived: %#", strvar);
txtlabel.stringValue=strvar; // DOSENT WORK!!
}
#end
secondController.h
#import <Cocoa/Cocoa.h>
#import "ViewController.h"
#interface secondController : NSViewController <ViewControllerDelegate>
{
IBOutlet NSTextField *txtfield;
}
-(IBAction)submit:(id)sender;
#end
secondController.m
#import "firstController.h"
#implementation secondController
-(void)viewDidLoad
{
[super viewDidLoad];
ViewController *custom = [[ViewController alloc] init];
// assign delegate
custom.delegate = self;
[custom helloDelegate];
}
-(void)sayHello:(ViewController *)ViewController
{
NSLog(#"Hiya!");
}
-(IBAction)submit:(id)sender
{
NSString *txtval= txtfield.stringValue;
NSLog(#"submit: %#", txtval);
ViewController *custom = [[ViewController alloc] init];
// assign delegate
custom.delegate = self;
[custom reciveVar:txtval];
}
#end
LOG Output:
Hiya!
submit: test
recived: test
(so i guess the delegate works..)
SOLVED. (Thanks to Phillip Mills)
NSNotification is way simpler and efficient than Delegates in this case.
ViewController.m
[...]
- (void)viewDidLoad
{
[super viewDidLoad];
txtlabel.stringValue=#"TEST";
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(handleUpdatedData:)
name:#"DataUpdated"
object:nil];
}
-(void)handleUpdatedData:(NSNotification *)notification
{
NSLog(#"recieved %#", notification);
txtlabel.stringValue=[notification object];
}
secondController.m
-(IBAction)submit:(id)sender
{
NSString *txtval= txtfield.stringValue;
NSLog(#"submit: %#", txtval);
[[NSNotificationCenter defaultCenter] postNotificationName:#"DataUpdated"
object:txtval];
}

Calling Function from RootViewController

How to call a RootViewController function from FirstViewController?
I'm using Xcode 4.6 with storyboard.
RootViewController.m:
-(void)openMenu
{
...
}
FirstViewController:
- (IBAction)btnMenu:(id)sender {
RootViewController *root = [[RootViewController alloc] init];
[root openMenu]; // No visible #interface for 'RootViewController' declares the selector 'openMenu'
}
You have to declare the method in your header RootViewController.h. Example
- (void)openMenu;
A common practice for something like this is to use delegation. Your FirstViewController would have a delegate and then your RootViewController would set the delegate for the instance, and receive the information for the event.
FirstViewController.h
#protocol FirstViewDelegate;
#interface FirstViewController : UIViewController
#property (strong) id<FirstViewDelegate> delegate;
#end
#protocol FirstViewDelegate <NSObject>
- (void)openMenu;
#end
FirstViewController.m
- (IBAction)btnMenu:(id)sender {
[self.delegate openMenu];
}
MainViewController.h
#import "FirstViewController.h"
#interface RootViewController : UIViewController
<
FirstViewDelegate
>
MainViewController.m
-(IBAction)showFirstViewButtonClicked:(id)sender {
FirstViewController *firstViewController = [[FirstViewController alloc] init];
firstViewController.delegate = self;
[self presentViewController:firstViewController animated:YES completion:nil];
}
-(void)openMenu {
// this will be called when the btnMenu action is fired in the firstViewController
}

Perform segue from delegate method

I have a segmented control which when clicked the user will be forced to enter a password.
After a successful check the modal screen should dismiss and in the controller with the segmented control a method is called and a segue should be performed to another controller.
The segue itself works but not after the login check. I think this is a problem with the "self"...
Code of delegate class:
#protocol LoginUserControllerDelegate
- (void)proceedAfterLogin:(BOOL)proceedToNextController;
#end
#interface LoginUserController : UIViewController {
IBOutlet UITextField *loginPWD;
id<LoginUserControllerDelegate> _delegate;
}
#property (nonatomic, retain) UITextField *loginPWD;
#property (nonatomic, assign) id<LoginUserControllerDelegate> delegate;
- (void)checkLogindata; // checks for correct password
#end
#implementation LoginUserController
#synthesize loginPWD;
#synthesize delegate = _delegate;
- (void)checkLogindata {
...
if ([tempDBPWD isEqualToString:tempLoginPWD]) {
if (_delegate != nil) {
[self dismissModalViewControllerAnimated:YES];
[_delegate proceedAfterLogin:YES];
}
}
...
}
#end
The segmented controller with the method:
#interface StartViewController : UIViewController <LoginUserControllerDelegate> {
UISegmentedControl *segmentedControl;
LoginUserController *_loginUserController;
}
#property (nonatomic,retain) IBOutlet UISegmentedControl *segmentedControl;
#property (nonatomic, retain) LoginUserController *loginUserController;
- (IBAction)segmentedControlIndexChanged:(id)sender;
#end
#implementation StartViewController
#synthesize segmentedControl;
#synthesize loginUserController = _loginUserController;
- (IBAction)segmentedControlIndexChanged:(id)sender
{
if (self.segmentedControl.selectedSegmentIndex == 0) {
// get delegate
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
UIStoryboard *storyboard = appDelegate.window.rootViewController.storyboard;
LoginUserController *loginUserControllerView = [storyboard instantiateViewControllerWithIdentifier:#"LoginUserViewID"];
loginUserControllerView.delegate = self;
// now show screen
[self presentModalViewController:loginUserControllerView animated:YES];
} else {
}
}
- (void)proceedAfterLogin:(BOOL)proceedToNextController
{
if (proceedToNextController) {
// yes, correct login now perform the segue to the controller
[[self segmentedControl] setSelectedSegmentIndex:UISegmentedControlNoSegment];
[self performSegueWithIdentifier:#"NextControllerSegueID" sender:self];
}
}
#end
I think the [self performSegueWithIdentifier:#"NextControllerSegueID" sender:self]; is the problem, because self is not correct. Is this where the error arises and how can I achieved my desired behaviour?
You're close, but you need to return to the delegate, and then call dismissModalViewControllerAnimated:YES. A modal controller can't dismiss itself, so you need to do your login, call back to the delegate, and have the delegate dismiss the modal controller.