使用委托在视图控制器之间进行通信

问了一些问题后,我学会了如何从一个视图控制器发送订单到另一个视图控制器,并设法编写它的工作代码,但没有任何反应…

在我的项目中,我有两个视图控制器名为sayfa1sayfa23 。 当点击sayfa1上的一个button时,它将打开sayfa23并写在标签上(随机hello看下面的代码),但是没有发生。 在模拟器上,button只会打开sayfa23 ,这就是没有发生任何标签。 如果你看看代码,你可以更好地理解它。

sayfa1.h

 #import <UIKit/UIKit.h> @protocol sayfa1Delegate <NSObject> - (void)dealWithButton1; @end @interface sayfa1 : UIViewController @property(nonatomic,assign) id<sayfa1Delegate> delegate; @end 

sayfa1.m

 #import "sayfa1.h" @interface sayfa1 () @end @implementation sayfa1 @synthesize delegate; -(IBAction)button { [delegate dealWithButton1]; } @end 

sayfa23.h

 #import <UIKit/UIKit.h> #import "sayfa1.h" @interface sayfa23 : UIViewController <sayfa1Delegate> { IBOutlet UILabel *label; sayfa1 *vc1 ; } @end 

sayfa23.m

 #import "sayfa23.h" #import "sayfa1.h" @interface sayfa23 () @end @implementation sayfa23 - (void)dealWithButton1 { vc1.delegate = self; int random_num; random_num = (arc4random() % 5 - 1) + 1; if (random_num == 1) { label.text = @"hello1"; } else if (random_num == 2) label.text = @"hello2"; else if (random_num == 3) label.text = @"hello3"; else if (random_num == 4) label.text = @"hello4"; } @end 

写这个代码后,我连接到sayfa23的button,所以它会打开新的页面,我也连接到sayfa1接收button的动作,我连接标签(在sayfa23sayfa23接收标签的命令。 但是,正如我所说没有发生没有错误,没有问好,我做错了什么? 我导入了sayfa1.hsayfa23.h在我的一些h文件的顶部导致Xcode给我一个关于没有定义和解决这个问题的错误,但这是我的错误还是别的什么。

我想要的例子。

  • 用户打开应用程序

  • sayfa1显示在屏幕上

  • 用户点击button和sayfa23显示sayfa23上的标签文本是由sayfa23上的button改变它写随机hello1..2..3等…

我做错了什么?

重读你的问题,你问你的第一个视图控制器可以打开第二个视图控制器,并设置一个文本框。 如果这确实是你想要做的,那么这个问题就简单得多了,根本不需要任何委托协议或代表。

之前的两个答复是通过讨论代表的,但是这是为了解决不同的问题。 如果您需要第二个控制器将某些事情传递回第一个控制器,则只需要代表。 但是,如果你只是想让你的第二个控制器从第一个控制器接收一些东西,就像下面这样简单:

 // FirstViewController.h #import <UIKit/UIKit.h> @interface FirstViewController : UIViewController @end 

执行如下:

 // FirstViewController.m #import "FirstViewController.h" #import "SecondViewController.h" @implementation FirstViewController - (NSString *)generateRandomText { NSString *result; int random_num; random_num = (arc4random() % 5 - 1) + 1; if (random_num == 1) result = @"hello1"; else if (random_num == 2) result = @"hello2"; else if (random_num == 3) result = @"hello3"; else if (random_num == 4) result = @"hello4"; return result; } // if you're using NIBs, it might be something like... // you only need this method if you're using NIBs and you've manually hooked a button up to this // if you're using segues, get rid of `goToNextViewController` and just use the following `prepareForSegue - (IBAction)goToNextViewController:(id)sender { SecondViewController *secondController = [[SecondViewController alloc] initWithNibName:@"SecondView" bundle:nil]; secondController.textFromParent = [self generateRandomText]; [self.navigationController pushViewController:secondController animated:YES]; } // if you're using segues, give your segue an identifier, eg toSecondViewSegue, in Interface Builder and reference the exact same identifier here // if you're not using segues, you don't need this prepareForSegue method - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { if ([segue.identifier isEqualToString:@"toSecondViewSegue"]) { SecondViewController *destinationController = segue.destinationViewController; destinationController.textFromParent = [self generateRandomText]; } } @end 

而你的第二个控制器可能看起来像:

 // SecondViewController.h #import <UIKit/UIKit.h> @interface SecondViewController : UIViewController @property (strong, nonatomic) NSString *textFromParent; @property (weak, nonatomic) IBOutlet UILabel *label; @end 

有了这样一个实现:

 // SecondViewController.m #import "SecondViewController.h" @implementation SecondViewController @synthesize textFromParent = _textFromParent; @synthesize label = _label; - (void)viewDidLoad { [super viewDidLoad]; self.label.text = self.textFromParent; } @end 

当第一个控制器实例化第二个控制器时,应将第二个控制器设置为指向第一个视图控制器。 因此你的第一个视图控制器可能看起来像

 // FirstViewController.h #import <UIKit/UIKit.h> @protocol FirstViewControllerDelegate <NSObject> - (void)dealWithButton; @end @interface FirstViewController : UIViewController <FirstViewControllerDelegate> @end 

执行如下:

 // FirstViewController.m #import "FirstViewController.h" #import "SecondViewController.h" @implementation FirstViewController - (IBAction)goToNextViewController:(id)sender { SecondViewController *secondController = [[SecondViewController alloc] initWithNibName:@"SecondView" bundle:nil]; secondController.delegate = self; [self.navigationController pushViewController:secondController animated:YES]; } - (void)dealWithButton { NSLog(@"Dealt with button from second controller"); } @end 

而你的第二个控制器可能看起来像:

 // SecondViewController.h #import <UIKit/UIKit.h> #import "FirstViewController.h" @class FirstViewController; @interface SecondViewController : UIViewController @property (weak, nonatomic) id<FirstViewControllerDelegate> delegate; @property (weak, nonatomic) IBOutlet UILabel *label; - (IBAction)buttonPressed:(id)sender; @end 

有了这样一个实现:

 // SecondViewController.m #import "SecondViewController.h" @implementation SecondViewController @synthesize delegate = _delegate; @synthesize label = _label; - (IBAction)buttonPressed:(id)sender { int random_num; random_num = (arc4random() % 5 - 1) + 1; if (random_num == 1) self.label.text = @"hello1"; else if (random_num == 2) self.label.text = @"hello2"; else if (random_num == 3) self.label.text = @"hello3"; else if (random_num == 4) self.label.text = @"hello4"; [self.delegate dealWithButton]; } @end 

更新:

你原来的问题并没有说清楚你是要把标签放在第一个控制器还是第二个控制器上。 我上面的答案假定你想在第二个控制器上,但回想起来,你可能已经想要在第一个控制器(代表)。 如果是这样,下面的代码就是这样做的。 请注意,我不只是更新dealWithButton的第一个视图控制器的标签,因为这很危险,因为您不知道视图是否可见(如果您收到了didReceiveMemoryWarning可能已经被卸载)。 所以我等待viewWillAppear 。 所以再次,第一个视图控制器:

 // FirstViewController.h #import <UIKit/UIKit.h> @protocol FirstViewControllerDelegate <NSObject> - (void)dealWithButton; @end @interface FirstViewController : UIViewController <FirstViewControllerDelegate> @property (weak, nonatomic) IBOutlet UILabel *label; @end 

其实施:

 // FirstViewController.m #import "FirstViewController.h" #import "SecondViewController.h" @interface FirstViewController () { NSString *_labelText; } @end @implementation FirstViewController @synthesize label = _label; // if you're using storyboards, it would be like: - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { if ([segue.identifier isEqualToString:@"delegateSegue"]) { SecondViewController *destinationController = segue.destinationViewController; FirstViewController *sourceController = segue.sourceViewController; destinationController.delegate = sourceController; } } // if not using storyboards, you probably have a button like: - (IBAction)goToNextViewController:(id)sender { SecondViewController *secondController = [[SecondViewController alloc] initWithNibName:@"SecondView" bundle:nil]; secondController.delegate = self; [self.navigationController pushViewController:secondController animated:YES]; } - (void)dealWithButton { // note, because this is being called by the second view controller, you should *not* update the UI // directly, because you can't be assured this view controller's view is still in memory (if you got // a didReceiveMemoryWarning while on the second view controller, this first view controller will // stay in memory, but its view could have been released). So save what you want the label to be, // and update it on viewWillAppear (and if the view was released, it will be reloaded by the time // you hit viewWillAppear. // // clearly, if you were doing view controller containment and this was the parent view, you wouldn't // want to do this. But I assume you're dealing with a simple push/present view controller situation. int random_num; random_num = (arc4random() % 5 - 1) + 1; if (random_num == 1) _labelText = @"hello1"; else if (random_num == 2) _labelText = @"hello2"; else if (random_num == 3) _labelText = @"hello3"; else if (random_num == 4) _labelText = @"hello4"; NSLog(@"Dealt with button from second controller"); } - (void)viewWillAppear:(BOOL)animated { self.label.text = _labelText; } @end 

而第二个视图控制器:

 // SecondViewController.h #import <UIKit/UIKit.h> #import "FirstViewController.h" @class FirstViewController; @interface SecondViewController : UIViewController @property (weak, nonatomic) id<FirstViewControllerDelegate> delegate; - (IBAction)buttonPressed:(id)sender; @end 

其实施:

 // SecondViewController.m #import "SecondViewController.h" @interface SecondViewController () @end @implementation SecondViewController @synthesize delegate = _delegate; - (IBAction)buttonPressed:(id)sender { [self.delegate dealWithButton]; } @end 

尝试将以下方法添加到sayfa23的实现中:

 - (void)viewDidLoad { vc1 = [[sayfa1 alloc] init]; vc1.delegate = self; } 

并删除vc1.delegate = self; 从你的dealWithButton1方法。

编辑 :你必须明白,dealWithButton1方法永远不会被调用,因为你永远不会发送消息到对象。 因此,你永远不会设置vc1的委托。 使用viewDidLoad方法进行一些设置是一个很好的方法,当视图加载的时候会调用这个方法。 在那里你可以分配init(创build一个sayfa1类的实例),并将它分配给你的属性vc1。 分配完对象后,可以向其发送消息。 你可以设置委托。

sayfa23.h

 #import <UIKit/UIKit.h> #import "sayfa1.h" @interface sayfa23 : UIViewController <sayfa1Delegate> { IBOutlet UILabel *label; } @property (nonatomic, strong) sayfa1 *vc1 ; @end 

sayfa23.m

 #import "sayfa23.h" #import "sayfa1.h" @interface sayfa23 () @end @implementation sayfa23 @synthesize vc1; - (void)viewDidLoad { vc1 = [[sayfa1 alloc] init]; vc1.delegate = self; } - (void)dealWithButton1 { int random_num; random_num = (arc4random() % 5 - 1) + 1; if (random_num == 1) { label.text = @"hello1"; } else if (random_num == 2) label.text = @"hello2"; else if (random_num == 3) label.text = @"hello3"; else if (random_num == 4) label.text = @"hello4"; } @end