MVC 學習

IOS 開發模式 之MVC模式

說到MVC 模式,根據意思來說 Model ,View,Controller  模型,視圖,控制。

說是這麼說,但是還是不明白到底應該怎麼弄。(這其實是說我自己的,從下面就能看出)。


Model  模型,建立一個數據模型,裏面是我們需要用到的數據,可以建立多個模型,一個模型裏面包含另一個模型。

View   視圖,創建視圖。把需要用到的控件視圖,建立一個子類。在裏面設置視圖,最後返回出來,代理一般在自己界面中是實現,一般就是自己創建的子類中實現。有時候還可以對model 的數據操作 

Controller 控制器。 裏面就是一些邏輯的處理 ,把返回的View 視圖添加到界面上,刪除控件等邏輯的是實現,對Model 數據的操作。

(我目前是這樣理解的,根據MVC的定義,View只需要處理視圖,對數據Model 的處理 應該在Controller 中,我目前在View 處理數據,以後再根據理解慢慢更改)

下面粘貼一段 網上覆制過來的其他網友的話:

在iOS cocoa touch 編程中, MVC機制被髮揮得淋漓盡致。 MVC 示意圖如下。 只有充分理解了MVC,才能在編寫出優雅的iOS app。爲充分理解 MVC, 相關的概念(比如: Delegate、 Protocol、 Notification 等)也要了然於胸。

     MVC 約定, Model 不允許與View 打交道。 Model 是管理數據的, 當Model中的數據發生變化時,與之對應的視圖應更新。 這就需要一種機制來支持。爲此 iOS 框架提供了兩種支持機制: Notification 和KVO (Key-Value Observing)。

  KVO 可簡單理解爲,爲你所關注的 Key 對象註冊一個監聽器。 當有數據發生變化時,就會發出廣播給所有的監聽器。

      MVC 也約定, View 不允許直接引用Modal, 它只能被Controller 所控制。 Controller 控制 View 顯示什麼數據。我們知道,View 所要顯示的數據是來源於 Modal, View 上產生的事件 ( 比如 Touch事件)需要通知 Controller。 既然MVC 不允許直接打交道,就需要提供一種機制。 

  不錯, iOS 確實提供了一種機制, 名曰: Delegate。 Delegate 這個詞, 有人將它譯爲“委託”,也有人將它譯爲“代理”。名稱上的差異沒有什麼,重要的是如何理解 Delegate。 Delegate設計模式的引入,就是爲了解決UIView與Controller松耦合互動問題。

網友的鏈接



下面的代碼 有我自己寫的 還有參考其他大神的


定義的Model

SectionModel

#import <Foundation/Foundation.h>

//分區模型

@interface SectionModel : NSObject

@property (nonatomic, copy) NSString *sectionTitle;

//是否可以展開

@property (nonatomic, assign) BOOL isExpanded;

//分區下面可以有很多個cell對應的模型

@property (nonatomic, strong) NSMutableArray *cellModels;

@end


CellModel

#import <Foundation/Foundation.h>

@interface CellModel : NSObject

@property (nonatomic, copy) NSString *title;

@end


創建View

我自定義了一個TableView 並在裏面對數據進行 處理,但是這樣不符合MVC模式 我只是根據自己理解這樣設置的

#import <UIKit/UIKit.h>

@interface TableView : UITableView

-(instancetype)initWithFrame:(CGRect)frame style:(UITableViewStyle)style;

@end


TableView 的實現文件 我導入了Model 模型文件

#import "TableView.h"

#import "HeaderView.h"

#import "SectionModel.h"

#import "CellModel.h"


@interface TableView ()<UITableViewDelegate,UITableViewDataSource,UIAlertViewDelegate>

@property (nonatomic,strong) NSMutableArray *dataArray;

@end



@implementation TableView

-(NSMutableArray *)dataArray

{

    if (_dataArray == nil) {

        _dataArray = [[NSMutableArray alloc]init];

        for (NSInteger i = 0; i < 3; i++) {

            //設置分區

            SectionModel *sectionModel = [[SectionModel alloc]init];

            sectionModel.isExpanded = NO;

            sectionModel.sectionTitle = [NSString stringWithFormat:@"section = %ld",i];

            //設置cell

            NSMutableArray *array =  [[NSMutableArray alloc]init];

            for (NSInteger j = 0; j < 5; j++) {

                CellModel *cellModel = [[CellModel alloc]init];

                cellModel.cellTitle = [NSString stringWithFormat:@"section = %ld, row = %ld",i,j];

                cellModel.webImageUrl = [NSString stringWithFormat:@""];

                [array addObject:cellModel];

            }

            sectionModel.cellModels = array; //分區模型裏面添加cell模型

            [_dataArray addObject:sectionModel];    //數據裏面添加分區模型

        }

    }

    return _dataArray;

}


-(instancetype)initWithFrame:(CGRect)frame style:(UITableViewStyle)style

{

    if (self = [super initWithFrame:frame style:style]) {

        

        self.delegate = self;

        self.dataSource = self;

        self.showsVerticalScrollIndicator = NO;

        self.showsHorizontalScrollIndicator = NO;

        [self registerClass:[HeaderView class] forHeaderFooterViewReuseIdentifier:headerIdentifier];

    }

    return self;

}


#pragma mark UITableViewDataSource

-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView

{

    return self.dataArray.count;

}

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

{

    SectionModel *sectionMocel = self.dataArray[section];

    

    return  sectionMocel.isExpanded ? sectionMocel.cellModels.count : 0;

}

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

{

    static NSString *identifier = @"TableView";

    

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];

    if (cell == nil) {

        cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];

    }

    UIView *selectBg = [[UIView alloc]initWithFrame:cell.frame];

    selectBg.backgroundColor = [UIColor redColor];

    cell.selectedBackgroundView = selectBg;

    

    cell.backgroundColor = [UIColor grayColor];

    cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;

    

    SectionModel *sectionModel = self.dataArray[indexPath.section];

    CellModel *cellModel = sectionModel.cellModels[indexPath.row];

    cell.textLabel.text = cellModel.cellTitle;

    

    return cell;

}

-(BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath

{

    return YES;

}

#pragma mark UITableViewDelegate

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath

{

    return 44;

}

-(CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section

{

    return headerHeight;

}

-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section

{

    HeaderView *headerView = [tableView dequeueReusableHeaderFooterViewWithIdentifier:headerIdentifier];

    SectionModel *sectionModle = self.dataArray[section];

    headerView.model = sectionModle;

    headerView.expandCallBack = ^(BOOL isExpanded){

    

        [tableView reloadSections:[NSIndexSet indexSetWithIndex:section] withRowAnimation:UITableViewRowAnimationFade];

    };

    return headerView;

}


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

{

    [tableView deselectRowAtIndexPath:indexPath animated:NO];

    

    SectionModel *sectionModel = self.dataArray[indexPath.section];

    CellModel *cellModel = sectionModel.cellModels[indexPath.row];

    NSLog(@"點擊到的是%@",cellModel.cellTitle);

    

    [self alert:sectionModel.sectionTitle message:cellModel.cellTitle];

}


-(UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath

{

    return UITableViewCellEditingStyleDelete;

}


-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath

{

    if (editingStyle == UITableViewCellEditingStyleDelete){

        SectionModel *sectionModel = self.dataArray[indexPath.section];

        [sectionModel.cellModels removeObjectAtIndex:indexPath.row];

        NSLog(@"刪除");

    }

    

    [tableView reloadData];

}


-(void)tableView:(UITableView *)tableView didEndEditingRowAtIndexPath:(NSIndexPath *)indexPath

{

    NSLog(@"結束編輯");

}


-(NSString *)tableView:(UITableView *)tableView titleForDeleteConfirmationButtonForRowAtIndexPath:(NSIndexPath *)indexPath

{

    return @"點擊刪除";

}


-(void)alert:(NSString *)title message:(NSString *)messsage

{

    UIAlertView *alert = [[UIAlertView alloc]initWithTitle:title message:messsage delegate:self cancelButtonTitle:@"取消" otherButtonTitles:@"確定", nil];

    [alert show];

}


-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex

{

    //確定 取消 0

    switch (buttonIndex) {

        case 0:

            NSLog(@"0");

            break;

        case 1:

            NSLog(@"1");

            break;

            

        default:

            break;

    }

}


Controller

Controller 文件 裏面就比較簡單了

#import "TableView.h" //導入子類文件

- (void)viewDidLoad {

    [super viewDidLoad];

UITableView *tableView = [[TableView alloc]initWithFrame:CGRectMake(0, 100, View_Width, 300) style:UITableViewStylePlain];

    [self.view addSubview:tableView];

}


我自定義表頭

#import <UIKit/UIKit.h>

#import <Foundation/Foundation.h>

@class SectionModel;


FOUNDATION_EXPORT NSString *headerIdentifier;

FOUNDATION_EXPORT CGFloat headerHeight;

typedef void(^HeaderViewExpandCallBack)(BOOL isExpanded);


@interface HeaderView : UITableViewHeaderFooterView


@property (nonatomic,strong) SectionModel *model;

@property (nonatomic,copy) HeaderViewExpandCallBack expandCallBack;

-(instancetype)initWithReuseIdentifier:(NSString *)reuseIdentifier;

@end


表頭文件的是實現

#import "HeaderView.h"

#import "SectionModel.h"



NSString *headerIdentifier = @"headerIdentifier";

CGFloat headerHeight = 44;



@interface HeaderView ()


@property (nonatomic,strong) UIImageView *arrowImageView;

@property (nonatomic,strong) UILabel *titleLabel;


@end


@implementation HeaderView


-(instancetype)initWithReuseIdentifier:(NSString *)reuseIdentifier

{

    if (self = [super initWithReuseIdentifier:reuseIdentifier]) {

        

        CGFloat width = [UIScreen mainScreen].bounds.size.width;

        

        self.arrowImageView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"back1.png"]];

        self.arrowImageView.frame = CGRectMake(0, (44-8)/2, 15, 8);

        [self.contentView addSubview:self.arrowImageView];

        

        UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];

        [button addTarget:self action:@selector(onExpand:) forControlEvents:UIControlEventTouchUpInside];

        [self.contentView addSubview:button];

        button.frame = CGRectMake(0, 0, width, 44);

        

        self.titleLabel = [[UILabel alloc]initWithFrame:CGRectMake(35, 0, 200, 44)];

        self.titleLabel.textColor = [UIColor blackColor];

        self.titleLabel.backgroundColor = [UIColor clearColor];

        [self.contentView addSubview:self.titleLabel];

        self.contentView.backgroundColor = [UIColor greenColor];

        

        UIView *line = [[UIView alloc]initWithFrame:CGRectMake(0, 43, width, 1)];

        line.backgroundColor = [UIColor lightGrayColor];

        [self.contentView addSubview:line];

        

    }

    return self;

}


//我們在配置數據的時候,也會根據isExpanded狀態來顯示圖片的方向,否則重用後就恢復原狀了。

-(void)onExpand:(UIButton *)sender

{

    self.model.isExpanded = !self.model.isExpanded;

    

    [UIView animateWithDuration:0.25 animations:^{

        

        if (self.model.isExpanded) {

            self.arrowImageView.transform = CGAffineTransformIdentity;

        }else{

            self.arrowImageView.transform = CGAffineTransformMakeRotation(M_PI);

        }

    }];

    

    if (self.expandCallBack) {

        self.expandCallBack(self.model.isExpanded);

    }

    

}


//重寫setModel方法來配置數據   get 只讀  set 設置

-(void)setModel:(SectionModel *)model

{

    if (_model != model) {

        _model = model;

    }

    

    if (model.isExpanded) {

        self.arrowImageView.transform = CGAffineTransformIdentity;

    }else{

        self.arrowImageView.transform = CGAffineTransformMakeRotation(M_PI);

    }

    

    self.titleLabel.text = model.sectionTitle;

}


@end










發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章