将viewModel设置为表视图数据源是错误的吗?

时间:2017-09-27 07:57:37

标签: ios swift uitableview design-patterns mvvm

我见过许多代码,其中将ViewModel设置为表视图数据源,而许多代码不设置。

1.将数据源设置到ViewModel一段时间是有意义的,因为数据源方法主要处理表示逻辑。

2.另一方面,将ViewModel设置为数据源意味着您正在实施cellForRowAtIndexPath等,这使得它不独立于UIKit

构建应用程序的最佳方式是什么,请澄清一下?

3 个答案:

答案 0 :(得分:3)

答案是,没有最好的方法来构建应用。根据您的需求,有很多好方法可以组织课程。 下面是我如何组织viewModel以便在表视图中显示数据的示例:

PaymentSectionItem是我的ViewModel

<强> PaymentSectionItem.h

@interface PaymentSectionItem : NSObject

@property (assign, nonatomic) NSUInteger itemID;
@property (strong, nonatomic) NSString *name;
@property (strong, nonatomic) NSArray *elements;
@property (assign, nonatomic) kTransactionType transactionType;

+ (NSArray<PaymentSectionItem *> *)allSectionItemsWithData;

@end

<强> PaymentSectionItem.m

@implementation PaymentSectionItem

#pragma mark - Custom Accessors

- (NSString *)localizedTitle {
    NSString *title = [NSString stringWithFormat:@"%@_section_title", self.name];
    return NSLocalizedString(title, @"Section title");
}

- (NSString *)localizedDescription {
    NSString *title = [NSString stringWithFormat:@"%@_section_description", self.name];
    return NSLocalizedString(title, @"Section description");
}

#pragma mark - Constructor

- (instancetype)initWithSectionItem:(kSectionItem)sectionItem {
    self = [super init];
    if (self) {
        [self setupFromHomeSectionItem:sectionItem];
    }
    return self;
}

#pragma mark - Private

- (void)setupFromHomeSectionItem:(kSectionItem)sectionItem {
    self.itemID = sectionItem;
    switch (sectionItem) {
        case kSectionItem1: {
            self.name = @"phones";
            self.elements = [Payment findPaymentsType1];
            break;
        }
        case kSectionItem2: {
            self.name = @"autopay";
            self.elements = [Payment findPaymentsType2];
            break;
        }
        case kSectionItem3: {
            self.name = @"trustfund";
            self.elements = [Payment findPaymentsType3];
            self.transactionType = kTransactionTypeTrustFund;
            break;
        }
        case kSectionItem4: {
            self.name = @"debitlink";
            self.elements = [Payment findPaymentsType4];
            self.transactionType = kTransactionTypeDebitLink;
            break;
        }
        case kSectionItem5: {
            self.name = @"pindebit";
            self.elements = [Payment findPaymentsType5];
            self.transactionType = kTransactionTypePINDebit;
            break;
        }
    }
}

#pragma mark - Public

+ (NSArray<PaymentSectionItem *> *)allSectionItemsWithData {
    NSMutableArray *items = [NSMutableArray new];
    [items addObject:[[PaymentSectionItem alloc] initWithSectionItem:kSectionItem1]];
    [items addObject:[[PaymentSectionItem alloc] initWithSectionItem:kSectionItem2]];
    [items addObject:[[PaymentSectionItem alloc] initWithSectionItem:kSectionItem3]];
    [items addObject:[[PaymentSectionItem alloc] initWithSectionItem:kSectionItem4]];
    [items addObject:[[PaymentSectionItem alloc] initWithSectionItem:kSectionItem5]];
    return items;
}

ViewController.h

- (void)viewDidLoad {
    [super viewDidLoad];
    self.items = [PaymentSectionItem allSectionItemsWithData];
}



#pragma mark - UITableViewDataSource

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return self.items.count;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return self.items[section].elements.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    GTLAutoPaySectionItem *sectionItem = self.items[indexPath.section];
    NSString *identifier = [self identifierForSectionItem:sectionItem atIndex:indexPath];
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
    UITableViewCell<PaymentCellProtocol> *paymentCell = (UITableViewCell<PaymentCellProtocol> *)cell;
    [paymentCell setupCellFromValue:sectionItem.elements[indexPath.row] withSectionItem:sectionItem];
    return cell;
}

如您所见,在我的情况下,我有一个包含许多部分的表视图,每个部分都有元素。这正是我在ViewModel中所做的。如果您有任何其他问题,请随时询问。

答案 1 :(得分:1)

否,将视图模型设置为数据源并充当数据模型并没有错。

好吧,这本书说,保持M,V&amp; C分离以提高可读性和可维护性。但现在我们有多种设计模式来保持简单。基本上在模型中我们只存储数据,并且它的操作是在视图级别完成的,这是实现View的好方法。

你不能总是有一个紧密耦合或松散耦合的M&amp; V.这取决于这两者的复杂程度。

答案 2 :(得分:0)

<强>视图模型

你的建议并没有错。在我看来,视图模型只是简单的逻辑,如字体和颜色。据我所知,没有人为此宣布过规则,但我希望视图模型很简单。

在我看来,您的桌面视图所在的位置应该与您的模型无关。假设你的tableView的superview是一个UITableViewCell。在这种情况下,我会通过回调连接逻辑。

所以回调就是这个。

protocol EventTableViewCellDatasource: class {
  func showTimesTableViewDatasource() -> UITableViewDataSource
}

细胞会这样做

class EventTableViewCell: UITableViewCell {

  weak var datasource: EventTableViewCellDatasource?

  @IBOutlet weak private var tableView: ShowTimesTableView! {
    didSet {
      tableView.dataSource = datasource?.showTimesTableViewDatasource()
    }
  }

  ...