I am trying to set up a system of ViewControllers and navigate between them. I am trying to navigate between DefaultViewController and CreateViewController. I am new to iOS programming, so I am having a hard time figuring this out. I have mainly been trying to use code from the Utility App template. It would be great if someone could spot my mistake!
The log CreateViewController: cancel is reached when I click on my Cancel-button, but DefaultViewController: createViewControllerDidFinish is not.
This is the relevant code:
DefaultViewController.h
#import <UIKit/UIKit.h>
#import <Social/Social.h>
#import "CreateViewController.h"
#interface DefaultViewController : UIViewController <CreateViewControllerDelegate, UIWebViewDelegate> {
...
}
#property (strong, nonatomic) UIWebView *webView;
- (IBAction)create:(id)sender;
#end
CreateViewController.h
#import <UIKit/UIKit.h>
#import <Social/Social.h>
#class CreateViewController;
#protocol CreateViewControllerDelegate
- (void)createViewControllerDidFinish:(CreateViewController *)controller;
#end
#interface CreateViewController : UIViewController <UIWebViewDelegate> {
...
}
#property (weak, nonatomic) id <CreateViewControllerDelegate> delegate;
- (IBAction)cancel:(id)sender;
- (IBAction)submit:(id)sender;
#end
DefaultViewController.m
#import "AppDelegate.h"
#import "DefaultViewController.h"
...
#implementation DefaultViewController
...
#pragma mark - CreateViewController
- (void)createViewControllerDidFinish:(CreateViewController *)controller {
NSLog(#"DefaultViewController: createViewControllerDidFinish");
[self.navigationController dismissViewControllerAnimated:YES completion:nil];
}
- (IBAction)create:(id)sender {
CreateViewController *vc2 = [[CreateViewController alloc] init];
[self.navigationController pushViewController:vc2 animated:YES];
}
#end
CreateViewController.m
#import "AppDelegate.h"
#import "CreateViewController.h"
...
#implementation CreateViewController
...
#pragma mark - Actions
- (IBAction)cancel:(id)sender {
NSLog(#"CreateViewController: cancel");
[self.delegate createViewControllerDidFinish:self];
}
- (IBAction)submit:(id)sender {
[webView stringByEvaluatingJavaScriptFromString:#"EntryCreate.submit();"];
}
#end
Using Navigation Controller,when you push a view controller you have to pop to dismiss
- (IBAction)cancel:(id)sender {
NSLog(#"CreateViewController: cancel");
[self.navigationController popViewControllerAnimated:YES];
}
No need for the controller instance Nav Controller is basically a stack and when you pop it removes from the top of the stack and move to the previous viewcontroller from where it is pushed.
Related
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];
}
I have a VC of custom type LVSBBSettingsViewController for user settings. The VC is presented by a main menu in LVSMainViewController. The main VC sets the values of the controls in the settings VC programatically. However, when the settings view appears, the controls all revert to the values assigned to them in the storyboard.
I am using delegation to close the settings view and to pass data from the settings VC back to the main VC when it closes. But I don't think that's what's causing the problem since the same thing happens even if I remove that.
What's causing this? I have a feeling I'm missing something really simple here...
LVSBBSettingsViewController.h:
#import <UIKit/UIKit.h>
#class LVSBBSettingsViewController;
#pragma mark LVSBBSettingsViewController Delegate
#protocol LVSBBSettingsViewControllerDelegate <NSObject>
- (void)settingsViewControllerDidCancel:(LVSBBSettingsViewController *)controller;
- (void)settingsViewControllerDidSave:(LVSBBSettingsViewController *)controller;
#end
#pragma mark LVSBBSettingsViewController
#interface LVSBBSettingsViewController : UITableViewController
#property (nonatomic, weak) id <LVSBBSettingsViewControllerDelegate> delegate;
#property (weak, nonatomic) IBOutlet UISwitch *showBranchVarLabelsSwitch;
#property (weak, nonatomic) IBOutlet UISwitch *useAnimationSwitch;
#property (weak, nonatomic) IBOutlet UISwitch *showAllNodesSwitch;
#property (weak, nonatomic) IBOutlet UILabel *tempLabel;
- (IBAction)cancel:(id)sender;
- (IBAction)done:(id)sender;
#end
LVSBBSettingsViewController.m:
#import "LVSBBSettingsViewController.h"
#interface LVSBBSettingsViewController ()
#end
#implementation LVSBBSettingsViewController
// ... Xcode-generated stuff ...
- (IBAction)cancel:(id)sender
{
[self.delegate settingsViewControllerDidCancel:self];
}
- (IBAction)done:(id)sender
{
[self.delegate settingsViewControllerDidSave:self];
}
#end
LVSBBMainViewController.h:
#import <UIKit/UIKit.h>
#import "LVSBBSettingsViewController.h"
#interface LVSMainViewController : UIViewController <LVSBBSettingsViewControllerDelegate>
#end
LVSBBMainViewController.m:
#import "LVSMainViewController.h"
#import "LVSBBMasterViewController.h"
#interface LVSMainViewController ()
#end
#implementation LVSMainViewController
{
LVSBBMasterViewController *bbmvc;
}
// ...
- (void)viewDidLoad
{
[super viewDidLoad];
// Get main storyboard
UIStoryboard *st = [UIStoryboard storyboardWithName:[[NSBundle mainBundle].infoDictionary objectForKey:#"UIMainStoryboardFile"] bundle:[NSBundle mainBundle]];
// Instantiate bbmvc
bbmvc = [st instantiateViewControllerWithIdentifier:#"BBMasterViewControllerStoryboard"];
// Initialize settings
bbmvc.showBranchVarLabels = YES;
bbmvc.useAnimation = YES;
bbmvc.showAllNodes = NO;
}
...
#pragma mark LVSBBSettingsViewController Delegate
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"ShowSettings"])
{
// Get pointer to settings VC
UINavigationController *navigationController = segue.destinationViewController;
LVSBBSettingsViewController *settingsViewController = [navigationController viewControllers][0];
// Set delegate
settingsViewController.delegate = self;
// Populate settings VC
// (same problem occurs if I replace right-hand sides of next 3 lines with NO;)
settingsViewController.showBranchVarLabelsSwitch.on = bbmvc.showBranchVarLabels;
settingsViewController.useAnimationSwitch.on = bbmvc.useAnimation;
settingsViewController.showAllNodesSwitch.on = bbmvc.showAllNodes;
settingsViewController.tempLabel.text = #"HELLO";
}
}
- (void)settingsViewControllerDidCancel:(LVSBBSettingsViewController *)controller
{
[self dismissViewControllerAnimated:YES completion:nil];
}
- (void)settingsViewControllerDidSave:(LVSBBSettingsViewController *)controller
{
// Set settings in bbmvc
bbmvc.showBranchVarLabels = controller.showBranchVarLabelsSwitch.on;
bbmvc.useAnimation = controller.useAnimationSwitch.on;
bbmvc.showAllNodes = controller.showAllNodesSwitch.on;
[self dismissViewControllerAnimated:YES completion:nil];
}
#end
UPDATE: As a workaround, I added properties in LVSBBSettingsViewController that match the properties in LVSMainViewController. In prepareForSegue:sender:, I set those properties instead of setting the controls directly. Then in viewDidLoad in LVSBBSettingsViewController, I set the control values based on the properties. This seems to work. Still not sure why I can't set the control values directly, though.
So I have 3 views as follows: viewController >> viewController2 >> viewController3.
In viewController3 I have created a Delegate Protocol. The protocol method is a simple method that prints out an NSLog.
When I call the delegates from ViewController3, only its parent (viewController2 ) responds not the (first) viewController. There are no errors.I think problem has got something to do with [v2 setDelegate:self]; in the viewController.m file.
Nevertheless,[self.v3 setDelegate:self]; works fine in ViewController2.m file.
Why does the (first) viewController delegate not respond ? Do delegates only work with its immediate child ??
> **ViewController.h**
#import <UIKit/UIKit.h>
#import "ViewController2.h"
#import "ViewController2.h"
#interface ViewController : UIViewController <PassData>{
ViewController2 *v2;
}
#property (strong, nonatomic) ViewController2 *v2;
> Blockquote
- (IBAction)button:(id)sender;
#end
> **ViewController.M**
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize v2;
- (IBAction)button:(id)sender {
v2 = [[ViewController2 alloc]initWithNibName:#"ViewController2" bundle:nil];
[v2 setDelegate:self];
[self.view addSubview:v2.view];
}
-(void)print: (BOOL)success;{
if (success == YES) {
NSLog(#"ViewController called");
}
}
#end
> > ViewController2.h
#import <UIKit/UIKit.h>
#import "ViewController3.h"
#interface ViewController2 : UIViewController <PassData> {
ViewController3 *v3;
}
#property (strong, nonatomic)ViewController3 *v3;
#property (retain) id delegate;
- (IBAction)button:(id)sender;
#end
ViewController2.m
#import "ViewController2.h"
#interface ViewController2 ()
#end
#implementation ViewController2
#synthesize v3,delegate;
- (IBAction)button:(id)sender {
v3 = [[ViewController3 alloc]initWithNibName:#"ViewController3" bundle:nil];
[self.v3 setDelegate:self];
[self.view addSubview:v3.view];
}
-(void)print: (BOOL)success;{
if (success == YES) {
NSLog(#"ViewController2 called");
}
}
#end
> ViewController3.h
#import <UIKit/UIKit.h>
#protocol PassData <NSObject>
#required
-(void)print:(BOOL)success;
#end
#interface ViewController3 : UIViewController {
id<PassData> delegate;
}
#property (retain) id delegate;
- (IBAction)callButton:(id)sender;
#end
ViewController3.m
#import "ViewController3.h"
#interface ViewController3 ()
#end
#implementation ViewController3
#synthesize delegate;
- (IBAction)callButton:(id)sender {
// call all delegates
[[self delegate]print:YES];
}
#end
v2 doesn't have a method "print", that's a protocol method of v3 -- you can't chain delegate messages like this. If you want multiple controllers to respond to something in another controller, then you should use an NSNotification -- any number of objects can register to receive a notification.
i try a simple Delegate but the method won't fire. Here is my code:
The view with the protocol and a button which should trigger the delegate:
ViewController.h
#import <UIKit/UIKit.h>
#protocol InitStackDelegate <NSObject>
#required
-(void)initstack:(NSInteger)amount;
#end
#interface ViewController : UIViewController{
IBOutlet UITextField *amountTextField;
__unsafe_unretained id<InitStackDelegate> delegate;
}
- (IBAction)init:(id)sender;
#property (nonatomic,assign)id delegate;
#end
ViewController.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize delegate;
- (IBAction)init:(id)sender {
//send the delegate
[delegate initstack:[amountTextField.text intValue]];
}
AppDelegate.h
#import <UIKit/UIKit.h>
#import "ViewController.h"
#interface AppDelegate : UIResponder <UIApplicationDelegate,InitStackDelegate> {
}
#property (strong, nonatomic) UIWindow *window;
#property (strong,nonatomic) ViewController *myView;
#end
AppDelegate.m
#import "AppDelegate.h"
#implementation AppDelegate
#synthesize window;
#synthesize myView;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions: (NSDictionary *)launchOptions
{
// Override point for customization after application launch.
//..... push second controller into navigation stack
myView.delegate = self;
return YES;
}
...
#pragma mark Delegate Method
-(void)initstack:(NSInteger)amount{
NSInteger test;
}
#end
When i hit the button i get to (IBAction) init but then the delegate do nothing. I set a breakpoint in AppDelegate.m but it is never reached. Any help?
thx
Mario
In you App Delegate, when you set myView.delegate=self myView doesn't actually point to anything!
You need to set myView to point to your ViewController.
Use this in didFinishLaunchingWithOptions
myView = (ViewController *)self.window.rootViewController;
myView.delegate = self;
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.