http://www.tuicool.com/articles/JbiMvumswift
在上一篇文章中 咱們講了經過整合tableview的代理,來達到代碼複用,減小控制器代碼量的效果,今天咱們接着來說另外的一些方法來減輕控制器代碼量,整合封裝,提升代碼的可讀性。less
TableView在iOS應用程序中是很是通用的組件,Apple爲咱們提供了tableview專屬的view controller類UITableViewController。Table view controller實現了一些很是有用的特性,來避免一遍又一遍的寫那些死板的代碼!ui
可是,咱們常常會遇到這樣一個問題,table view controller 只限於管理一個全屏展現的table view。大多數狀況下,咱們想達到的效果就是這樣,可是若是不是呢,咱們就只能使用一般的控制器,其實還有其餘的方法來達到使用table view controller 的目的。atom
Table view controllers 會在第一次顯示 table view 的時候幫你加載其數據。另外,它還會幫你切換 table view 的編輯模式、響應鍵盤通知、以及一些小任務,好比閃現側邊的滑動提示條和清除選中時的背景色。爲了讓這些特性生效,當你在子類中覆寫相似 viewWillAppear: 或者 viewDidAppear: 等事件方法時,須要調用 super 版本。spa
Table view controllers 相對於標準 view controllers 的一個特別的好處是它支持 Apple 實現的「下拉刷新」。目前,文檔中惟一的使用 UIRefreshControl 的方式就是經過 table view controller ,雖然經過努力在其餘地方也能讓它工做(例如直接將UIRefreshControl直接addSubView到tableview),但極可能在下一次 iOS 更新的時候就不行了。代理
這些要素加一塊兒,爲咱們提供了大部分 Apple 所定義的標準 table view 交互行爲,若是你的應用剛好符合這些標準,那麼直接使用 table view controllers 來避免寫那些死板的代碼是個很好的方法。orm
Table view controllers 的 view 屬性永遠都是一個 table view。若是你稍後決定在 table view 旁邊顯示一些東西(好比一個地圖,一個小的按鈕),若是不依賴於那些奇怪的 hacks,估計就沒什麼辦法了。對象
若是你是用代碼或 .xib 文件來定義的界面,那麼遷移到一個標準 view controller 將會很是簡單。可是若是你使用了 storyboards,那麼這個過程要多包含幾個步驟。除非從新建立,不然你並不能在 storyboards 中將 table view controller 改爲一個標準的 view controller。這意味着你必須將全部內容拷貝到新的 view controller,而後再從新鏈接一遍。blog
最後,你須要把遷移後丟失的 table view controller 的特性給補回來。大多數都是 viewWillAppear: 或 viewDidAppear: 中簡單的一條語句。切換編輯模式須要實現一個 action 方法,用來切換 table view 的 editing 屬性。大多數工做來自從新建立對鍵盤的支持。事件
在選擇這條路以前,其實還有一個更輕鬆的選擇,它能夠經過分離咱們須要關心的功能(關注點分離),讓你得到額外的好處:
和徹底拋棄 table view controller 不一樣,你還能夠將它做爲 child view controller 添加到其餘 view controller 中。這樣,parent view controller 在管理其餘的你須要的新加的界面元素的同時,table view controller 還能夠繼續管理它的 table view。
咱們來看代碼:
我有一個UITableViewController
@interface MyTableViewController () @end @implementation MyTableViewController - (void)viewDidLoad { [super viewDidLoad]; [self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"cell"]; self.refreshControl = [[UIRefreshControl alloc] initWithFrame:CGRectMake(0, 0, 20, 20)]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; } #pragma mark - Table view data source - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return 1; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return 10; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell" forIndexPath:indexPath]; cell.textLabel.text = [NSString stringWithFormat:@"%ld",(long)indexPath.row]; return cell; }
我想要使用這個UITableViewController來管理個人tableview
而後 我還有一個view controller,在這個view controller中 我既要包含這個table view 還要有其餘的view 用上面的加自controller來實現
@implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; [self addMyTableViewController]; [self addOtherView]; } //添加zicontroller - (void)addMyTableViewController{ MyTableViewController *vc = [[MyTableViewController alloc] init]; [self addChildViewController:vc]; CGRect frame = self.view.bounds; frame.size.height = 300; vc.view.frame = frame; [self.view addSubview:vc.view]; [vc didMoveToParentViewController:self]; } - (void)addOtherView{ UIButton *btn = [[UIButton alloc] initWithFrame:CGRectMake(20, 400, 100, 30)]; btn.backgroundColor = [UIColor redColor]; [self.view addSubview:btn]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; }
若是咱們使用了這種方法,那麼咱們就須要在子controller 和 父 controller之間創建起通訊渠道,由於,若是點擊了cell,在父類中我須要知道,雖然這樣看起來是額外的開銷,可是咱們的代碼變得很是清晰,複用性也更高
咱們怎樣創建起通訊呢,固然最簡單的就是使用delegate,這個就比較簡單的了
#import <UIKit/UIKit.h> @protocol MyTableViewControllerDelegate <NSObject> - (void)didSelectCell; @end @interface MyTableViewController : UITableViewController @property (nonatomic, weak) id<MyTableViewControllerDelegate> delegate; @end
傳遞點擊事件
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{ [tableView deselectRowAtIndexPath:indexPath animated:YES]; if ([self.delegate respondsToSelector:@selector(didSelectCell)]) { [self.delegate didSelectCell]; } }
在父controller中捕獲點擊事件
MyTableViewController *vc = [[MyTableViewController alloc] init]; vc.delegate = self;
-(void)didSelectCell{ NSLog(@"點擊"); }
若是咱們想自定義cell內部的狀態,在點擊cell的時候 自定義高亮樣式 咱們知道有這樣的delegate方法,讓咱們在view controller中操做,可是咱們要講的就是減小view controller的代碼
首先咱們來看看在view controller 中 怎樣來改變
- (void)tableView:(UITableView *)tableView didHighlightRowAtIndexPath:(NSIndexPath *)indexPath { //高亮時 } - (void)tableView:(UITableView *)tableView didUnhighlightRowAtIndexPath:(NSIndexPath *)indexPath { //非高亮 }
View 的實現細節和 delegate 的實現交織在一塊兒了。咱們應該把這些細節移到 cell 自身中去。
-(void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated{ [super setHighlighted:highlighted animated:animated]; if (highlighted) { //高亮時改變cell的狀態 }else{ //非高亮時改變 } }
Table view controllers(以及其餘的 controller 對象!)應該在 model 和 view 對象之間扮演協調者和調解者的角色。它不該該關心明顯屬於 view 層或 model 層的任務。你應該始終記住這點,這樣 delegate 和 data source 方法會變得更小巧,最多包含一些簡單的樣板代碼。
這不只減小了 table view controllers 那樣的大小和複雜性,並且還把業務邏輯和 view 的邏輯放到了更合適的地方。Controller 層的裏裏外外的實現細節都被封裝成了簡單的 API,最終,它變得更加容易理解,也更利於團隊協做。
參考:
https://www.objccn.io/issue-1-2/
歡迎你們關注個人公衆號,我會按期分享一些我在項目中遇到問題的解決辦法和一些iOS實用的技巧,現階段主要是整理出一些基礎的知識記錄下來
http://ppsheep.com/2016/12/14/UITableViewController%E5%AD%90%E6%8E%A7%E5%88%B6%E5%99%A8%E7%9A%84%E4%BD%BF%E7%94%A8%E6%96%B9%E6%B3%95/?utm_source=tuicool&utm_medium=referral