I have a ViewController class with the following structure:
Header file:
#protocol GCStageViewControllerDelegate;
#interface GCStageViewController : UIViewController <UIActionSheetDelegate, UITextFieldDelegate, UIImagePickerControllerDelegate> {
id <GCStageViewControllerDelegate> delegate;
...
}
#property (nonatomic, retain) id <GCStageViewControllerDelegate> delegate;
...
#end
#protocol GCStageViewControllerDelegate
- (void)gcStageViewContollerDidFinish:(GCStageViewController *)controller withGCStageItem:(GCStageItem *)item;
#end
Implementation file:
- (void)viewDidLoad {
...
stageInputTextField.delegate = self; // works
...
}
- (void)takePicture {
UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
[imagePicker setSourceType:UIImagePickerControllerSourceTypeCamera];
} else {
[imagePicker setSourceType:UIImagePickerControllerSourceTypePhotoLibrary];
}
imagePicker.delegate = self; // here I get the error
[self presentModalViewController:imagePicker animated:YES];
}
If I set the delegate in the takePicture method I get the following warning:
Assigning to 'id<UINavigationControllerDelegate,UIImagePickerControllerDelegate>' from incompatible type 'GCStageViewController *'
Any ideas what's wrong?
Apparently UIImagePicker needs you to also implement the UINavigationControllerDelegate protocol. See the documentation, where it clearly shows that the delegate should conform to both. :-)
Luckily, all of the methods in that protocol are optional, so all you need to do it pretend:
// change this
#interface GCStageViewController : UIViewController <UIActionSheetDelegate, UITextFieldDelegate, UIImagePickerControllerDelegate> {
// to this
#interface GCStageViewController : UIViewController <UIActionSheetDelegate, UITextFieldDelegate, UIImagePickerControllerDelegate, UINavigationControllerDelegate> {
The UIImagePickerControllerDelegate actually requires conformation to two protocols: UIImagePickerControllerDelegate and UINavigationControllerDelegate. Conform to UINavigationControllerDelegate in the header and the error will disappear.
#interface GCStageViewController : UIViewController <UIActionSheetDelegate, UITextFieldDelegate, UIImagePickerControllerDelegate, UINavigationControllerDelegate>
Related
Trying to open a view controller from an SKScene.
Found https://stackoverflow.com/a/20072795/1686319 very helpful, but i get an error when trying to set the delegate from the view controller.
No visible #interface for 'SKScene' declares the selector
'setDelegate:'
EABMyScene.h
#import <SpriteKit/SpriteKit.h>
#protocol EABMySceneDelegate <NSObject>
-(void)doSomething;
#end
#interface EABMyScene : SKScene {
}
#property (nonatomic, weak) id <EABMySceneDelegate> delegate;
#end
Any idea?
Update:
EABViewController.h
#import <UIKit/UIKit.h>
#import <SpriteKit/SpriteKit.h>
#protocol ViewControllerDelegate <NSObject>
-(void) openTweetSheet;
#end
#interface EABViewController : UIViewController <ViewControllerDelegate>
#end
EABViewController.m
#import "EABViewController.h"
#import "EABMyScene.h"
#implementation EABViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Configure the view.
SKView * skView = (SKView *)self.view;
skView.showsFPS = YES;
skView.showsNodeCount = YES;
// Create and configure the scene.
SKScene * scene = [EABMyScene sceneWithSize:skView.bounds.size];
scene.scaleMode = SKSceneScaleModeAspectFill;
[scene setDelegate:self];
// Present the scene.
[skView presentScene:scene];
}
-(void)openTweetSheet
{
NSLog(#"Open Tweet Delegate Method");
}
EABMyScene.h
#import <SpriteKit/SpriteKit.h>
#interface EABMyScene : SKScene {
}
#property (nonatomic, weak) id <ViewControllerDelegate> delegate;
#end
Error: No visible #interface for 'SKScene' declares the selector 'setDelegate:'
Class SKScene does not have a property named delegate, so the statement
[scene setDelegate:self];
produced the compiler error. To fix this issue, cast scene to your SKScene subclass EABMyScene:
[(EABMyScene *)scene setDelegate:self];
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
}
I'm studing protocol and delegates using an Example! When I try to re create this example I notice that this condition is not respected:
if([delegate respondsToSelector:#selector(amountEntered:)]) {blabla}
where is the mistake? Scripts:
First View .h
#import <UIKit/UIKit.h>
#import "EnterAmountViewController.h"
#interface DelegateExampleViewController : UIViewController <EnterAmountDelegate>{
IBOutlet UILabel *amountLabel;
}
-(IBAction)changeAmountPressed;
#end
First View .m
#import "DelegateExampleViewController.h"
#implementation DelegateExampleViewController
-(IBAction)changeAmountPressed
{
EnterAmountViewController * enterAmountVC = [[EnterAmountViewController alloc]init];
enterAmountVC.delegate = self;
}
-(void)amountEntered:(NSInteger)amount
{
amountLabel.text = [NSString stringWithFormat:#"%i" , amount];
}
#end
Second View .h
#import <UIKit/UIKit.h>
#protocol EnterAmountDelegate <NSObject>
-(void)amountEntered:(NSInteger)amount;
#end
#interface EnterAmountViewController : UIViewController {
IBOutlet UITextField *amountTextField;
id<EnterAmountDelegate> delegate;
}
-(IBAction)savePressed;
#property(nonatomic,retain) id<EnterAmountDelegate> delegate;
#end
Second View .m
#import "EnterAmountViewController.h"
#import "DelegateExampleViewController.h"
#implementation EnterAmountViewController
#synthesize delegate;
- (void)viewDidLoad {
[super viewDidLoad];
amountTextField.text = #"";
[amountTextField becomeFirstResponder];
}
-(IBAction)savePressed
{
if([delegate respondsToSelector:#selector(amountEntered:)])
{
[delegate amountEntered:[amountTextField.text intValue]];
NSLog(#"rugg");
}
}
#end
Thanks in advance!
In the method:
-(IBAction)changeAmountPressed
{
EnterAmountViewController * enterAmountVC = [[EnterAmountViewController alloc]init];
enterAmountVC.delegate = self;
}
you are creating an instance of EnterAmountViewController on the stack as a local variable. This variable will be inaccessible at the end of the scope. So, when you execute savePressed you are doing it on a different object where you did not set delegate.
In other words, when you check
if([delegate respondsToSelector:#selector(amountEntered:)])
it returns NO because delegate is nil...
The correct way to set the delegate is using the prepareForSegue mechanism:
#implementation DelegateExampleViewController
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
[(EnterAmountViewController*)segue.destinationViewController setDelegate:self];
}
...
You do not need the changeAmountPressed method nor the relative binding.
I have a UIViewController which is embedded in a navigation controller and presented modally:
//UIViewController
AuthenticationController *auth = [[AuthenticationController alloc] init];
//UINavigationController
AuthRootController *navController = [[AuthRootController alloc]
initWithRootViewController:auth];
navController.navigationBar.topItem.title = #"Anmelden";
navController.delegate = self;
[self presentModalViewController:navController animated:YES];
RELEASE_SAFELY(navController);
However there is something wrong with the delegate I created within the AuthRootController class:
#protocol AuthRootControllerDelegate
#required
-(void)authRootControllerDidEnd:(UINavigationController *)sender;
#end
#interface AuthRootController : UINavigationController {
id<AuthRootControllerDelegate> delegate;
}
#property (nonatomic, assign) IBOutlet id delegate;
#end
And the implementation:
#implementation AuthRootController
#synthesize delegate;
-(void)userDidCancelController:(UINavigationController *)sender{
if (self.delegate && [self.delegate conformsToProtocol:#protocol(AuthRootControllerDelegate)]) {
[self.delegate authRootControllerDidEnd:sender];
}
}
#end
When I use the method
-(void)authRootControllerDidEnd:(UINavigationController *)sender
it is not triggered. Any ideas?
Have you declared that your delegate conforms to AuthRootControllerDelegate? The conformsToProtocol test looks at whether the delegate declares conformance, it doesn't do any sort of method-by-method check. So even if you've implemented authRootControllerDidEnd: on your delegate, conformsToProtocol can still return NO.
In your interface you aren't declaring it as implementing the delegate protocol, you need to modify your interface declaration like this:
#interface AuthRootController : UINavigationController<AuthRootControllerDelegate> {
According to the View Controller Programming Guide, delegation is the preferred method to dismiss a modal view.
Following Apple's own Recipe example, i have implemented the following, but keep getting warnings that the addNameController:didAddName method is not found...
NameDelegate.h
#protocol NameDelegate
- (void)addNameController:(AddName *)addNameController didAddName:(NSString *)name;
#end
AddName.h
#interface AddName : UIViewController {
UITextField *nameField;
id delegate;
}
- (IBAction)doneAction;
- (id)delegate;
- (void)setDelegate:(id)newDelegate;
#property (nonatomic, retain) IBOutlet UITextField *nameField;
#end
AddName.m
- (IBAction)doneAction {
[delegate addNameController:self didAddName:[nameField text]];
}
- (id)delegate {
return delegate;
}
- (void)setDelegate:(id)newDelegate {
delegate = newDelegate;
}
ItemViewController.h
#import "NameDelegate.h"
#interface ItemViewController : UITableViewController <NameDelegate>{
}
#end
ItemViewController.m
- (void)addItem:(id)sender {
AddName *addName = [[AddName alloc] init];
addName.delegate = self;
[self presentModalViewController:addName animated:YES];
}
- (void)addNameController:(AddName *)addNameController didAddName:(NSString *)name {
//Do other checks before dismiss...
[self dismissModalViewControllerAnimated:YES];
}
I think all the required elements are there and in the right place?
Thanks
You haven't specified that the delegate property of AddName has to conform to the NameDelegate protocol.
Use this code in AddName.h:
#import "NameDelegate.h"
#interface AddName : UIViewController {
UITextField *nameField;
id <NameDelegate> delegate;
}
#property(nonatomic, retain) IBOutlet UITextField *nameField;
#property(nonatomic, assign) id <NameDelegate> delegate;
- (IBAction)doneAction;
#end