ios - 画面遷移 - viewcontroller 間 データ 受け渡し swift




ビューコントローラ間でのデータの受け渡し (20)

私は、iOSとObjective-C、そしてMVCのパラダイムが新しく、次のことに悩まされています。

データ入力フォームとして機能するビューがあり、ユーザーに複数の製品を選択するオプションを提供したいと考えています。 製品は別のビューにUITableViewControllerリストされており、複数の選択を有効にしています。

私の質問は、データをあるビューから別のビューにどのように転送するのですか? 私は配列内のUITableViewの選択肢を保持しUITableViewが、フォームの提出時に他のデータと一緒にコアデータに保存できるように、それを前のデータ入力フォームビューに戻すにはどうしたらいいですか?

私はサーフィンして、一部の人々がアプリケーションデリゲートで配列を宣言するのを見ました。 私はシングルトンについて何かを読んだが、これらが何であるか分からず、データモデルの作成について何かを読んだ。

これを実行する正しい方法は何でしょうか、それについてどうすればよいでしょうか?


迅速

ここに、そしての周りに何トンもの説明がありますが、あなたが何か基本的なものを手に入れようとしている初心者なら、このYouTubeチュートリアルを見てみてください。

データを次のView Controllerに転送する

ビデオに基づく例を次に示します。 最初のView Controllerのテキストフィールドから2番目のView Controllerのラベルに文字列を渡すことが考えられます。

Interface Builderでストーリーボードレイアウトを作成します。 セグを作るには、ボタンをクリックしてコントロールを Second View Controllerにドラッグするだけです。

ファーストビューコントローラ

First View Controllerのコードは次のとおりです。

import UIKit

class FirstViewController: UIViewController {

    @IBOutlet weak var textField: UITextField!

    // This function is called before the segue
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {

        // get a reference to the second view controller
        let secondViewController = segue.destination as! SecondViewController

        // set a variable in the second view controller with the String to pass
        secondViewController.receivedString = textField.text!
    }

}

Second View Controller

Second View Controllerのコードは次のとおりです。

import UIKit

class SecondViewController: UIViewController {

    @IBOutlet weak var label: UILabel!

    // This variable will hold the data being passed from the First View Controller
    var receivedString = ""

    override func viewDidLoad() {
        super.viewDidLoad()

        // Used the text from the First View Controller to set the label
        label.text = receivedString
    }

}

忘れないでください

  • UITextFieldUILabelのコンセントをUILabelます。
  • 第1および第2のView ControllerをIBの適切なSwiftファイルに設定します。

以前のView Controllerにデータを戻す

2番目のビューコントローラから最初のビューコントローラにデータを戻すには、プロトコルとデリゲートを使用します 。 このビデオは、そのプロセスの非常に明確な散歩です:

以下は、ビデオに基づいた例です(いくつかの変更が加えられています)。

Interface Builderでストーリーボードレイアウトを作成します。 繰り返しますが、セグを作るには、ボタンからSecond View Controllerにドラッグを制御するだけです。 segue識別子をshowSecondViewController設定しshowSecondViewController 。 また、次のコードの名前を使用してアウトレットとアクションを接続することを忘れないでください。

ファーストビューコントローラ

First View Controllerのコードは次のとおりです。

import UIKit

class FirstViewController: UIViewController, DataEnteredDelegate {

    @IBOutlet weak var label: UILabel!

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "showSecondViewController" {
            let secondViewController = segue.destination as! SecondViewController
            secondViewController.delegate = self
        }
    }

    func userDidEnterInformation(info: String) {
        label.text = info
    }
}

私たちのカスタムDataEnteredDelegateプロトコルの使用に注意してください。

2番目のビューコントローラとプロトコル

2番目のView Controllerのコードは次のとおりです。

import UIKit

// protocol used for sending data back
protocol DataEnteredDelegate: class {
    func userDidEnterInformation(info: String)
}

class SecondViewController: UIViewController {

    // making this a weak variable so that it won't create a strong reference cycle
    weak var delegate: DataEnteredDelegate? = nil

    @IBOutlet weak var textField: UITextField!

    @IBAction func sendTextBackButton(sender: AnyObject) {

        // call this method on whichever class implements our delegate protocol
        delegate?.userDidEnterInformation(info: textField.text!)

        // go back to the previous view controller
        _ = self.navigationController?.popViewController(animated: true)
    }
}

protocolはView Controllerクラスの外にあることに注意してください。

それでおしまい。 今すぐアプリケーションを実行すると、2番目のビューコントローラから最初のビューコントローラにデータを戻すことができるはずです。


MVCのMは「モデル」用であり、MVCのパラダイムでは、モデルクラスの役割はプログラムのデータを管理することです。 モデルはビューの反対です - ビューはデータの表示方法を知っていますが、データで何をするかについては何も知らないのに対し、モデルはデータの操作方法のすべてを知っていますが、表示方法については何も知りません。 モデルは複雑になる可能性はありますが、必ずしもそうである必要はありません。アプリケーションのモデルは、文字列や辞書の配列と同じくらいシンプルなものです。

コントローラの役割は、ビューとモデルを仲介することです。 したがって、1つ以上のビュー・オブジェクトと1つ以上のモデル・オブジェクトへの参照が必要です。 モデルが辞書の配列であり、各辞書がテーブルの1つの行を表すとします。 あなたのアプリのルートビューはそのテーブルを表示し、ファイルから配列を読み込む責任があります。 ユーザーがテーブルに新しい行を追加することを決定すると、いくつかのボタンがタップされ、コントローラは新しい(変更可能な)辞書を作成し、配列に追加します。 行を入力するために、コントローラはディテールビューコントローラを作成し、それに新しい辞書を与えます。 ディテール・ビュー・コントローラーがディクショナリーを埋めて戻ります。 辞書はすでにモデルの一部であるため、何も起こる必要はありません。


iOSの別のクラスにデータを受け取るにはさまざまな方法があります。 例えば ​​-

  1. 別のクラスの割り当て後の直接初期化。
  2. 委任 - データを戻すため
  3. 通知 - 一度に複数のクラスにデータをブロードキャストする
  4. NSUserDefaults保存する - 後でアクセスする
  5. シングルトンクラス
  6. データベースやplistのような他の記憶メカニズム

しかし、現在のクラスで割り当てが行われている別のクラスに値を渡す単純なシナリオの場合、最も一般的で好ましい方法は、割り当て後の値を直接設定することです。 これは次のように行われます。

コントローラ1とコントローラ 2の2つのコントローラ

Controller1クラスでController2オブジェクトを作成し、渡すString値でプッシュしたいとします。 これは次のように行うことができます:

- (void)pushToController2 {

    Controller2 *obj = [[Controller2 alloc] initWithNib:@"Controller2" bundle:nil];
    [obj passValue:@"String"];
    [self pushViewController:obj animated:YES];
}

Controller2クラスの実装では、この関数がas-

@interface Controller2  : NSObject

@property (nonatomic , strong) NSString* stringPassed;

@end

@implementation Controller2

@synthesize stringPassed = _stringPassed;

- (void) passValue:(NSString *)value {

    _stringPassed = value; //or self.stringPassed = value
}

@end

Controller2クラスのプロパティは、次のように直接設定することもできます。

- (void)pushToController2 {

    Controller2 *obj = [[Controller2 alloc] initWithNib:@"Controller2" bundle:nil];
    [obj setStringPassed:@"String"];  
    [self pushViewController:obj animated:YES];
}

複数の値を渡すには、次のような複数のパラメータを使用できます。

Controller2 *obj = [[Controller2 alloc] initWithNib:@"Controller2" bundle:nil];
[obj passValue:@“String1” andValues:objArray withDate:date]; 

または、共通のフィーチャに関連する3つ以上のパラメータを渡す必要がある場合は、値をModelクラスに格納し、そのModelObjectを次のクラスに渡すことができます

ModelClass *modelObject = [[ModelClass alloc] init]; 
modelObject.property1 = _property1;
modelObject.property2 = _property2;
modelObject.property3 = _property3;

Controller2 *obj = [[Controller2 alloc] initWithNib:@"Controller2" bundle:nil];
[obj passmodel: modelObject];

だからあなたがしたいならば -

1) set the private variables of the second class initialise the values by calling a custom function and passing the values.
2) setProperties do it by directlyInitialising it using the setter method.
3) pass more that 3-4 values related to each other in some manner , then create a model class and set values to its object and pass the object using any of the above process.

お役に立てれば


1. 2番目のView Controllerに最初のView Controllerのインスタンスを作成し、そのプロパティを作成します@property (nonatomic,assign)

2.SecondviewControllerこのView Controllerのインスタンスを割り当てます。

2.選択操作が終了すると、アレイを最初のView Controllerにコピーします。SecondViewをアンロードすると、FirstViewはアレイデータを保持します。

お役に立てれば。


NewsViewController

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
  [tbl_View deselectRowAtIndexPath:indexPath animated:YES];
  News *newsObj = [newstitleArr objectAtIndex:indexPath.row];
  NewsDetailViewController *newsDetailView = [[NewsDetailViewController alloc] initWithNibName:@"NewsDetailViewController" bundle:nil];

  newsDetailView.newsHeadlineStr = newsObj.newsHeadline;

  [self.navigationController pushViewController:newsDetailView animated:YES];
}

NewsDetailViewController.h

@interface NewsDetailViewController : UIViewController
@property(nonatomic,retain) NSString *newsHeadlineStr;
@end

NewsDetailViewController.m

@synthesize newsHeadlineStr;

NSProxyに基づくModelオブジェクトとMockオブジェクトの考え方は、ユーザーが選択できるものを取り消すことができれば、データをコミットまたは破棄するのが好きです。

単一のオブジェクトまたは2つのオブジェクトであるため、データを渡すのは簡単です.UINavigationControllerコントローラを使用すると、モデルへの参照を内部に保つことができ、すべてのプッシュビューコントローラがナビゲーションコントローラから直接アクセスできます。


ViewControlerOneからViewControllerTwoにデータを渡したい場合は、これらを試してみてください。

ViewControlerOne.hでこれらを行います

 @property (nonatomic, strong) NSString *str1;

ViewControllerTwo.hでこれらを行います

 @property (nonatomic, strong) NSString *str2;

ViewControllerTwo.mでstr2を合成する

@interface ViewControllerTwo ()
@end
@implementation ViewControllerTwo
@synthesize str2;

ViewControlerOne.mでこれらを行います

 - (void)viewDidLoad
 {
   [super viewDidLoad];

  // Data or string you wants to pass in ViewControllerTwo..
  self.str1 = @"hello world";

 }

ボタンのクリックイベントでこれを行う..

-(IBAction)ButtonClicked
{ //Navigation on buttons click event from ViewControlerOne to ViewControlerTwo with transferring data or string..
  ViewControllerTwo *objViewTwo=[self.storyboard instantiateViewControllerWithIdentifier:@"ViewControllerTwo"];
  obj.str2=str1;
  [self.navigationController pushViewController: objViewTwo animated:YES];
}

これらをViewControllerTwo.mで行います

- (void)viewDidLoad
{
 [super viewDidLoad];
  NSLog(@"%@",str2);
}

あなたが1つのviewControllerから別のviewControllerへデータを送信したい場合は、ここに方法があります:

viewControllerとViewControllerを持っているとしましょう。

ViewController.hの

#import <UIKit/UIKit.h>

@interface ViewController : UIViewController
{
    IBOutlet UITextField *mytext1,*mytext2,*mytext3,*mytext4;
}

@property (nonatomic,retain) IBOutlet UITextField *mytext1,*mytext2,*mytext3,*mytext4;

-(IBAction)goToNextScreen:(id)sender;

@end

ViewController.mで

#import "ViewController.h"

#import "NewViewController.h"

@implementation ViewController
@synthesize mytext1,mytext2,mytext3,mytext4;

-(IBAction)goToNextScreen:(id)sender
{
    NSArray *arr = [NSArray arrayWithObjects:mytext1.text,mytext2.text,mytext3.text,mytext4.text, nil];


    NewViewController *newVc = [[NewViewController alloc] initWithNibName:@"NewViewController" bundle:nil];

    newVc.arrayList = arr;

    [self.navigationController pushViewController:newVc animated:YES];

}

NewViewController.hで

#import <UIKit/UIKit.h>

@interface NewViewController : UITableViewController
{
    NSArray *arrayList;

    NSString *name,*age,*dob,*mobile;

}

@property(nonatomic, retain)NSArray *arrayList;

@end

NewViewController.mで

#import "NewViewController.h"

#import "ViewController.h"

@implementation NewViewController
@synthesize arrayList;

#pragma mark - Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{

    // Return the number of sections.
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{

    // Return the number of rows in the section.
    return [arrayList count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil)
    {
         cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];      
    }
    // Configure the cell...
    cell.textLabel.text = [arrayList objectAtIndex:indexPath.row];
    return cell;


}

@end

このようにして、あるView Controllerから別のView Controllerにデータを渡すことができます...


あるコントローラから別のコントローラにデータを渡したい場合は、このコードを試してみてください

FirstViewController.h

@property (nonatomic, retain) NSString *str;

SecondViewController.h

@property (nonatomic, retain) NSString *str1;

FirstViewController.m

- (void)viewDidLoad
   {
     // message for the second SecondViewController
     self.str = @"text message";

     [super viewDidLoad];
   }

-(IBAction)ButtonClicked
 {
   SecondViewController *secondViewController = [[SecondViewController alloc] initWithNibName:@"SecondViewController" bundle:nil];
   secondViewController.str1 = str;
  [self.navigationController pushViewController:secondViewController animated:YES];
 }

この質問には多くの回答があり、実際に動作するView Controller通信を実行するさまざまな方法を提供していますが、実際に使用するのに最適なものと避けるものは何も言及されていません。

実際には、私の意見では、ほんのいくつかのソリューションが推奨されています:

  • データを転送するには:
    • ストーリーボードとセグを使用するときのprepare(for:sender:)方法をオーバーライドするUIViewController
    • コードを使用してビューコントローラーのトランジションを実行するときに、イニシャライザまたはプロパティを使用してデータを渡します
  • データを後方に渡す
    • 上記のいずれかの方法でView Controller間を進めることができるアプリ共有状態を更新する
    • 委任を使う
    • 巻き戻しセグを使う

ソリューション私は使用しないことをお勧めします:

  • 委任を使用する代わりに直前のコントローラを直接参照する
  • シングルトンによるデータの共有
  • アプリケーションデリゲートを介してデータを渡す
  • ユーザーのデフォルトによるデータの共有
  • 通知によるデータの受け渡し

これらのソリューションは短期間では機能しますが、あまりにも多くの依存関係が導入され、アプリケーションのアーキテクチャが壊れてしまい、後でさらに問題が生じます。

興味のある方には、これらの点をより深く解説し、さまざまな欠点を強調する記事をいくつか書きました。


これはそれを行う方法ではなく、デリゲートを使用する必要があります.ViewController1とViewController2の2つのビューコントローラがあると仮定します。このチェックは最初のもので、状態が変わったら、ViewController2で何かしたいそれを適切な方法で達成するには、以下のことを行う必要があります:

プロジェクトに新しいファイルを追加する(Objective-Cプロトコル)ファイル - >新規、今度はViewController1Delegateという名前をつけるか、必要なものを@interfaceと@endディレクティブの間に書く

@optional

- (void)checkStateDidChange:(BOOL)checked;

今度はViewController2.hに行き、

#import "ViewController1Delegate.h"

定義を次のように変更します

@interface ViewController2: UIViewController<ViewController1Delegate>

今度はViewController2.mに行き、実装の中でadd:

- (void)checkStateDidChange:(BOOL)checked {
     if (checked) {
           // Do whatever you want here
           NSLog(@"Checked");
     }
     else {
           // Also do whatever you want here
           NSLog(@"Not checked");
     }
}

次に、ViewController1.hに移動して、次のプロパティを追加します。

@property (weak, nonatomic) id<ViewController1Delegate> delegate; 

今度はViewController1をいくつかのイベントの後でViewController2の中に作成する場合、NIBファイルを使ってこのようにしてください:

ViewController1* controller = [[NSBundle mainBundle] loadNibNamed:@"ViewController1" owner:self options:nil][0];
controller.delegate = self;
[self presentViewController:controller animated:YES completion:nil];

これですべての設定が完了し、ViewController1で変更されたチェックのイベントが検出されるたびに、以下のことが行われます

[delegate checkStateDidChange:checked]; // You pass here YES or NO based on the check state of your control

あなたの質問を正しく理解できなかったことが明らかでないものがあるかどうか教えてください。


より多くの研究の後、Protocols and Delegatesは正しい/ Appleがこれを行う方法として正しいと思われた。

私はこの例を使って終わった

ビューコントローラと他のオブジェクト間でデータを共有する @ iPhone Dev SDK

うまく動作し、私の意見の間に文字列と配列を前後に渡すことができました。

ご協力ありがとうございます


私はこれが殴られた主題だと知っていますが、SWIFTスラントでこの質問に答えるために、裸の骨の例が必要な場合、ここではセグを使用してデータを渡す方法を紹介します。

上記と似ていますが、ボタンやラベルなどはありません。あるビューから次のビューにデータを渡すだけです。

ストーリーボードの設定

3つの部分があります。

  1. 送り主
  2. セグエ
  3. 受信機

これは非常にシンプルなビューレイアウトで、その間にセグがあります。

送信者の設定は次のとおりです

ここに受信機の設定があります。

最後に、セグの設定。

ビューコントローラ

私たちはこれを単純なままにして、ボタンではなく、アクションではなく、アプリケーションがロードされたときにデータを送信者から受信者に移動し、送信された値をコンソールに出力するだけです。

このページは最初に読み込まれた値を受け取り、それを渡します。

//
//  ViewControllerSender.swift
//  PassDataBetweenViews
//
//  Created by Chris Cantley on 8/25/15.
//  Copyright (c) 2015 Chris Cantley. All rights reserved.
//

import UIKit


class ViewControllerSender: UIViewController {

    // THE STUFF - put some info into a variable
    let favoriteMovie = "Ghost Busters"


    override func viewDidAppear(animated: Bool) {
        // PASS IDENTIFIER - go to the recieving view controller.
        self.performSegueWithIdentifier("goToReciever", sender: self)
    }

    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {

        //GET REFERENCE - ...to the receiver view.
        var viewControllerReceiver = segue.destinationViewController as? ViewControllerReceiver

        //PASS STUFF - pass the variable along to the target.
        viewControllerReceiver!.yourFavMovie = self.favoriteMovie

    }

}

このページは、ロードされたときに変数の値をコンソールに送信するだけです。この時点までに、私たちのお気に入りの映画はその変数に含まれているはずです。

//
//  ViewControllerReceiver.swift
//  PassDataBetweenViews
//
//  Created by Chris Cantley on 8/25/15.
//  Copyright (c) 2015 Chris Cantley. All rights reserved.
//

import UIKit

class ViewControllerReceiver: UIViewController {

    //Basic empty variable waiting for you to pass in your fantastic favorite movie.
    var yourFavMovie = ""

    override func viewDidLoad() {
        super.viewDidLoad()


        //And now we can view it in the console.
        println("The Movie is \(self.yourFavMovie)")

    }



}

これは、あなたがセグを使用したいがナビゲーションコントローラの下にあなたのページを持っていない場合に、あなたがそれに取り組む方法です。

それが実行されると、自動的に受信者ビューに切り替え、送信者から受信者に値を渡し、コンソールに値を表示する必要があります。


私はブロックを渡すと、最もシンプルでエレガントなバージョンを見つける。 返されたデータを "A"として返し、ビューコントローラを "B"として返すビューコントローラを命名しましょう。 この例では、まずType1とType2の2つの値を取得します。

ストーリーボードを使用していると仮定すると、最初のコントローラは、例えばセグの準備中にコールバックブロックを設定します。

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([segue.destinationViewController isKindOfClass:[BViewController class]])
    {
        BViewController *viewController = segue.destinationViewController;

        viewController.callback = ^(Type1 *value1, Type2 *value2) {
            // optionally, close B
            //[self.navigationController popViewControllerAnimated:YES];

            // let's do some action after with returned values
            action1(value1);
            action2(value2);
        };

    }
}

と "B"ビューコントローラーは、コールバックプロパティ、BViewController.hを宣言する必要があります:

// it is important to use "copy"
@property (copy) void(^callback)(Type1 *value1, Type2 *value2);

実装ファイルBViewController.mよりも、コールバックを返すために必要な値を取得した後に呼び出す必要があります。

if (self.callback)
    self.callback(value1, value2);

覚えておくべきことの1つは、ブロックを使用すると、 here説明さhereいるような強い参照と__weak参照を頻繁に管理する必要があることhere


答えの多くにはいくつかの良い情報がありますが、質問には完全には触れていません。

質問は、View Controller間で情報を渡すことについて質問します。 具体的な例では、ビュー間で情報を渡すことについて尋ねられていますが、自己宣言された新機能をiOSに与えた場合、元のポスターはViewController間ではなく、ビュー間ではありません(ViewControllerからの関与なし)。 すべての答えが2つのView Controllerに焦点を当てているようですが、アプリが情報交換に2つ以上のView Controllerを必要とするようになったらどうなりますか?

元のポスターは、 シングルトンAppDelegateの使用についても質問しました 。 これらの質問に答える必要があります。

誰かがこの質問を見て助けるために、誰が完全な答えを望んでいるのか、私はそれを提供しようとします。

アプリケーションシナリオ

非常に仮説的で抽象的な議論をするのではなく、具体的なアプリケーションを念頭におくことが役立ちます。 2ビューコントローラの状況と2ビューコントローラ以上の状況を定義するために、2つの具体的なアプリケーションシナリオを定義します。

シナリオ1:最大2つのView Controllerで情報を共有する必要があります。 図1を参照してください。

アプリケーションには2つのView Controllerがあります。 ViewControllerA(データ入力フォーム)とView Controller B(製品リスト)があります。 製品リストで選択した項目は、データ入力フォームのテキストボックスに表示されている項目と一致する必要があります。 このシナリオでは、ViewControllerAとViewControllerBは、相互に直接通信する必要があり、他のView Controllerは通信できません。

シナリオ22つ以上のView Controllerが同じ情報を共有する必要があります。 図2を参照してください。

アプリケーションには4つのView Controllerがあります。 これは家の目録を管理するためのタブベースのアプリケーションです。 3つのビューコントローラは、同じデータの異なるビューをフィルタリングして表示します。

  • ViewControllerA - ラグジュアリーアイテム
  • ViewControllerB - 非保険商品
  • ViewControllerC - 家全体のインベントリ
  • ViewControllerD - 新しい項目フォームを追加する

個々のアイテムが作成または編集されるたびに、他のビューコントローラと同期する必要があります。 たとえば、ViewControllerDにボートを追加しても保険がかかっていない場合は、ユーザーがViewControllerA(Luxury Items)に移動したときにボートが表示され、ViewControllerC(Entire Home Inventory)にもボートが表示されますViewControllerB(非保険商品)。 新しいアイテムの追加だけでなく、4つのView Controllerのいずれかから許可される可能性のあるアイテムの削除や既存アイテムの編集(「新しいアイテムフォームの追加」から許可される可能性があります)編集のために)。

すべてのビューコントローラは同じデータを共有する必要があるため、4つのビューコントローラはすべて同期した状態を維持する必要があるため、単一のビューコントローラが基になるデータを変更するたびに、他のすべてのビューコントローラと何らかの通信が必要です。 このシナリオでは、各View ControllerがそれぞれのView Controllerと直接通信しないようにする必要があることは明らかです。 それが明白でない場合は、(4つではなく)20種類のビューコントローラがあるかどうかを検討してください。 1つのView Controllerが変更を行ったときに、他の19個のView Controllerのそれぞれに通知することは、どれほど困難でエラーが発生しやすいでしょうか?

ソリューション:デリゲートとオブザーバーパターン、そしてシングルトン

シナリオ1では、いくつかの実行可能な解決策があります。

  • セグ
  • 代表者
  • ビューコントローラのプロパティを直接設定する
  • NSUserDefaults(実際には貧弱な選択肢)

シナリオ2では、他にも実行可能なソリューションがあります。

  • オブザーバーパターン
  • シングルトン

シングルトンはクラスのインスタンスであり、そのインスタンスはその存続期間中に存在する唯一のインスタンスです。 シングルトンは、それが単一のインスタンスであるという事実からその名前を得る。 通常、シングルトンを使用する開発者は、シングルトンにアクセスするための特別なクラスメソッドを持っています。

+ (HouseholdInventoryManager*) sharedManager; {
    static dispatch_once_t onceQueue;
    static HouseholdInventoryManager* _sharedInstance;

    // dispatch_once is guaranteed to only be executed once in the
    // lifetime of the application
    dispatch_once(&onceQueue, ^{
        _sharedInstance = [[self alloc] init];
    });
    return _sharedInstance;
}

シングルトンが何であるかを理解したので、シングルトンがどのようにオブザーバパターンに適合するかについて説明しましょう。 オブザーバパターンは、あるオブジェクトで他のオブジェクトによる変更に応答するために使用されます。 2番目のシナリオでは、基になるデータの変更についてすべて知りたい4つの異なるView Controllerがあります。 「基礎となるデータ」は単一のインスタンス、つまりシングルトンに属している必要があります。 「変化について知る」は、シングルトンに加えられた変更を観察することによって達成されます。

ホームインベントリアプリケーションは、インベントリアイテムのリストを管理するように設計されたクラスの単一のインスタンスを有する。 マネージャーは家財道具のコレクションを管理します。 以下は、データマネージャのクラス定義です。

#import <Foundation/Foundation.h>

@class JGCHouseholdInventoryItem;

@interface HouseholdInventoryManager : NSObject
/*!
 The global singleton for accessing application data
 */
+ (HouseholdInventoryManager*) sharedManager;


- (NSArray *) entireHouseholdInventory;
- (NSArray *) luxuryItems;
- (NSArray *) nonInsuredItems;

- (void) addHouseholdItemToHomeInventory:(JGCHouseholdInventoryItem*)item;
- (void) editHouseholdItemInHomeInventory:(JGCHouseholdInventoryItem*)item;
- (void) deleteHoueholdItemFromHomeInventory:(JGCHouseholdInventoryItem*)item;
@end

ホームインベントリ項目のコレクションが変更されると、ビューコントローラはこの変更を認識する必要があります。 上記のクラス定義は、これがどのように起こるかを明白にしません。 オブザーバーのパターンに従う必要があります。 ビューコントローラは、sharedManagerを正式に観察する必要があります。 別のオブジェクトを観察するには2つの方法があります。

  • Key-Value-Observing(KVO)
  • NSNotificationCenter。

シナリオ2では、KVOを使用して観察できるHouseholdInventoryManagerの単一のプロパティはありません。 私たちは簡単に観察できる単一のプロパティを持たないので、この場合オブザーバパターンはNSNotificationCenterを使用して実装する必要があります。 4つのView Controllerのそれぞれは通知を購読し、適切な場合には通知を通知センターに送信します。 インベントリマネージャは、インベントリアイテムのコレクションが変更されたときに知りたいと思うかもしれないビューコントローラまたは他のクラスのインスタンスについて何も知る必要はありません。 NSNotificationCenterはこれらの実装の詳細を処理します。 View Controllerは単に通知に登録するだけで、データマネージャーは単に通知を送信します。

多くの初心者プログラマは、アプリケーションの存続期間中に常に正確に1つのアプリケーションデリゲートが存在し、グローバルにアクセス可能であるという事実を利用しています。 プログラマーの初めは、アプリケーション内のどこからでもアクセスできるように、この事実を利用してオブジェクトや機能をappDelegateに組み込みます。 AppDelegateがシングルトンであるという理由だけで、他のシングルトンをすべて置き換える必要はありません。 これは、オブジェクト指向の優れた実践を破り、1つのクラスに負担をかけるため、貧弱なプラクティスです。 各クラスには、クラスの名前だけで簡単に説明できる明確な役割が必要です。

アプリケーション代理人が肥大化し始めるたびに、機能をシングルトンに削除し始めます。 たとえば、Core Data StackはAppDelegateに残すべきではなく、代わりに独自のクラスcoreDataManagerクラスに配置する必要があります。

参考文献


.xibファイルを使用しているときに、委任はそのような操作を実行する唯一の解決策ですが、上で説明したすべての回答は、storyboard委任を使用する必要がある.xibsファイルのためのものです。それはあなたができる唯一の解決策です。

別の解決策は、シングルトンクラスパターンを使用してそれを一度初期化し、あなたのアプリ全体でそれを使用することです。


これは本当に素晴らしいtutorialです。次にコード例を示します。

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    if ([segue.identifier isEqualToString:@"myIdentifer]) {
        NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
        myViewController *destViewController = segue.destinationViewController;
        destViewController.name = [object objectAtIndex:indexPath.row];
    }
}

これを行う方法はたくさんあります。正しいものを選ぶことが重要です。おそらく最も大きなアーキテクチャ上の決定の1つは、モデルコードをアプリケーション全体でどのように共有したりアクセスしたりするかにあります。

私はこれについてのブログ記事を書いていますモデルコードの共有。簡単な要約を以下に示します。

共有データ

1つのアプローチは、ビューコントローラ間でモデルオブジェクトへのポインタを共有することです。

  • データを設定するビューコントローラ(ナビゲーションまたはタブバーコントローラ内)のブルートフォース反復
  • prepareForSegue(ストーリーボードの場合)またはinit(プログラムの場合)

segueの準備が最も一般的なので、ここでは例です:

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    var next = segue.destinationViewController as NextViewController
    next.dataSource = dataSource
}

独立したアクセス

もう1つのアプローチは、一度にデータがいっぱいの画面を処理し、ビューコントローラを互いに結合する代わりに、各ビューコントローラを独立して取得できる単一のデータソースに結合することです。

私がこれを行ったのを見た最も一般的な方法は、singletonインスタンスです。だからあなたのシングルトンオブジェクトは、DataAccessあなたはUIViewControllerのviewDidLoadメソッドで次を行うことができた場合:

func viewDidLoad() {
    super.viewDidLoad()
    var data = dataAccess.requestData()
}

データの受け渡しに役立つ追加ツールがあります。

  • キー値の観測
  • NSNotification
  • コアデータ
  • NSFetchedResultsController
  • 情報源

コアデータ

コアデータの良い点は、逆の関係があることです。ノートブックのようなものとは逆の関係にあるため、NotesViewControllerにノートオブジェクトを与えるだけでよいのです。NotesViewControllerのノートブックにデータが必要な場合は、次の手順を実行してオブジェクトグラフをバックアップすることができます。

let notebookName = note.notebook.name

私のブログの記事:モデルコードの共有


私の場合、グローバルオブジェクトとして動作するシングルトンクラスを使用して、アプリケーションのほぼすべての場所からデータにアクセスできます。まず、シングルトンクラスを構築することです。「Objective-Cシングルトンはどのように見えるでしょうか?」というページを参照してくださいオブジェクトをグローバルにアクセス可能にするappName_Prefix.pchために行った作業は、すべてのクラスでimportステートメントを適用するためのものです。このオブジェクトにアクセスして使用するには、単純にクラスメソッドを実装して、共有インスタンスを返します。共有インスタンスには、独自の変数


私はdidSelectRowAtPath方法を使用してこれを複雑にすることについて多くの人々を見てきました。私は私の例でコアデータを使用しています。

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{

    //this solution is for using Core Data
    YourCDEntityName * value = (YourCDEntityName *)[[self fetchedResultsController] objectAtIndexPath: indexPath];

    YourSecondViewController * details = [self.storyboard instantiateViewControllerWithIdentifier:@"nameOfYourSecondVC"];//make sure in storyboards you give your second VC an identifier

    //Make sure you declare your value in the second view controller
    details.selectedValue = value;

    //Now that you have said to pass value all you need to do is change views
    [self.navigationController pushViewController: details animated:YES];

}

メソッド内に4行のコードがあり、完了しました。





uiviewcontroller