TableView 单元格中的 MVVM

Posted

技术标签:

【中文标题】TableView 单元格中的 MVVM【英文标题】:MVVM in TableView Cell 【发布时间】:2021-05-25 07:57:06 【问题描述】:

希望你一切都好,我正在开发一个应用程序,它使用 TableView 向使用 ViewModel 的用户显示提要,我的 ViewModel 包含一个包含所有单元格数据的变量,ViewModel 还包含其他数据,我在做什么正在将整个 ViewModel 引用和 indexPath 传递给单元格,您可以在这里看到:

func configureCell(feedsViewModelObj feedsViewModel: FeedsViewModel, cellIndexPath: IndexPath, presentingVC: UIViewController)
    //Assigning on global variables
    self.feedsViewModel = feedsViewModel
    self.cellIndexPath = cellIndexPath
    self.presentingVC = presentingVC
   
    let postData = feedsViewModel.feedsData!.data[cellIndexPath.row]
    
    //Populate
    nameLabel.text = postData.userDetails.name
    userImageView.sd_setImage(with: URL(string: postData.userDetails.photo), placeholderImage: UIImage(named: "profile-image-placeholder"))
    
    updateTimeAgo()
    postTextLabel.text = postData.description
    upvoteBtn.setTitle(postData.totalBull.toString(), for: .normal)
    upvoteBtn.setSelected(selected: postData.isClickedBull, isAnimated: false)
    downvoteBtn.setSelected(selected: postData.isClickedBear, isAnimated: false)
    downvoteBtn.setTitle(postData.totalBear.toString(), for: .normal)
    commentbtn.setTitle(postData.totalComments.toString(), for: .normal)
    optionsBtn.isHidden = !(postData.canEdit && postData.canDelete)
    
    populateMedia(mediaData: postData.files)

那么,将完整的 ViewModel 引用和索引传递给单元格然后每个单元格从数据数组访问其数据是正确还是好方法? (如果没有请指导我)。 非常感谢。

【问题讨论】:

我会搜索“MVVM Swift viewModel”,看看其他人是如何做到的。 【参考方案1】:

*不需要将整个 ViewModel 引用和 indexPath 传递给单元格。收到数据后回调:

ViewController -> ViewModel -> TableViewDatasource -> TableViewCell.*

视图控制器

 class ViewController: UIViewController 
        var viewModel: ViewModel?
        
        override func viewDidLoad() 
            super.viewDidLoad()
            TaxiDetailsViewModelCall()
        
        
        func TaxiDetailsViewModelCall() 
            viewModel = ViewModel()
            viewModel?.fetchFeedsData(completion: 
                self?.tableViewDatasource = TableViewDatasource(_feedsData:modelview?.feedsData ?? [FeedsData]())
                DispatchQueue.main.async 
                    self.tableView.dataSource = self.tableViewDatasource
                    self.tableView.reloadData()
                
           )
        
    

查看模型

class ViewModel 
var feedsData = [FeedsData]()
    func fetchFeedsData(completion: () -> ())  
        let _manager = NetworkManager()
        _manager.networkRequest(_url: url, _modelType: FeedsData.self, _sucessData:  data in
            self.feedsData.accept(data)
       completion()
        )
    

TableView 数据源

 class TableViewDatasource: NSObject,UITableViewDataSource 
        
        var feedsData: [FeedsData]?
        init(_feedsData: [FeedsData]) 
            feedsData = _feedsData
        
        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
            return feedsData.count
        
        
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
            guard let cell = tableView.dequeueReusableCell(withReuseIdentifier: "TableViewCellName", for: indexPath) as? TableViewViewCell else 
                return TableViewViewCell()
            
            cell.initialiseOutlet(_feedsData: feedsData[indexPath.row])
            return cell
        
    

表格视图单元格

class TableViewCell: UITableViewCell 
            
            @IBOutlet weak var nameLabel : UILabel!
            @IBOutlet weak var userImageView : UIImageView!
            @IBOutlet weak var postTextLabel : UILabel!
            @IBOutlet weak var upvoteBtn : UIButton!
            @IBOutlet weak var downvoteBtn : UIButton!
            @IBOutlet weak var commentbtn : UIButton!
            @IBOutlet weak var optionsBtn : UIButton!
            
            
            override func awakeFromNib() 
                super.awakeFromNib()
            
            
            /*
             Passing feedsData Object from TableViewDatasource
             */
            func initialiseOutlet(_feedsData: feedsData) 
                nameLabel.text = _feedsData.userDetails.name
                userImageView.sd_setImage(with: URL(string: _feedsData.userDetails.photo), placeholderImage: UIImage(named: "profile-image-placeholder"))
                
                updateTimeAgo()
                postTextLabel.text = _feedsData.description
                upvoteBtn.setTitle(_feedsData.totalBull.toString(), for: .normal)
                upvoteBtn.setSelected(selected: _feedsData.isClickedBull, isAnimated: false)
                downvoteBtn.setSelected(selected: _feedsData.isClickedBear, isAnimated: false)
                downvoteBtn.setTitle(_feedsData.totalBear.toString(), for: .normal)
                commentbtn.setTitle(_feedsData.totalComments.toString(), for: .normal)
                optionsBtn.isHidden = !(_feedsData.canEdit && postData.canDelete)
            
        

【讨论】:

但是这样我们的cell(view)是直接和model通信的,是不是违反了mvvm规则? 模型视图属性被传递给 TableViewDatasource。单元格(视图)不直接与模型通信。请找到代码 sn-p-TableViewDatasource(_feedsData:modelview?.feedsData ?? [FeedsData]())。

以上是关于TableView 单元格中的 MVVM的主要内容,如果未能解决你的问题,请参考以下文章

Swift:Tableview 中特定单元格中的 addSublayer 不是每个单元格

如何在可重用的 tableView 单元格中更新 UITextfield 中的文本值,每个单元格中的值不同

尝试快速从数组中删除时,不应删除 tableview 单元格中的最后一个单元格

多个tableView单元格中的多个collectionView

Tableview 禁用单元格中的用户交互

TableView 单元格中的 UITextField