I'm just starting to learn Objective-C and I'm not 100% on all the syntax yet, and I think that might be where I'm having trouble, then again I'm not sure. I'm trying to get one view controller to send a message to its parent/callee view controller. I have it set up like this:
//ParentViewController.h
#import "SubViewController.h"
#interface ParentViewController : UIViewController <SubViewControllerDelegate>
- (void) sendMessageToParent:(NSInteger)num;
#end
This is the implementation:
//ParentViewController.m
#implementation ParentViewController
- (void) sendMessageToParent:(NSInteger)num
{
NSLog(#"Message is %d", num);
}
- (void) buttonPushed
{
[self performSegueWithIdentifier:#"SubView" sender:sender];
}
#end
Here's the other view controller setup:
//SubViewController.h
#protocol SubViewControllerDelegate <NSObject>
- (void) sendMessageToParent:(NSInteger)num;
#end
#interface SubViewController : UIViewController
#property (nonatomic, weak) id <SubViewController> delegate;
#end
And implementation:
//SubViewController.m
#implementation SubViewController
#synthesize delegate;
- (void) something
{
[self.delegate sendMessageToParent:4];
[self.dismissViewControllerAnimated:YES completion:nil];
}
Appreciate any help, thanks.
You need to add to ParentViewController:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"SubView"])
{
SubViewController *vc = [segue destinationViewController];
vc.delegate = self;
}
}
You need to add handler for prepareForSegue and set .delegate properly there. I don't think your SubviewController has delegate set to the parent one.
Looks like you're not setting SubViewController's delegate to SuperViewController. You'd do this typically when you instantiate SubViewController. e.g. subViewController.delegate = self
ParentViewController.h
#interface ParentViewController : UIViewController
#end
ParentViewController.m
#implementation ParentViewController <SubViewControllerDelegate> // Better to place this in .m than .h
#pragma mark - SubViewController Delegate
- (void)sendMessageToParent:(NSInteger)num
{
NSLog(#"Message is %d", num);
}
- (void)buttonPushed
{
[self performSegueWithIdentifier:#"SubView" sender:sender];
}
#end
SubViewController.h
#protocol SubViewControllerDelegate <NSObject>
- (void)sendMessageToParent:(NSInteger)num;
#end
#interface SubViewController : UIViewController
#property (nonatomic, weak) id<SubViewController> delegate;
#end
SubViewController.m
#implementation SubViewController
// #synthesize delegate; // Not necessary, old fashioned
- (void)something
{
// Set a breakpoint here and step through, you're not setting your delegate, so this conditional is not being hit
if (self.delegate && [self.delegate respondsToSelector:#selector(sendMessageToParent:)])
{
[self.delegate sendMessageToParent:4];
}
[self.dismissViewControllerAnimated:YES completion:nil];
}
Related
On a button press, I am trying to send data from Collection View Controller to my View Controller. Here is what I have so far:
CollectionViewController.h
#import <UIKit/UIKit.h>
#class CollectionViewController;
#protocol CollectionViewDelegate <NSObject>
-(void) sendTest;
#end
#interface CollectionViewController : UICollectionViewController
#property (nonatomic, weak) id<CollectionViewDelegate> deligate;
#end
CollectionViewController.m
-(void) viewDidLoad {
[super viewDidLoad];
}
...
NSLog(#"check");
[self.deligate sendTest];
NSLog(#"called");
FooViewController.m
#import "CollectionViewController.h"
#interface FooViewController () <CollectionViewDelegate> {}
#end
#implementation FooViewController
- (void)viewDidLoad {
[super viewDidLoad];
CollectionViewController *controler = [[CollectionViewController alloc] init];
controler.deligate = self;
}
- (void) sendTest {
NSLog(#"Delegates are great!");
}
Unfortunaly when I call [self.deligate sendTest]; nothing happens. I know it is called, because I get the check, called logs.
The main wrong thing is that you are creating a CollectionViewController yourself, but you shouldn't. The CollectionViewController that you want is instantiated automagically by the Storyboard. How to find this view controller?
1 - Catch it during the segue in FooViewController:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
CollectionViewController *collectionViewController =(CollectionViewController *) segue.destinationViewController;
collectionViewController.deligate = self;
}
2 - Find it in within the child view controllers in FooViewController
self.childViewControllers
Does it help you?
I have a UIViewController several segues deep that when the use is finished, should unwind and take them back to the DashboardViewController.
I created the unwindToDashboard method in the Dashboard and hooked a button up to the Exit in my FinishViewController. So that when its clicked will fire the unwind action.
That works fine.
But I need to pass back data to the Dashboard from the FinishViewController.
So I created a delegate ProcessDataDelegate for the FinishViewController and made the Dashboard conform to it.
However, the delegate method in the Dashboard is NOT called.
Can anyone tell me what I have done wrong?
DashboardViewController.m
#import "FinishViewController.h"
#interface DashboardViewController () <ProcessDataDelegate>{
FinishViewController *fm;
}
#end
#implementation DashboardViewController
- (void)viewDidLoad {
[super viewDidLoad];
if(!fm){
fm = [[FinishViewController alloc] init];
}
fm.delegate = self;
}
- (IBAction)unwindToDashboard:(UIStoryboardSegue *)unwindSegue {
//empty
}
#pragma mark PROTOCOL METHODS
-(void) didFinishWithResults:(NSDictionary*) dictionary{
NSLog(#"Dashboard method called didFinishWithResults");
}
#end
FinishViewController.h
#class FinishViewController;
#protocol ProcessDataDelegate <NSObject>
#required
- (void) didFinishWithResults: (NSDictionary*)dictionary;
#end
#interface FinishViewController : UIViewController
#property (nonatomic, weak) id <ProcessDataDelegate> delegate;
#end
FinishViewController.m
#interface FinishViewController ()
#end
#implementation FinishViewController
- (void)viewDidLoad {
[super viewDidLoad];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
NSLog(#"fired via the button to the exit--- Segue: %#", [segue identifier]);
[delegate didFinishWithResults:nil ];
}
#end
You need pass your delegate in prepareForSegue method of your DashboardViewController, there get the destinationViewController and cast to FinishViewController if the identifier is equal to your expected segue identifier
Something like this
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
NSLog(#"fired via the button to the exit--- Segue: %#", [segue identifier]);
if([[segue identifier] isEqualToString:#"YourSegueIdentifier"])
{
((FinishViewController*)[segue destinationViewController]).delegate = self
}
}
I am trying yo pass data of two textfields in secondViewController to ViewController and set text of labels in ViewController.
But the delegate method for passing data is not being called. I have checked it by putting break point. Hence label text is not changing.
SecondViewController.h
#import <UIKit/UIKit.h>
#class SecondViewController;
#protocol SecondViewDelegate <NSObject>
-(void)getText1:(NSString*)str1 andText2:(NSString*)str2;
#end
#interface SecondViewController : UIViewController<UITextFieldDelegate>
#property (weak, nonatomic) IBOutlet UITextField *textField1;
#property (weak, nonatomic) IBOutlet UITextField *textField2;
#property (weak) id<SecondViewDelegate>delegate;
#end
SecondViewController.m
#import "SecondViewController.h"
#interface SecondViewController ()
#end
#implementation SecondViewController
#synthesize delegate=_delegate;
- (void)viewDidLoad {
[super viewDidLoad];
self.textField1.delegate=self;
self.textField2.delegate=self;
[self.textField1 becomeFirstResponder];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(BOOL)textFieldShouldReturn:(UITextField *)textField
{
if ( textField == self.textField1 ) { [self.textField1 resignFirstResponder]; [self.textField2 becomeFirstResponder]; }
else if ( textField == self.textField2) {
[_delegate getText1:self.textField1.text andText2:self.textField2.text];
NSLog(#"%#",self.textField1.text);
[self.navigationController popToRootViewControllerAnimated:YES];
}
return YES;
}
#end
View Controller.h
#import <UIKit/UIKit.h>
#import "SecondViewController.h"
#interface ViewController : UIViewController<SecondViewDelegate>
-(void)getText1:(NSString *)str1 andText2:(NSString *)str2;
#end
View Controller.m
#import "ViewController.h"
#interface ViewController ()
#property (weak, nonatomic) IBOutlet UILabel *label1;
#property (weak, nonatomic) IBOutlet UILabel *label2;
#end
#implementation ViewController
#synthesize label1;
#synthesize label2;
- (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)onClick:(id)sender {
SecondViewController* sv= [[SecondViewController alloc] init];
sv.delegate=self;
[self performSegueWithIdentifier:#"moveToSecondController" sender:self];
}
-(void)getText1:(NSString *)str1 andText2:(NSString *)str2{
[label1 setText:str1];
[label2 setText:str2];
}
#end
The problem is that you've created two SecondViewController objects and made your ViewController the delegate of the wrong one.
This: [[SecondViewController alloc] init] creates an object in code. This: [self performSegueWithIdentifier:#"moveToSecondController" sender:self] creates an object from a storyboard definition.
Don't bother creating the first one, just perform the segue. Then, implement the prepareForSegue method and set your delegate there, using the destination controller (which will be the correct SecondViewController).
Try setting your delegate in prepareForSegue method like:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// Make sure your segue name in storyboard is the same as this line
if ([[segue identifier] isEqualToString:#"YOUR_SEGUE_NAME_HERE"])
{
// Get reference to the destination view controller
SecondViewController *vc = [segue destinationViewController];
vc.delegate=self;
}
}
You don't need to declare your delegate method in ViewController.h. It has already been done in SecondViewController.h as the delegate method.
import
import "SecondViewController.h"
#interface ViewController : UIViewController
// Remove this method in ViewController.h file this is call as a simple method for ViewController class
-(void)getText1:(NSString *)str1 andText2:(NSString *)str2;
#end
I'm having trouble figuring out why I'm getting a nil delegate for this call. It seems like I'm setting the delegate just fine.
LogoutViewController.h
#protocol SomeNewDelegate <NSObject>
#required
- (void)someMethod;
#end
#interface LogoutViewController : UIViewController
#property (nonatomic, weak) id<SomeNewDelegate> delegate;
LogoutViewController.m
- (IBAction)logoutButtonTapped:(id)sender {
NSLog(#"logout tapped");
[self.delegate someMethod];
[self dismissViewControllerAnimated:YES completion:nil];
}
MainViewController.m
#interface MainViewController () <UIScrollViewDelegate, SomeNewDelegate>
#property (nonatomic, strong) LogoutViewController *logoutVC;
#end
#implementation MainViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.logoutVC.delegate = self;
}
- (void)someMethod {
NSLog(#"someMethod");
}
someMethod never gets called and I don't see why the delegate is nil. Any help?
Use below code in viewDidload
LogoutViewController *logoutVC = [[LogoutViewController alloc]init];
logoutVC.delegate = self;
Remove LogoutViewController from property.
I have used this and its working fine.
Hope its working for you.
Edited code in .h file
#protocol syncDataDelegate <NSObject>
#required
- (void) offlineSyncProcess;
#end
#interface LoginViewController : UIViewController
{
id <syncDataDelegate> syncDelegate;
}
#property (retain) id syncDelegate;
in .m file
#implementation LoginViewController
{
// your code
}
#synthesize syncDelegate;
- (IBAction)logoutButtonTapped:(id)sender {
NSLog(#"logout tapped");
[syncDelegate offlineSyncProcess];
}
You can call delegate method from here in LoginViewController.m file from any method.
in My Delegate implementation
in .m file
#interface MainViewController ()<syncDataDelegate>
#end
#implementation MainViewController
- (void)viewDidLoad
{
[super viewDidLoad];
LoginViewController *LVC = [[LoginViewController alloc]init];
LVC.syncDelegate = self;
}
now use the delegate methode here
- (void) offlineSyncProcess
{
// your code here
}
this code is working in my project, check this in your project.
Make sure your logoutVC is not nil when you try to set the delegate property for it.
You can implement the setDelegate method in your LogoutViewController.m. Then use break point to make sure it is invoked.
Delegate is nil because your logoutVC is nil, you haven't allocated memory to the logoutvc property.
Just before self.logoutVC.delegate = self
Add following code
self.logoutVC = [[LogoutViewController alloc]init];
Everything will start working automatically.
I'm new to iOS programming and I can't get this simple concept to work -- I just want the popup controller to be able to call a method and send data on the parent controller. Can anyone spot what I'm doing wrong here?
in DetailViewController.h
#import <UIKit/UIKit.h>
#import "Employee.h"
#import "CompleteViewController.h"
#class EmployeesTVC;
#interface DetailViewController : UIViewController <UISplitViewControllerDelegate, UIPopoverControllerDelegate>
#property (strong) UIPopoverController *popController;
-(IBAction)completeButtonPressed:(id)sender;
#end
in DetailViewController.m (took out irrelevant parts)
#implementation DetailViewController {
__weak UIPopoverController *completePopover;
}
// ...
#pragma mark - Complete / Score popover methods
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
NSLog(#"preparing for segue");
UIStoryboardPopoverSegue *popoverSegue = (UIStoryboardPopoverSegue *)segue;
UIPopoverController *scorePopoverController = [popoverSegue popoverController];
[scorePopoverController setDelegate:self];
self.popController = scorePopoverController;
}
- (IBAction)completeButtonPressed:(id)sender {
if (completePopover) {
[completePopover dismissPopoverAnimated:YES];
} else {
[self performSegueWithIdentifier:#"showScorePopover" sender:sender];
}
}
- (void) scoreAssigned:(NSString *)score {
NSLog(score);
NSLog(#"Score Assigned");
}
// ...
#end
CompleteViewController.h (the popup view controller)
#import <UIKit/UIKit.h>
#protocol CompleteViewDelegate <NSObject>
- (void)scoreAssigned:(NSString *)score;
#end
#interface CompleteViewController : UIViewController
#property (nonatomic, assign) id<CompleteViewDelegate> delegate;
- (IBAction)okButtonPressed:(id)sender;
#end
CompleteViewController.m
#import "CompleteViewController.h"
#implementation CompleteViewController
#synthesize delegate;
- (IBAction)okButtonPressed:(id)sender {
NSLog(#"OK Button Pressed");
[delegate scoreAssigned:#"100"];
}
#end
Is your first NSLog statement firing? "OK Button Pressed". If not, make sure (IBAction)okButtonPressed is wired up in Interface Builder. If so, but a break point on [delegate scoreAssigned:#"100"]; and hover over "delegate" with your mouse to see if it's nil, just to see if the delegate was successfully assigned. If this doesn't fix it, let us know exactly where you're getting to before things stop working.
Properly presenting a UIPopoverController
[completePopover setDelegate:self];
[completePopover presentPopoverFromBarButtonItem:yourButtonItem permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
//or if you don't have a bar button item
[completePopover presentPopoverFromRect:CGRectMake(0.0, 0.0, 0.0, 0.0) inView:yourTargetView permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
Keep in mind that inView can be any subclass of UIView, like UIButton for instance.