【问题标题】:How do I set up a simple delegate to communicate between two view controllers?如何设置一个简单的委托来在两个视图控制器之间进行通信?
【发布时间】:2011-09-04 08:44:55
【问题描述】:

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

谢谢

【问题讨论】:

标签: ios objective-c iphone delegates


【解决方案1】:

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

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

中制作的

声明了一个协议并创建了一个 delegate 变量到 ViewControllerB

    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
            }
        }
    }

【讨论】:

    【解决方案2】:

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

    【讨论】:

      【解决方案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
      

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

      @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
      

      Here 是关于委托的维基文章。

      【讨论】:

      • 虽然这涵盖了如何设置一个有效的委托协议。我认为它省略了几个关键点。首先,在调用委托上的方法时,您应该首先检查委托是否响应了该选择器。如果没有,您的应用程序将崩溃。其次,您需要将“@protocol MyFirstControllerDelegate”设置为 @protocol MyFirstControllerDelegate
      【解决方案4】:

      简单的例子...

      假设子视图控制器有一个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
      

      希望这会有所帮助!

      【讨论】:

      • 父母如何注册为孩子的代理人?
      • 通过调用detailViewController.delegate = self;(在上面的代码sn-p中是-tableView:didSelectRowAtIndexPath:
      • 谢谢。如果 ChildViewController 委托给 UITableView,那么 UITableView 方法应该在哪里?在孩子还是在父母身上?
      • 很好的例子/解释!不幸的是,当我尝试编译时,出现“找不到‘MyProtocol’的协议声明”错误。不过,正如您所描述的:生成的视图控制器在其 .h 文件中具有协议定义,并在其 .m 文件中调用协议方法。托管视图控制器在其 .h @interface 声明中有 ——这是发生错误的地方。不过,您的答案似乎是一样的……有什么想法吗?
      • 谢谢。我已经查看了至少十几个资源,这是我能够遵循的第一个资源。我认为编号代码 cmets 可以很好地帮助解释它的顺序。
      猜你喜欢
      • 2017-08-31
      • 1970-01-01
      • 1970-01-01
      • 2016-06-10
      • 2017-04-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多