Objective-C

テーブルビューでMVCモデル分けをしてみた

前回の記事に引き続き、MVCモデルにおけるデリゲートの使い方に関して備忘録を残します。

テーブルビューのクラス分けに挑戦してみました。
その際にデリゲートの使い方が見えてきたので、ここに残そうと思います。
今回は、DBの代わりにArrayを使っています。

View

※この他にラベルを3つ配置したカスタムセルクラスを用意しています。

TableViewProvider.h
@import UIKit;
#import <Foundation/Foundation.h>
#import "CellDataModel.h"

@interface TableViewProvider : NSObject <UITableViewDataSource>
@property (strong, nonatomic) NSArray<CellDataModel *> *dataList;
@end

TableViewProvider.m
@import UIKit;
#import "TableViewProvider.h"
#import "CustomCell.h"

@interface TableViewProvider ()

@end

@implementation TableViewProvider

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return self.dataList.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    CustomCell *cell = [tableView dequeueReusableCellWithIdentifier:[CustomCell identifier] forIndexPath:indexPath];

    cell.numberLabel.text = self.dataList[indexPath.row].numdber;
    cell.nameLabel.text = [NSString stringWithFormat:@"名前:%@", self.dataList[indexPath.row].name];
    cell.adressLabel.text = [NSString stringWithFormat:@"住居:%@", self.dataList[indexPath.row].adress];

    return cell;
}
@end

Controller

.hには設定なし

ListViewController.m
#import "ListViewController.h"
#import "CustomCell.h"
#import "TableViewProvider.h"
#import "DataModel.h"

@interface ListViewController () <UITableViewDelegate, DataModelDelegate>
@property (weak, nonatomic) IBOutlet UITableView *tableView;
@property (nonatomic) TableViewProvider *provider;
@property (nonatomic) DataModel *dataModel;
@property (nonatomic) int counter;
@end

@implementation ListViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    [self setupTableView];

    self.dataModel = [[DataModel alloc] init];
    self.dataModel.delegate = self;
    [self.dataModel resetDatabase];
    self.counter = 1;
}

- (void)setupTableView {
    UINib *nib = [UINib nibWithNibName:[CustomCell nibName] bundle:nil];
    [self.tableView registerNib:nib forCellReuseIdentifier:[CustomCell identifier]];

    self.provider = [[TableViewProvider alloc] init];
    self.tableView.delegate = self;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
    CustomCell *cell = [tableView cellForRowAtIndexPath:indexPath];
    NSLog(@"%@", cell.nameLabel.text);
}

- (IBAction)createTableViewCell:(id)sender {
    NSString *number = [NSString stringWithFormat:@"%d", self.counter];
    [self.dataModel allItems:number name:@"hogehoge" adress:@"tokyo"];
    self.counter++;

    self.provider.dataList = self.dataModel.items;
    self.tableView.dataSource = self.provider;
    [self.tableView reloadData];
}

// 今回のArrayを用いたコードでは必要ないが、モデルクラスからリロードをかける必要がある場合は、デリゲートメソッドとして使用する
- (void)reloadData {
    [self.tableView reloadData];
}

@end

Model

DataModel.h
#import <Foundation/Foundation.h>
#import "CellDataModel.h"

@protocol DataModelDelegate <NSObject>
// デリゲートメソッドを使用する場合に記載
- (void)reloadData;
@end

@interface DataModel : NSObject

// デリゲートメソッドを使用する場合に記載
@property (weak, nonatomic) id<DataModelDelegate> delegate;

@property (strong, nonatomic) NSMutableArray *items;
- (void)resetDatabase;
- (void)allItems:(NSString *)number name:(NSString *)name adress:(NSString *)adress;
@end

DataModel.m
#import "DataModel.h"
#import "CellDataModel.h"

@interface DataModel ()
// DBのカラムの代わりのプロパティ
@property (strong, nonatomic) NSMutableArray *numberList;
@property (strong, nonatomic) NSMutableArray *nameList;
@property (strong, nonatomic) NSMutableArray *adressList;
@end

@implementation DataModel
- (void)allItems:(NSString *)number name:(NSString *)name adress:(NSString *)adress{

    CellDataModel *item = [[CellDataModel alloc]initWithPropty:number name:name adress:adress];
    [self.items addObject:item];
}

- (void)resetDatabase {
    self.items = [@[] mutableCopy];
    self.numberList = [@[] mutableCopy];
    self.nameList = [@[] mutableCopy];
    self.adressList = [@[] mutableCopy];
}
@end

データモデルとして、3つのプロパティを持ったCellDataModelクラスを別途用意してあります。

CellDataModel.h
#import <Foundation/Foundation.h>

@interface CellDataModel : NSObject
@property (strong, nonatomic)NSString *numdber;
@property (strong, nonatomic)NSString *name;
@property (strong, nonatomic)NSString *adress;

- (instancetype)initWithPropty:(NSString *)number name:(NSString *)name adress:(NSString *)adress;
@end

CellDataModel.h
#import "CellDataModel.h"

@implementation CellDataModel

- (instancetype)initWithPropty:(NSString *)number name:(NSString *)name adress:(NSString *)adress {

    self = [super init];
    if (self) {
        self.numdber = number;
        self.name = name;
        self.adress = adress;
    }
    return self;
}

@end

まとめ

今回は、モデルはDBの代わりにArrayを使っていますが、適宜DBコードに置き換えて使っていこうと思います。
ちなみに、自作デリゲートを使ってModelクラスからViewの更新を行う際は、以下のような流れで考えています。

  1. contorollerクラスが、Viewクラスからデータを受け取る。
  2. modelクラスが、controllerクラスからデータを受け取り、DBに保存する。
  3. modelクラスが、controllerクラスにデリゲート通知を送る。
  4. controllerクラス、上記通知を受け取り、デリゲートメソッドを実行する。
  5. controllerクラスのデリゲートメソッドで、modelクラスにデータソース作成を依頼する
  6. modelクラスがデータソースの作成をし、controllerクラスに返す。
  7. controllerクラスは、modelクラスからデータソースを受け取り、(そのまま)viewクラスにデータを渡す。
  8. controllerクラスのリロードメソッドを呼び、viewクラスを更新する。