如何设置一个简单的委托来在两个视图控制器之间进行通信?

How do I set up a simple delegate to communicate between two view controllers?

提问人:Strong Like Bull 提问时间:5/30/2011 最后编辑:Alex CioStrong Like Bull 更新时间:12/23/2022 访问量:134820

问:

我有两个,需要使用委托将值从子视图控制器传递给父视图控制器。我知道什么是代表,只是想看一个简单易懂的例子。UITableViewControllers

谢谢

iOS Objective-C iPhone 委托

评论

1赞 phi 5/30/2011
如果您尝试使用“实用工具”Xcode 模板,则已经实现了一个委托模式。你需要更多的帮助吗?
0赞 Muhammad_Awaab 7/24/2014
这是一个非常简单的教程。tutorialspoint.com/ios/ios_delegates.htm

答:

3赞 BDGapps 5/30/2011 #1

您需要使用委托和协议。下面是一个带有示例 http://iosdevelopertips.com/objective-c/the-basics-of-protocols-and-delegates.html 的网站

303赞 Simon Whitaker 5/30/2011 #2

下面是一个简单的示例:

假设子视图控制器有一个,我们希望通过委托将滑块的值传递回父视图控制器。UISlider

在子视图控制器的头文件中,声明委托类型及其方法:

ChildViewController.h

#import <UIKit/UIKit.h>

// 1. Forward declaration of ChildViewControllerDelegate - this just declares
// that a ChildViewControllerDelegate type exists so that we can use it
// later.
@protocol ChildViewControllerDelegate;

// 2. Declaration of the view controller class, as usual
@interface ChildViewController : UIViewController

// Delegate properties should always be weak references
// See http://stackoverflow.com/a/4796131/263871 for the rationale
// (Tip: If you're not using ARC, use `assign` instead of `weak`)
@property (nonatomic, weak) id<ChildViewControllerDelegate> delegate;

// A simple IBAction method that I'll associate with a close button in
// the UI. We'll call the delegate's childViewController:didChooseValue: 
// method inside this handler.
- (IBAction)handleCloseButton:(id)sender;

@end

// 3. Definition of the delegate's interface
@protocol ChildViewControllerDelegate <NSObject>

- (void)childViewController:(ChildViewController*)viewController 
             didChooseValue:(CGFloat)value;

@end

在子视图控制器的实现中,根据需要调用委托方法。

ChildViewController.m

#import "ChildViewController.h"

@implementation ChildViewController

- (void)handleCloseButton:(id)sender {
    // Xcode will complain if we access a weak property more than 
    // once here, since it could in theory be nilled between accesses
    // leading to unpredictable results. So we'll start by taking
    // a local, strong reference to the delegate.
    id<ChildViewControllerDelegate> strongDelegate = self.delegate;

    // Our delegate method is optional, so we should 
    // check that the delegate implements it
    if ([strongDelegate respondsToSelector:@selector(childViewController:didChooseValue:)]) {
        [strongDelegate childViewController:self didChooseValue:self.slider.value];
    }
}

@end

在父视图控制器的头文件中,声明它实现了协议。ChildViewControllerDelegate

RootViewController.h

#import <UIKit/UIKit.h>
#import "ChildViewController.h"

@interface RootViewController : UITableViewController <ChildViewControllerDelegate>

@end

在父视图控制器的实现中,适当地实现委托方法。

RootViewController.m

#import "RootViewController.h"

@implementation RootViewController

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    ChildViewController *detailViewController = [[ChildViewController alloc] init];
    // Assign self as the delegate for the child view controller
    detailViewController.delegate = self;
    [self.navigationController pushViewController:detailViewController animated:YES];
}

// Implement the delegate methods for ChildViewControllerDelegate
- (void)childViewController:(ChildViewController *)viewController didChooseValue:(CGFloat)value {

    // Do something with value...

    // ...then dismiss the child view controller
    [self.navigationController popViewControllerAnimated:YES];
}

@end

评论

1赞 Madbreaks 1/16/2013
家长如何注册为孩子的代表?
2赞 Simon Whitaker 1/16/2013
通过调用(它在上面的代码片段中。detailViewController.delegate = self;-tableView:didSelectRowAtIndexPath:
0赞 Dejell 3/19/2013
谢谢。如果将 ChildViewController 委托给 UITableView,则 UITableView 方法应位于何处?在孩子还是父母?
0赞 Danny 6/5/2013
很好的例子/解释!不幸的是,当我尝试编译时,我收到“找不到'MyProtocol'的协议声明”错误。不过,正如您所描述的:生成的视图控制器在其 .h 文件中具有 procotol 定义,并在其 .m 文件中调用协议方法。托管视图控制器在其 .h @interface声明中具有 <MyProtocol>,这是发生错误的地方。不过,你的答案似乎是一样的......有什么想法吗?
0赞 JaseC 6/23/2015
谢谢。我至少看了十几个资源,这是我第一次能够关注。我认为编号的代码注释非常适合帮助解释它的顺序。
33赞 Jhaliya - Praveen Sharma 5/30/2011 #3

下面的代码只是显示了委托概念的最基本用法。您可以根据需要命名变量和类。

首先,您需要声明一个协议:

我们将其称为 MyFirstControllerDelegate.h

@protocol MyFirstControllerDelegate
- (void) FunctionOne: (MyDataOne*) dataOne;
- (void) FunctionTwo: (MyDatatwo*) dataTwo;
@end

导入 MyFirstControllerDelegate.h 文件并使用协议 MyFirstControllerDelegate 确认 FirstController

#import "MyFirstControllerDelegate.h"

@interface FirstController : UIViewController<MyFirstControllerDelegate>
{

}

@end

在实现文件中,需要实现协议的两个功能:

@implementation FirstController 


    - (void) FunctionOne: (MyDataOne*) dataOne
      {
          //Put your finction code here
      }
    - (void) FunctionTwo: (MyDatatwo*) dataTwo
      {
          //Put your finction code here
      }

     //Call below function from your code
    -(void) CreateSecondController
     {
             SecondController *mySecondController = [SecondController alloc] initWithSomeData:.];
           //..... push second controller into navigation stack 
            mySecondController.delegate = self ;
            [mySecondController release];
     }

@end

SecondController 中:

@interface SecondController:<UIViewController>
{
   id <MyFirstControllerDelegate> delegate;
}

@property (nonatomic,assign)  id <MyFirstControllerDelegate> delegate;

@end

SecondController 的实现文件中。

@implementation SecondController

@synthesize delegate;
//Call below two function on self.
-(void) SendOneDataToFirstController
{
   [delegate FunctionOne:myDataOne];
}
-(void) SendSecondDataToFirstController
{
   [delegate FunctionTwo:myDataSecond];
}

@end

这是关于委托的 wiki 文章。

评论

0赞 CW0007007 6/19/2014
虽然这涵盖了如何设置有效的委托协议。我认为它省略了几个关键点。首先,在委托上调用方法时,应首先检查委托是否响应该选择器。否则,您的应用程序将崩溃。其次,您需要将“@protocol MyFirstControllerDelegate”设置为@protocol MyFirstControllerDelegate <NSObject>
8赞 user9106403 2/12/2018 #4

以下解决方案是使用委托将数据从 VC2 发送到 VC1 的非常基本和简单的方法。

PS:此解决方案是在Xcode 9.X和Swift 4中制作的

声明了一个协议,并在 ViewControllerB 中创建了一个委托 var

    import UIKit

    //Declare the Protocol into your SecondVC
    protocol DataDelegate {
        func sendData(data : String)
    }

    class ViewControllerB : UIViewController {

    //Declare the delegate property in your SecondVC
        var delegate : DataDelegate?
        var data : String = "Send data to ViewControllerA."
        override func viewDidLoad() {
            super.viewDidLoad()
        }

        @IBAction func btnSendDataPushed(_ sender: UIButton) {
                // Call the delegate method from SecondVC
                self.delegate?.sendData(data:self.data)
                dismiss(animated: true, completion: nil)
            }
        }

ViewControllerA 确认协议,并期望通过委托方法 sendData 接收数据

    import UIKit
        // Conform the  DataDelegate protocol in ViewControllerA
        class ViewControllerA : UIViewController , DataDelegate {
        @IBOutlet weak var dataLabel: UILabel!

        override func viewDidLoad() {
            super.viewDidLoad()
        }

        @IBAction func presentToChild(_ sender: UIButton) {
            let childVC =  UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier:"ViewControllerB") as! ViewControllerB
            //Registered delegate
            childVC.delegate = self
            self.present(childVC, animated: true, completion: nil)
        }

        // Implement the delegate method in ViewControllerA
        func sendData(data : String) {
            if data != "" {
                self.dataLabel.text = data
            }
        }
    }