2つのView Controller間で通信するように単純なデリゲートを設定するにはどうすればよいですか?


136

2つUITableViewControllersあり、デリゲートを使用して子ビューコントローラーから親に値を渡す必要があります。私はデリゲートが何であるかを知っており、単純に従う例を見てみたかっただけです。

ありがとうございました


1
「Utility」Xcodeテンプレートを試すと、すでに実装されているデリゲートパターンがあります。多分それ以上の助けが必要ですか?
ファイ

これは非常に簡単なチュートリアルです。tutorialspoint.com/ios/ios_delegates.htm
Muhammad_Awaab

回答:


304

簡単な例...

子ビューコントローラーにが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 2013年

2
呼び出すことによりdetailViewController.delegate = self;(それは中です-tableView:didSelectRowAtIndexPath:。上記のコードで
サイモン・ウィテカー

ありがとう。ChildViewControllerがUITableViewに委任されている場合、UITableViewメソッドはどこにあるべきですか?子供か親か?
デジェル2013年

素晴らしい例/説明!残念ながら、コンパイルしようとすると「「MyProtocol」のプロトコル宣言が見つかりません」というエラーが表示されます。ただし、説明したとおりです。生成されたビューコントローラは、.hファイルにプロトコルの定義があり、.mファイルのプロトコルメソッドを呼び出します。ホスティングビューコントローラの.h @interface宣言に<MyProtocol>があり、エラーが発生します。あなたの答えは同じようですが、何かアイデアはありますか?
Danny

ありがとうございました。私は少なくとも十数のリソースを見てきましたが、これは私がフォローできた最初のものです。番号付きコードのコメントは、シーケンスの説明に役立つと思います。
JaseC 2015年

32

以下のコードは、デリゲートの概念の非常に基本的な使用法を示しているにすぎません。要件に応じて変数とクラスに名前を付けます。

まず、プロトコルを宣言する必要があります。

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記事があります。


これは、動作するデリゲートプロトコルのセットアップ方法をカバーしています。いくつかの重要なポイントを省略していると思います。まず、デリゲートでメソッドを呼び出すときは、まずデリゲートがそのセレクターに応答することを確認する必要があります。そうしないと、アプリがクラッシュします。次に、「@ protocol MyFirstControllerDelegate」を@protocol MyFirstControllerDelegate <NSObject>に設定する必要があります
CW0007007

6

次の解決策は、デリゲートを使用してVC2からVC1にデータを送信するための非常に基本的でシンプルなアプローチです。

PS:このソリューションはXcode 9.XとSwift 4で作成されました

プロトコルを宣言し、作成したデリゲートにVARを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
            }
        }
    }

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.