iOSシリーズ訳文:すっきりしたテーブルビューコード

44951 ワード

自動回転 http://www.cocoachina.com/applenews/devnews/2013/1218/7565.html
表ビューは、非常に万能なiOSアプリケーション構築モジュールです.したがって、テーブルビューに直接または間接的に関連するコードが多く、データを提供し、テーブルビューを更新し、その動作を制御し、選択した反応を制御することを含む.これはいくつかの例にすぎない.この文章では、きちんとした構造の良いコードを紹介します.
 
UITable View Controller VS UID View Controler
アップルは、テーブルビューの専用ビューコントローラとしてUITable View Controllerを提供します.Table view controllersは、コードの重複を避けるために、いくつかの非常に有用な特性を実現しました.一方、Table view controllersは、フルスクリーン表示を管理するためのテーブルビューに限定される.しかし、ほとんどの場合、これはあなたの需要を満たすことができます.満足しないなら、その解決方法を以下に説明します.
 
Table View Controllerの特性
Table View Controllerは初めて表示される時にテーブルビューのデータをロードします.より具体的には、テーブルビューの編集モードの切り替えを助けることができ、キーボードの通知に反応して、スクロールリフレッシュやクリアオプションなどの小さな機能が得られます.重要なのは、これらの特性を実現するために、義子クラスを決めて書き直すことができます.
 
Table View Controllersは標準ビューコントローラの独特なセールスポイントを超えています.アップルのz「ドロップダウンアップデート」の機能をサポートしています.これはテーブルコントローラを使って記録更新を制御する唯一の方法です.他にもいくつかの方法がありますが、次のiOSでの更新は簡単ではありません.
 
これらのすべての原理は、多くのテーブルビューコントローラのインターフェースがアップルによって定義されているように、APPがこれらの基準に適合している場合、フォームコントローラを使用することは、テンプレートコードの書き換えを避けるための良い方法であると主張しています.
 
Table Viewコントローラの制限
表ビューコントローラのビュー属性は常にテーブルビューに設定されています.後でグラフ以外のもの(地図など)を画面に表示したいと決めたら、下手なパッチに依存したくないなら、あなたは惨めです.
 
コードにインターフェースが定義されていたり、使っています.xibファイルは標準的なビューコントローラに変換しやすいです.スクリプトを使うと、この変換プロセスはより多くのステップに関連します.スクリプトを使用すると、表ビューコントローラを標準のテーブルビューコントローラに変更する必要があります.これはすべてのコンテンツをこの新しい試みコントローラにコピーして再構築しなければならないということです.最後に、変更中になくした表ビューコントローラの機能をもう一度追加する必要があります.ほとんどがview Willapearやview DidApparの中の簡単な単行文です.編集状態を切り替えるには、テーブルビューをクリックして属性を編集する方法が必要です.ほとんどの仕事はキーボードのサポートを再作成することです.
 
このコースを続ける前に、ここではポイント分離の利点を付加する簡単な代替方法があります.
 
サブビューコントローラ
テーブルビューマネージャを完全に脱出するためではなく、別のビューコントローラにサブビューコントローラとして追加することもできます.その後、テーブルビューマネージャはこのビューを管理し続けるだけで、親ビューマネージャは任意の追加的なインターフェース要素を処理することができます.

  
  
  
  
  1. - (void)addPhotoDetailsTableView 
  2.     DetailsViewController *details = [[DetailsViewController alloc] init]; 
  3.     details.photo = self.photo; 
  4.     details.delegate = self; 
  5.     [self addChildViewController:details]; 
  6.     CGRect frame = self.view.bounds; 
  7.     frame.origin.y = 110; 
  8.     details.view.frame = frame; 
  9.     [self.view addSubview:details.view];     
  10.     [details didMoveToParentViewController:self]; 
この解決法を選択すると、サブビューと親ビューの間の通信チャネルを確立する必要があります.例えば、別のビューをプレイできるように、父親ビューはテーブルビューのセルが選択されていることを知る必要があります.この使用シーンを考慮して、最も綺麗な方法はテーブルビューコントローラのためにプロキシプロトコルを定義し、親ビューでこのプロトコルを実現することです.
 
この解決方法を使うなら、子供から父親までの通信通路を作らなければなりません.例えば、ユーザがテーブルビューのセルを選択した場合、親ビューコントローラは、メッセージを受信して別のビューコントローラを押す必要がある.例によれば、通常最も簡潔な方法は、このテーブルビューコントローラのために委託プロトコルを定義し、親ビューマネージャで実行することである.

  
  
  
  
  1. @protocol DetailsViewControllerDelegate 
  2. - (void)didSelectPhotoAttributeWithKey:(NSString *)key; 
  3. @end 
  4.   
  5. @interface PhotoViewController () <DetailsViewControllerDelegate> 
  6. @end 
  7.   
  8. @implementation PhotoViewController 
  9. // ... 
  10. - (void)didSelectPhotoAttributeWithKey:(NSString *)key 
  11.     DetailViewController *controller = [[DetailViewController alloc] init]; 
  12.     controller.key = key; 
  13.     [self.navigationController pushViewController:controller animated:YES]; 
  14. @end 
 
ご覧のように、このような構造はビューコントローラ間の通信にいくつかの他の追加のオーバーヘッドを伴って綺麗な注目点分離とより良い重用性を交換します.具体的な用例によって、最終的には必要以上の簡単さと複雑さを必要とします.これは考慮と決定が必要です.
 
懸念点を分離
 
テーブルビューを処理する時、モデルに関する様々なタスクがあります.コントローラとビューの境界を越える問題です.ビューコントローラがこれらのタスクを保存する場所となることを防止するために、これらのタスクを個別により適切な場所に置くという表示を行います.これはコードの可読性、メンテナンス性、およびテスト性に寄与する.
 
図コントローラを軽視した文章で詳細な概念と拡張技術を述べた.どうやって私たちのデータソースとモデルロジックを導入しますか?表ビューの環境下で、ビューコントローラとビューの注目点を分離する方法について専門的に確認します.
 
 
ブリッジモデルのオブジェクトとユニットの間の差
ある程度は、ビュー層に表示したいデータを差し出す必要があります.モデルとビューの間の明確な分離点を維持したいので、このタスクは常にテーブルビューのデータソースに配置されます.

  
  
  
  
  1. - (UITableViewCell *)tableView:(UITableView *)tableView  
  2.          cellForRowAtIndexPath:(NSIndexPath *)indexPath 
  3.     PhotoCell *cell = [tableView dequeueReusableCellWithIdentifier:@"PhotoCell"]; 
  4.     Photo *photo = [self itemAtIndexPath:indexPath]; 
  5.     cell.photoTitleLabel.text = photo.name; 
  6.     NSString* date = [self.dateFormatter stringFromDate:photo.creationDate]; 
  7.     cell.photoDateLabel.text = date; 
 
このコードはデータソースとセルの設計ロジックを結びつけています.私たちはこれをセルのクラスで再現したほうがいいです.

  
  
  
  
  1. @implementation PhotoCell (ConfigureForPhoto) 
  2.   
  3. - (void)configureForPhoto:(Photo *)photo 
  4.     self.photoTitleLabel.text = photo.name; 
  5.     NSString* date = [self.dateFormatter stringFromDate:photo.creationDate]; 
  6.     self.photoDateLabel.text = date; 
  7.   
  8. @end 
 
この場合、私たちのデータソースコードは非常に簡単になります.

  
  
  
  
  1. - (UITableViewCell *)tableView:(UITableView *)tableView 
  2.          cellForRowAtIndexPath:(NSIndexPath *)indexPath 
  3.     PhotoCell *cell = [tableView dequeueReusableCellWithIdentifier:PhotoCellIdentifier]; 
  4.     [cell configureForPhoto:[self itemAtIndexPath:indexPath]]; 
  5.     return cell; 
例示的なコードでは、セルを初期化する時にblockの方式で、テーブルビューのデータソースは、個別の制御対象に分離されています.この例では、このblockは以下のようになります.

  
  
  
  
  1. TableViewCellConfigureBlock block = ^(PhotoCell *cell, Photo *photo) { 
  2.     [cell configureForPhoto:photo]; 
  3. }; 
セルを使いなおす
このように複数のデータモデルが同じセルタイプを使って展示されている場合には、1ステップでセルの再使用効果が得られます.まず、このセルタイプを使ってデータを展示する必要があるすべてのオブジェクトを定義します.その後、いくつかのセルの種類における配置方法を修正して、上記の合意に従う対象を任意に受け入れることができます.この二つの簡単なステップは、セルとデータモデルを分離し、セルに異なるデータタイプを受け入れることができます.
 
セルでセルを処理した状態
もし私たちが標準の状況とは違って、テーブルビューのハイライトと選択状態を作りたいなら、二つの代理方法を実現して、セルを私たちが望む状態に修正する必要があります.たとえば:

  
  
  
  
  1. - (void)tableView:(UITableView *)tableView 
  2.         didHighlightRowAtIndexPath:(NSIndexPath *)indexPath 
  3.     PhotoCell *cell = [tableView cellForRowAtIndexPath:indexPath]; 
  4.     cell.photoTitleLabel.shadowColor = [UIColor darkGrayColor]; 
  5.     cell.photoTitleLabel.shadowOffset = CGSizeMake(3, 3); 
  6.   
  7. - (void)tableView:(UITableView *)tableView 
  8.         didUnhighlightRowAtIndexPath:(NSIndexPath *)indexPath 
  9.     PhotoCell *cell = [tableView cellForRowAtIndexPath:indexPath]; 
  10.     cell.photoTitleLabel.shadowColor = nil; 
 
しかし、この2つの方法は、セルがどのように配置されているかを知ることに依存します.もし私たちがセルを交換したいなら、またはセルを再設計したいなら、私たちもこの代理コードを修正する必要があります.viewの設計の詳細は代理とインターリーブしました.このロジックをcellに入れるべきです.

  
  
  
  
  1. @implementation PhotoCell 
  2. // ... 
  3. - (void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated 
  4.     [super setHighlighted:highlighted animated:animated]; 
  5.     if (highlighted) { 
  6.         self.photoTitleLabel.shadowColor = [UIColor darkGrayColor]; 
  7.         self.photoTitleLabel.shadowOffset = CGSizeMake(3, 3); 
  8.     } else { 
  9.         self.photoTitleLabel.shadowColor = nil; 
  10.     } 
  11. @end 
一般的に、view層の実現の詳細とコントローラ層の実現の詳細を分離することを強く提案します.プロキシはviewの状態変化を知ることができますが、viewの樹状構造をどのように修正するか、およびそのサブビューがどのような状態に設定されるべきかを知るべきではありません.これらの状態はすべてviewにカプセル化され、外部へのアクセスインターフェースを提供するべきです.
複数のセルタイプを処理します.
一つのテーブルビューに複数のセルタイプがあると、データソースが制御不能になります.私達のサンプルアプリでは、私達の写真の詳細表には二つの種類の異なるセルがあります.一つは採点を表示し、もう一つは一般的な表示キー-値のセルです.異なるセルタイプを示すコードを分離するために、データソースの方法では異なるタイプのセルを簡単に呼び出す方法です.

  
  
  
  
  1. - (UITableViewCell *)tableView:(UITableView *)tableView   
  2.          cellForRowAtIndexPath:(NSIndexPath *)indexPath 
  3.     NSString *key = self.keys[(NSUInteger) indexPath.row]; 
  4.     id value = [self.photo valueForKey:key]; 
  5.     UITableViewCell *cell; 
  6.     if ([key isEqual:PhotoRatingKey]) { 
  7.         cell = [self cellForRating:value indexPath:indexPath]; 
  8.     } else { 
  9.         cell = [self detailCellForKey:key value:value]; 
  10.     } 
  11.     return cell; 
  12.   
  13. - (RatingCell *)cellForRating:(NSNumber *)rating 
  14.                     indexPath:(NSIndexPath *)indexPath 
  15.     // ... 
  16.   
  17. - (UITableViewCell *)detailCellForKey:(NSString *)key 
  18.                                 value:(id)value 
  19.     // ... 
 
テーブルビューの編集
テーブルビューは簡単で使いやすい編集機能を提供しています.セルを並べ替えて削除することができます.これらのイベントが発生した場合、テーブルデータソースは、プロキシ方法によって通知される.したがって、実際の修正データを実行するために、論理的なプロキシ方法がよく見られます.
 
データを処理するのは完全にモデル層の仕事です.モデル層は、データソースプロキシ法から呼び出すことができるデータを削除し、並べ替えするためのインターフェースを提供するべきである.この方法では,コントローラは,モデル層の実現の詳細を知る必要はなく,ビューとモデル層の間のコーディネーターだけを演じている.もう一つの利点は、論理モデルがコントローラ層のものと相互作用しないようにテストが容易になることである.
 
結論
Table view controllers(および他のコントローラオブジェクト)は、モデルとビューオブジェクトとの間のコーディネーション・仲介の役割を果たすべきであり、彼らはモデルまたはビューの具体的な実装の詳細に関心を持つべきではない.これを覚えておけば、代表とデータソースの方法がより簡単で、維持しやすいサンプルコードになります.
 
このようにすると、Table view controllersのコード規模と複雑さを低減するだけでなく、モデル論理コードとビューコードをより適切な場所に置くことができます.コントローラの上下の間の実装の詳細は、簡単なAPIに隠されており、結果としてコードがより分かりやすく、協働している.
 
原文のリンク:  Flarian Kugler   伯楽オンライン-christtian
訳文のリンク:  http://blog.jobbole.com/53123/