4

たまたまtableViewControllerであるビューコントローラーが、NSArrayまたはNSDictionaryであるそのプロパティが、表示のためにテーブルにロードされるデータを保持していることを知らされずに知っていることは、私を悩ませています。

次のように明示的に言う必要があるようです。

[self.tableView useData:self.MyArray];

tableViewController 内に複数の配列を持ち、プログラムで一方と他方を切り替えたいと考えています。

tableViewController が searchViewController を使用すると、次のことができることに気付きました。

if (tableView == self.searchDisplayController.searchResultsTableView) {

私はこれを行うことさえできました:

self.tableView =  self.searchDisplayController.searchResultsTableView;
[self.tableView reloadData];

しかし、self.tableView をメイン データソースに戻す方法がどこにも見つかりません。

4

2 に答える 2

41

さて、iPhoneの教材の大部分は、アプリ全体のデザインに十分な注意を払っていないため、あなたの不満を理解しています。彼らは目の保養のインターフェースのためのビーラインを作り、データの処理がそもそもアプリの完全な目的であるにもかかわらず、アプリがデータを処理する方法にリップサービスのみを支払います!

教材は、iPhone /CocoaAPI全体のベースとなるModel-View-Controllerデザインパターンを説明するのに十分な時間を費やしていません。教材があなたを信じさせたように、UIビューがプログラムのコアであるという誤った信念の下で、機能を間違ったオブジェクトに詰め込もうとし続けるため、何かを理解するのに苦労しています。この誤解の下では、Appleのドキュメントでさえ、何も意味がありません。

一歩下がって考え直す必要があります。表示するデータとそれをいつ表示するかを決定するのは、ビューの機能ではありません。アプリのデータを保持、管理、または保存することは、テーブルビューコントローラーの機能ではありません。これらの関数は、データモデルオブジェクトに適切に属しています(おそらく聞いたことはありません)。データモデルタスクをビューとビューコントローラに分割しようとしているため、問題が発生しています。

どうやら、テーブルビューコントローラのプロパティとしてテーブルのデータを保持しているため、アプリにはデータモデルすらありません。これは単純なチュートリアルの例でよく見られますが、最も些細なアプリ以外の複雑さの下で崩壊するのは悪い設計です。

代わりに、データは独自のカスタムオブジェクトに保存および管理する必要があります。これがデータモデルです。あなたの場合、データが2つの配列に分散しているように見えるので、次のようなデータモデルオブジェクトを作成します。

@interface MyDataModel : NSObject {
@protected
    NSArray *arrayOne;
    NSArray *arrayTwo;
@public
    NSArray *currentlyUsedArray;

}
@property(nonatomic, retain)  NSArray *currentlyUsedArray;

-(void) switchToArrayOne;
-(void) switchToArrayTwo;
-(void) toggleUsedArray;

@end

#import "MyDataModel.h"

@interface MyDataModel ()
@property(nonatomic, retain)  NSArray *arrayOne;
@property(nonatomic, retain)  NSArray *arrayTwo;

@end


@implementation MyDataModel

- (id) init{
    if (self=[super init]) {
        self.arrayOne=//... initialize array from some source
        self.arrayTwo=//... initialize array from some source
        self.currentlyUsedArray=self.arrayOne; //whatever default you want
    }
    return self;
}

-(void) switchToArrayOne{
    self.currentlyUsedArray=self.arrayOne;
}

-(void) switchToArrayTwo{
    self.currentlyUsedArray=self.arrayTwo;
}

- (void) toggleUsedArray{
    if (self.currentlyUsedArray==self.arrayOne) {
        self.currentlyUsedArray=self.arrayTwo;
    }else {
        self.currentlyUsedArray=self.arrayOne;
    }
}

(実際のデータはカプセル化されており、他のオブジェクトはにしかアクセスできないことに注意してくださいcurrentlyUsedArray。データモデルは、データの内部状態に基づいて、提供するデータを決定します。)

このデータモデルオブジェクトは、どこからでもアクセスできる場所にある必要があります。最良の方法はシングルトンにすることですが、手っ取り早い方法はアプリデリゲートの属性としてパークすることです。

したがって、テーブルビューコントローラには、次のプロパティがあります。

MyDataModel *theDataModel;
@property (nonatomic, retain) MyDataModel *theDataModel;

その後、実装で

@synthesize theDataModel;

-(MyDataModel *) theDataModel; {
    if (theDataModel; !=nil) {
        return theDataModel; ;
    }
    id appDelegate=[[UIApplication sharedApplication] delegate];
    self.theDataModel=appDelegate.theDataModelProperty;
    return theDataModel;
}

次に、テーブルビューデータソースメソッドで:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    ...
    cell.textLabel.text=[self.theDataModel.currentlyUsedArray objectAtIndex:indexPath.row];
    return cell;
}

アプリ内のどこかのイベントで配列を切り替える必要がある場合は、アプリデリゲートからデータモデルオブジェクトを呼び出して、適切な配列切り替えメッセージを送信するだけです。

id appDelegate=[[UIApplication sharedApplication] delegate];
[appDelegate.theDataModelProperty toggleUsedArray];

これで、後続のすべてのデータ操作は、その特定のテーブルビューであろうと、他の完全に無関係なビューであろうと、適切な配列からのデータを使用します。

なぜこのすべてのトラブルを経験するのですか?これにより、アプリケーションがモジュール化されます。データ管理を毎回書き直すことなく、それぞれが異なる方法でデータを表示するさまざまなビューを簡単に追加できます。データモデルを使用して、テーブル、Webビュー、またはコマンドラインに表示されるデータを管理できます。データモデルをまったく別のアプリに簡単に移動することもできます。

このモジュール性により、大規模で複雑なアプリの管理が非常に簡単になります。データを操作および制御するオブジェクトは1つだけです。まれにしか使用されないコードセグメントのマイナーエラーによってアプリ全体が破棄されることを心配する必要はありません。ビューを簡単にプラグインしたり、アプリを壊すことなく簡単に削除したりできます。

これはもちろん些細な例ですが、良い習慣を示しています。

ただし、これにより、どのデータをいつロードするかを知っているテーブルビューの問題をどのように解決できるのでしょうか。単純ですが、そうではありません。ロードするデータやロードするタイミングを知ることは、テーブルビューの仕事ではありません。データモデルはwhat-dataを処理し、tableviewコントローラーはwhenを処理します。(たとえば、URLの更新時にデータモデルに通知を発行させることもできます。その後、View Controllerは通知に登録しreloadData、データモデルが変更されるたびに呼び出すことができます。)

MVCの機能を容赦なくコンパートメント化してカプセル化することで、保守とデバッグが容易なシンプルで再利用可能なコンポーネントから複雑なアプリを作成します。

ほとんどの教材は、この非常に重要な概念にリップサービスを支払うだけです。

于 2010-03-14T17:23:27.103 に答える
2

テーブルビューのコントローラーは、何も「言われなくても知っている」わけではありません。データの由来であると言及したようなプロパティは本質的にありません。そのデータを一度に 1 セルずつ、通常はビュー コントローラーのサブクラスで提供します。

通常、テーブル ビュー コントローラー オブジェクトは、テーブル ビューのデリゲートとテーブル ビューのデータ ソース デリゲートの両方です。アップルのドキュメントから:

UITableView オブジェクトには、デリゲートとデータ ソースが必要です。Model-View-Controller デザイン パターンに従って、データ ソースはアプリケーションのデータ モデル (つまり、そのモデル オブジェクト) とテーブル ビューの間を仲介します。一方、デリゲートは、テーブル ビューの外観と動作を管理します。多くの場合、データ ソースとデリゲートは (必ずしもそうとは限りませんが) 同じオブジェクトであり、そのオブジェクトは多くの場合、UITableViewController のカスタム サブクラスです。

テーブル ビューは配列やディクショナリを取り込んで、そこからデータを取得しません。データソースで各セルがどのように見えるかを尋ねます。このメソッドを実装するだけです:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

そして、質問されている行に必要なセルの内容を返します。そこにロジックを配置して、好きな場所からデータをミックス/マッチ/プルできます。

あなたの混乱は、何が起こっているのか不明確なサンプル コードのスープから来ているのでしょうか? テーブル ビューを最初から作成して、これがどのように機能するかを確認することをお勧めします。これは、プロジェクトに新しいクラスを追加することで簡単に実行できます。「新しい」ウィザードで XCode 内から UITableViewController サブクラスを選択できます。上記を含む、関連するすべての空のメソッドを .m ファイルに事前設定します。


編集: 検索を行うときに、View Controller が所有するテーブル ビューを変更しないでください。ビューコントローラーが所有する「tableView」と呼ばれるインスタンス参照と、どのテーブルビューがセルを要求しているかtableView:cellForRowAtIndexPath:を伝えるために渡されるデリゲートメソッドへの引数を混同しています。デフォルト/コンテンツテーブルと検索結果の両方のデリゲートである同じviewcontrollerを使用して通常の方法で検索を設定すると、どちらでも呼び出される可能性があります。これに関するドキュメントについては、こちらを参照してください

于 2010-03-14T14:55:27.703 に答える