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.
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'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.
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.
I am having trouble calling the the popoverControllerDidDismissPopover method in as much as I do not know where to put it and how to call it.
I have created a popover as follows -
// SettingsViewController.h
#import <UIKit/UIKit.h>
#import <QuartzCore/QuartzCore.h>
#import "ViewController.h"
#import "SharedData.h"
#import "PlayerPopUpVC.h"
#interface SettingsViewController : UIViewController <UITableViewDataSource, UIPopoverControllerDelegate> {
- (IBAction)popUp:(id)sender;
#property (strong, nonatomic) UIPopoverController *playerPopUpVC;
#property (strong, nonatomic) PlayerPopUpVC *popUp;
// SettingsViewController.m
#import "SettingsViewController.h"
- (IBAction)popUp:(id)sender {
UIButton *editPlayers = (UIButton *)sender;
if(self.playerPopUpVC) {
self.popUp= [[PlayerPopUpVC alloc] initWithNibName:#"PlayerPopUpVC" bundle:nil];
self.popUp=[[UIPopoverController alloc] initWithContentViewController:self.popUp];
}
[self.playerPopUpVC presentPopoverFromRect:[editPlayers frame] inView:[editPlayers superview] permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}
I know I have to set the delegate of my PopOver to self in order to call the method but cannot work out what the code is.
I have tried -
self.playerPopUpVC.delegate=self
but Xcode does not like it.
My popOver class looks like this -
// PlayerPopUpVC.h
#import <UIKit/UIKit.h>
#interface PlayerPopUpVC : UIViewController <UITableViewDataSource, UIPopoverControllerDelegate> {
}
// PlayerPopUpVC.m
#import "PlayerPopUpVC.h"
#interface PlayerPopUpVC ()
#end
- (void)viewDidLoad
{
[super viewDidLoad];
self.modalInPopover = NO;
self.contentSizeForViewInPopover = CGSizeMake(240, 400);
}
Any help would be most welcome. I have spent a week now trying to sort it.
First, you need to understand the delegate pattern, which seems that you dont fully understand yet.
The popover will be the one which will call the popoverControllerDidDismissPopover method on the delegate. You only have to implement the UIPopoverControllerDelegate protocol in your class and assign yourself as the delegate of the popover. Why do you say that XCode doesn't like it? please, provide more info.
Furthermore, you are making an incorrect assignment here:
self.popUp=[[UIPopoverController alloc] initWithContentViewController:self.popUp];
Edit: Provided more code to help with the error. Please, review the delegate pattern next time before making these questions.
Your SettingsController.m should have this instead:
- (IBAction)popUp:(id)sender {
UIButton *editPlayers = (UIButton *)sender;
if(!self.popUp) {
self.popUp= [[PlayerPopUpVC alloc] initWithNibName:#"PlayerPopUpVC" bundle:nil];
}
self.playerPopUpVC=[[UIPopoverController alloc] initWithContentViewController:self.popUp];
self.playerPopUpVC.delegate = self;
[self.playerPopUpVC presentPopoverFromRect:[editPlayers frame] inView:[editPlayers superview] permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}
- (void)popoverControllerDidDismissPopover:(UIPopoverController *)popoverController {
// Your code here
}