Sorry about the confusion.
What I want to do:
enter a string in a textfield in a view(EnterCommandViewController) and click save button, which will dismiss current view and go back to another view(DetectionViewController) and show the string in the UILabel in current view(DetectionViewController). So I have put define the delegate protocol in EnterCommandViewController, my question is that why the respondToSelector, which is used to check whether someone is listening does not work.
I am really a beginner in iOS, I am right now writing a delegate to send text got form UITextField to a UILabel, But I found that the respondToSelector cannot be called by using NSLog for testing.
Below is my code for reference:
EnterCommandViewController.h
#import <UIKit/UIKit.h>
#import "RscMgr.h"
#protocol EnterCommandDelegate <NSObject>
-(void) commandEntered:(NSString*)command;
#end
#interface EnterCommandViewController : UIViewController <RscMgrDelegate>
{
RscMgr* rscMgr;
__weak IBOutlet UITextField *inputTextField;
__unsafe_unretained id<EnterCommandDelegate> delegate;
}
-(void)sendMessage:(NSString*)message;
- (IBAction)cancelPressed;
- (IBAction)savePressed;
#property (nonatomic,assign)id delegate;
#end
EnterCommandViewController.m
#import "EnterCommandViewController.h"
#interface EnterCommandViewController () <UITextFieldDelegate>
{
#private
BOOL connected;
}
#end
#implementation EnterCommandViewController
#synthesize delegate;
- (void)viewDidLoad {
[super viewDidLoad];
rscMgr = [[RscMgr alloc] init];
[rscMgr setDelegate:self];
// Do any additional setup after loading the view, typically from a nib.
inputTextField.text=#"";
[inputTextField becomeFirstResponder];
}
-(void) viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
inputTextField.delegate = self;
}
-(void) viewWillDisappear:(BOOL)animated{
[super viewWillDisappear:animated];
inputTextField.delegate = nil;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)cancelPressed {
[self dismissViewControllerAnimated:YES completion:^{}];
}
- (IBAction)savePressed {
//is anyone listening
NSLog(#"the command is %#",inputTextField.text);
NSLog(#"Checking -- SomeMethod is listening");
if([delegate respondsToSelector:#selector(commandEntered:)]){
NSLog(#"SomeMethod is listening");
//send delegate function with the command entered by the user
[delegate commandEntered:inputTextField.text];
}
[self dismissViewControllerAnimated:YES completion:^{}];
}
DetectionViewController.h
#import <UIKit/UIKit.h>
#import "EnterCommandViewController.h"
#interface DetectionViewController : UIViewController <EnterCommandDelegate>{
__weak IBOutlet UILabel *showCommand;
}
- (IBAction)showSettings:(UIBarButtonItem *)sender;
#end
DetectionViewController.m
#import <Foundation/Foundation.h>
#import "DetectionViewController.h"
#implementation DetectionViewController
- (IBAction)showSettings:(UIBarButtonItem *)sender {
}
-(void) viewDidLoad{
[super viewDidLoad];
showCommand.text=#"";
EnterCommandViewController* enterCVC = [[EnterCommandViewController alloc] init];
enterCVC.delegate = self;
}
#pragma mark - EnterCommandDelegate function(s)
-(void) commandEntered:(NSString *)command{
// showCommand.text = command;
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(#"command: %#",command);
[self->showCommand setText:command];
});
}
#end
AppDelegate.m
#import "AppDelegate.h"
#interface AppDelegate ()
#end
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
return YES;
}
You are not setting the delegate properly.
EnterCommandViewController* enterCVC = [[EnterCommandViewController alloc] init];
enterCVC.delegate = self;
This is not the way of setting the delegate in your case, since you are not using the created instance of enterCVC, instead a new instance is created from the storyboard when you are transitioning toEnterCommandViewController `(From your comment its clear that you are using the storyboard for this).
So what you can do is you should the delegate from prepareForSegue in DetectionViewController like
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// Get reference to the destination view controller
EnterCommandViewController* enterCVC = [segue destinationViewController];
enterCVC.delegate = self;
}
Related
I have two UIViewControllers embedded in a UINavigationController. The first view controller has the following source code :
ViewController.h :
#import <UIKit/UIKit.h>
#import "ViewController_2.h"
#interface ViewController : UIViewController <HanselDelegate>
#property (strong, nonatomic) IBOutlet UILabel *TestLabel;
- (IBAction)ButtonClick:(id)sender;
#end
ViewController.m :
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (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)ButtonClick:(id)sender {
NSLog(#"To call the second UIViewController...");
[self performSegueWithIdentifier:#"idCallSecond" sender:self];
}
-(void)SetFirstLabel {
NSLog(#"To run the delegate method...");
_TestLabel.text = #"Hello from the second...";
}
#end
The second controller has the following code:
ViewController2.h :
#import <UIKit/UIKit.h>
#protocol HanselDelegate <NSObject>
-(void)SetFirstLabel;
#end
#interface ViewController_2 : UIViewController
#property (nonatomic, weak)id<HanselDelegate> delegate;
- (IBAction)Button2Click:(id)sender;
#end
ViewController2.m:
#import "ViewController_2.h"
#interface ViewController_2 ()
#end
#implementation ViewController_2
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)Button2Click:(id)sender {
if ([self.delegate respondsToSelector:#selector(SetFirstLabel)]) {
NSLog(#"To call the delegate method");
[self.delegate SetFirstLabel];
}
[self.navigationController popViewControllerAnimated:YES];
}
#end
If I press the button in ViewController2, the method SetFirstLabel doesn't get called. Why is it so? Did I forgot something?
You forgot to set the delegate in ViewController.m
set this in ViewController.m
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"idCallSecond"]) {
ViewController_2 * vc2 = [segue destinationViewController];
vc2.delegate = self;
}
}
Basically, I am now intend to use delegate to pass values between view controllers.
The flow of the view controllers is A -> B -> C using push segue.
When the user does some action in the "C" view controller, how to pass the value BACK to the first view controller, which is "A"?
In my code, "self.delegate" is always nil and the delegate method is never triggered.
Below is the code of the First VC and Third VC:
First VC .m:
#import "ViewController.h"
#import "ThirdViewController.h"
#interface ViewController ()<PassValueProtocal>
#property (weak, nonatomic) IBOutlet UILabel *myLabel;
#end
#implementation ViewController
{
ThirdViewController *thirdVC;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void) passValueBack:(NSString *)value
{
NSLog(#"HAHAH");
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)segueToSecondVC:(UIButton *)sender
{
thirdVC = [ThirdViewController sharedManager];
thirdVC.delegate = self;
}
#end
Third VC .h:
#import <UIKit/UIKit.h>
#protocol PassValueProtocal <NSObject>
- (void) passValueBack: (NSString *) value;
#end
#interface ThirdViewController : UIViewController
#property (weak, nonatomic) id<PassValueProtocal>delegate;
+ (id) sharedManager;
#end
Third VC .m:
#import "ThirdViewController.h"
#interface ThirdViewController ()
#property (weak, nonatomic) IBOutlet UITextField *myTextField;
#end
#implementation ThirdViewController
+ (id) sharedManager
{
NSLog(#"myDelegate sharedManager");
static ThirdViewController *sharedManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{ sharedManager = [[self alloc] init]; });
return sharedManager;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)passValueAction:(UIButton *)sender
{
NSLog(#"%#", self.delegate);
if ([self.delegate respondsToSelector:#selector(passValueBack:)])
{
[self.delegate passValueBack:self.myTextField.text];
}
}
#end
Your code
- (IBAction)segueToSecondVC:(UIButton *)sender
{
thirdVC = [ThirdViewController sharedManager];
thirdVC.delegate = self;
}
Should not be here. You should implement function prepareForSegue and move this code there. Something like
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
ThirdViewController *thirdVC = (ThirdViewController *)segue.destinationViewController;
thirdVC.delegate = self;
}
So perhaps this is a beginner's mistake and super easy to you guys, but i really do not know how to solve it,really appreciate for any suggestions:
Right Now:
1: I have to ViewController: EnterCommandViewController and DetectionViewController
2: I wrote Delegate protocol in EnterCommandViewController and set DetectionViewController as its delegate.
3: About delegate: I have a inputTextField in the EnterCommandView and a "Save" bar button item on the top toolbar in this view. Once I click the save , current view will be dismissed and return back to DetectionView and show the NSString just entered in the UILabel in DetectionView.
Finally, My question is that Why After I alloc and init a EnterCommandViewController instance , that is enterCVS, the instance is still nil as show in end of my post.
Code:
EnterCommandViewController.h
#import <UIKit/UIKit.h>
#import "RscMgr.h"
#protocol EnterCommandDelegate <NSObject>
#optional
-(void) commandEntered:(NSString*)command;
#end
#interface EnterCommandViewController : UIViewController <RscMgrDelegate,EnterCommandDelegate>
{
RscMgr* rscMgr;
IBOutlet UITextField *inputTextField;
// DetectionViewController* detectionViewController;
// __unsafe_unretained id<EnterCommandDelegate> delegate;
}
-(void)sendMessage:(NSString*)message;
-(id)initWithDelegate:(id)delegateToBe;
- (IBAction)cancelPressed;
- (IBAction)savePressed;
#property (nonatomic,weak) id<EnterCommandDelegate> delegate; //assign replaced
#end
EnterCommandVIewController.m
#import "EnterCommandViewController.h"
#import "DetectionViewController.h"
#interface EnterCommandViewController () <UITextFieldDelegate>
{
#private
BOOL connected;
}
#end
#implementation EnterCommandViewController
#synthesize delegate;
- (void)viewDidLoad {
[super viewDidLoad];
rscMgr = [[RscMgr alloc] init];
[rscMgr setDelegate:self];
// Do any additional setup after loading the view, typically from a nib.
[inputTextField becomeFirstResponder];
}
-(id)initWithDelegate:(id)delegateToBe{
if(self = [super init]){
delegate = delegateToBe;
}
return self;
}
-(void) viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
inputTextField.delegate = self;
}
-(void) viewWillDisappear:(BOOL)animated{
[super viewWillDisappear:animated];
inputTextField.delegate = nil;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - UITextFieldDelegate Methods
-(BOOL) textFieldShouldReturn:(UITextField *)textField{
[self sendMessage:textField.text];
textField.text = nil;
return NO;
}
#pragma mark - Serial Tx/Rx Methods Implementation
-(void) sendMessage:(NSString *)message{
if(connected == YES) {
[rscMgr writeString:message];
}
else{
NSLog(#"CableDisconnected!");
NSLog(#"Attempted To Send: %#",message);
}
}
- (IBAction)cancelPressed {
[self dismissViewControllerAnimated:YES completion:^{}];
}
- (IBAction)savePressed {
//is anyone listening
if([[[UIDevice currentDevice]systemVersion] compare:#"7.0" options:NSNumericSearch] != NSOrderedAscending){
NSLog(#"SYStem version > 7.0");
}
if(delegate&&[delegate respondsToSelector:#selector(commandEntered:)]){
NSLog(#"SomeMethod is listening");
[delegate commandEntered:inputTextField.text];
}
[self dismissViewControllerAnimated:YES completion:nil]; //commened: ^{}
}
#pragma mark - RscMgrDelegate Methods Implementation
-(void) cableConnected:(NSString *)protocol{
inputTextField.text = #"cableConnected";
[rscMgr setBaud:9600];
[rscMgr open];
connected = YES;
}
-(void) cableDisconnected{
inputTextField.text = #"cableDisconnected";
connected = NO;
}
-(void) readBytesAvailable:(UInt32)length{}
-(void) portStatusChanged{}
#end
DetectionViewController.h
#import <UIKit/UIKit.h>
#import "EnterCommandViewController.h"
#interface DetectionViewController : UIViewController <EnterCommandDelegate>{
}
- (IBAction)showSettings:(UIBarButtonItem *)sender;
#property (nonatomic, strong) EnterCommandViewController* enterCVC;
#property (nonatomic, strong) IBOutlet UILabel *showReceivedCommand;
#end
DetectionViewController.m
#import <Foundation/Foundation.h>
#import "DetectionViewController.h"
#import "EnterCommandViewController.h"
#implementation DetectionViewController
#synthesize showReceivedCommand;
#synthesize enterCVC;
- (IBAction)showSettings:(UIBarButtonItem *)sender {
}
-(void) viewDidLoad{
[super viewDidLoad];
if(showReceivedCommand){
showReceivedCommand.text=#"Initial text";
NSLog(#"UILAbel in ViewDidload is not nil");
}else {
NSLog(#"UILAbel in viewDidload is nil");
}
enterCVC = [[EnterCommandViewController alloc] init];
if(enterCVC.delegate) NSLog(#"X nil");
[enterCVC setDelegate:self];
}
#pragma mark - EnterCommandDelegate function(s)
-(void)commandEntered:(NSString *)command{
dispatch_async(dispatch_get_main_queue(), ^{
if(showReceivedCommand){
NSLog(#"UILabel is not nil");
}else{NSLog(#"UILabel is nil");}
showReceivedCommand = [[UILabel alloc] init];
NSLog(#"command received: %#",command);
showReceivedCommand.text = command;
[showReceivedCommand setNeedsDisplay];
NSLog(#"text in showReceivedCommand is %#",showReceivedCommand.text);
});
}
#end
I set a break point at DetectionViewController.n --> ViewDidLoad() --> [enterCVC setDelegate:self];
I got:
self DetectionViewController * 0x15c50e850 0x000000015c50e850
UIViewController UIViewController
showReceivedCommand UILabel * 0x15c510650 0x000000015c510650
enterCVC EnterCommandViewController * 0x15c611360 0x000000015c611360
showReceivedCommand UILabel * 0x15c510650 0x000000015c510650
enterCVC EnterCommandViewController * 0x15c611360 0x000000015c611360
UIViewController UIViewController
rscMgr RscMgr * nil 0x0000000000000000
inputTextField UITextField * nil 0x0000000000000000
connected BOOL NO false
delegate id 0x0 0x0000000000000000
enterCVC = [[EnterCommandViewController alloc] init]
Try changing that to....
enterCVC = [[EnterCommandViewController alloc] initWithDelegate:self];
I have a UIViewController with a UIPickerView that creates a string that I want to pass along to my RootViewController (BL_MainViewController).
My tactic was to use the delegate pattern but I can't figure out where I'm going wrong here. If my RootViewController is created using a Storyboard, how do I tell it BL_MainViewController.BL_SetTimerViewController = self and where do I set that in the implementation (guess:ViewDidLoad)?
BL_SetTimerViewController.h (the child VC presented by modal segue in IB)
#protocol BL_SetTimerViewControllerDelegate
-(void) updateLabelWithString:(NSString *)string;
#end
#interface BL_SetTimerViewController : UIViewController{
... // some ivars
}
#property (assign, nonatomic) id <BL_SetTimerViewControllerDelegate> delegate;
#end
BL_SetTimerViewController.m
#implementation BL_SetTimerViewController
...
#synthesize delegate;
...
- (IBAction)setTimerAndDismissViewController:(id)sender {
// does some stuff, then:
[self.delegate updateLabelWithString:#"TEST"];
[self dismissViewControllerAnimated:YES completion:nil];
}
BL_MainViewController.h (The Root VC)
#import "BL_SetTimerViewController.h"
#interface BL_MainViewController : UIViewController <BL_SetTimerViewControllerDelegate>{
...
}
#end
BL_MainViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
// do some stuff here
// presumably also assign the delegate protocol?
}
-(void)updateLabelWithString:(NSString *)string {
self.pLabel.text = string;
}
In your BL_MainViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
}
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
self.pLabel.text=GlobleSting;
}
-(void)updateLabelWithString:(NSString *)string {
GlobleSting = string; //declare in .h file
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"YoursegueIdentifir"]) {
BL_SetTimerViewController *settimerVC =
segue.destinationViewController;
settimerVC.delegate = self;
}
}
Super simple test app for delegate(note that many thing are left out as it's quickly thrown together), this works for me.(note that delegate is weak, not assign. If you are targeting iOS 5+, use weak for delegates)
SimpleProtocol.h
#protocol SimpleProtocol <NSObject>
- (void)updateText:(NSString *)text;
#end
ViewController.m
#import "ViewController.h"
#import "SecondViewController.h"
#import "SimpleProtocol.h"
#interface ViewController ()<SimpleProtocol>
#property (nonatomic, weak) IBOutlet UILabel *label;
#end
#implementation ViewController
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
SecondViewController *vc = (SecondViewController *)segue.destinationViewController;
vc.delegate = self;
}
- (void)updateText:(NSString *)text
{
self.label.text = text;
}
#end
SecondViewController.m
#import "SimpleProtocol.h"
#interface SecondViewController ()
#end
#implementation SecondViewController
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[NSTimer scheduledTimerWithTimeInterval:3 target:self selector:#selector(timerFire:) userInfo:nil repeats:NO];
}
- (void)timerFire:(NSTimer *)timer
{
NSString *text = [NSString stringWithFormat:#"Test %#", #(arc4random())];
[self.delegate updateText:text];
[self.navigationController popViewControllerAnimated:YES];
}
#end
I'm trying to modify the demo that comes with the Facebook iOS SDK.
I need the login button appears in a second modal view.
When I click on the login button, it opens Facebook App and authorization is sought, then returns to my app but fbDidLogin is not fired.
I have followed all the steps from here https://github.com/facebook/facebook-ios-sdk.
Here is the code i'm using. Please help me to find out what i'm missing.
I'm using Xcode 4.1 and iOS SDK 4.3
myAppAppDelegate.h
#import <UIKit/UIKit.h>
#import "loginView.h"
#import "firstView.h"
#class firstView;
#interface myAppAppDelegate : NSObject <UIApplicationDelegate> {
firstView* controller;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) IBOutlet firstView *firstViewViewController;
#end
myAppAppDelegate.m
#import "firstView.h"
#import "loginView.h"
#synthesize window;
#synthesize firstViewViewController = _ firstViewViewController;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
controller = [[firstView alloc] init];
firstView *firstView = [[firstView alloc] initWithNibName:nil bundle:nil];
[window addSubview:viewController.view];
[self.window makeKeyAndVisible];
return YES;
}
- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url {
return [[controller fb] handleOpenURL:url];
}
- (void)dealloc {
[window release];
[_firstViewViewController release];
[controller release];
[super dealloc];
}
#end
firstView.h
#import <UIKit/UIKit.h>
#interface firstView : UIViewController
-(IBAction)openLoginView:(id)sender;
#end
firstView.m
#import "loginView.h"
#implementation firstView
-(IBAction)openLoginView:(id)sender{
loginView *loginView = [[loginView alloc] initWithNibName:nil bundle:nil];
[self presentModalViewController:loginView animated:YES];
}
#end
loginView.h
#import <UIKit/UIKit.h>
#import "FBConnect.h"
#interface loginView : UIViewController<FBRequestDelegate,
FBDialogDelegate,
FBSessionDelegate>{
NSArray* _permissions;
Facebook* _fb;
}
#property(readonly) Facebook *fb;
-(IBAction)fbButtonClick:(id)sender;
#end
loginView.m
#import "loginView.h"
static NSString* kAppId = #"260718013943480";
#implementation loginView
#synthesize fb = _fb;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
if (!kAppId) {
NSLog(#"missing app id!");
exit(1);
return nil;
}
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
_permissions = [[NSArray arrayWithObjects:
#"read_stream", #"publish_stream", #"offline_access",nil] retain];
}
return self;
}
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
_fb = [[Facebook alloc] initWithAppId:kAppId];
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)login {
[_fb authorize:_permissions delegate:self];
}
- (IBAction)fbButtonClick:(id)sender {
NSLog(#"login button clicked");
[self login];
}
- (void)fbDidLogin {
NSLog(#"logged in");
}
/**
* Called when the user canceled the authorization dialog.
*/
-(void)fbDidNotLogin:(BOOL)cancelled {
NSLog(#"did not login");
}
/**
* Called when the request logout has succeeded.
*/
- (void)fbDidLogout {
NSLog(#"logedout");
}
#end
First of all, how does this even compile?
#synthesize firstViewViewController = _ firstViewViewController;
You don't have _firstViewController declared anywhere.
Secondly, I think you are mixing views and view controllers.
Finally, your view controller that handles FB authorization (loginView) should implement
FBRequestDelegate,FBDialogDelegate,FBSessionDelegate
So your loginView.h should look something like:
#interface loginView : UIViewController <
FBRequestDelegate,FBDialogDelegate,FBSessionDelegate>{