Welcome to MLink Developer Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
219 views
in Technique[技术] by (71.8m points)

ios - Array is being updated late - Swift - MVVM

Hello guys I'm kinda new with implementing the MVVM pattern and I'm trying to figure out why my array is being updated so late, I mean if I'm not using DispatchQueue it wont load up, I mean I'm trying to separate the tableviewdatasource from viewcontroller and it seems to be a harm more than useful. Here's my Code:

ViewModel:

import Foundation
import UIKit

class NotificationsViewModel: NSObject {
    
    private(set) var notificationsData: [Notification]! {
        didSet {
            self.bindNotificationsViewModelToController()
        }
    }
    
    var bindNotificationsViewModelToController : (() -> ()) = {}
    
    var arrOfNotifications = [Notification]()
    
    var selectedCounter = 0
    var notificationIsRead = false
    
    override init() {
        super.init()
        callFuncToGetNotData()
        
    }
    
    
    func callFuncToGetNotData()  {
        DispatchQueue.main.async {
            var tempNotificationsArr : [Notification] = []
            
            var notification1 = Notification(image: UIImage(named: "messageImage")!, title: "Hello1", date: Date.getCurrentDate(Date())(), team: "In: Team1", isRead: false)
            var notification2 = Notification(image: UIImage(named: "messageImage")!, title: "Hello2", date: Date.getCurrentDate(Date())(), team: "In: QA Teams", isRead: true)
            
            
            tempNotificationsArr.append(notification1)
            tempNotificationsArr.append(notification2)
            
            self.notificationsData = tempNotificationsArr
        }
        
    }
    
    
    func setTitle(title:String, subtitle:String) -> UIView {
        
        let titleLabel = UILabel(frame: CGRect(x: 0, y: -2, width: 0, height: 0))
        
        titleLabel.backgroundColor = UIColor.clear
        titleLabel.textColor = UIColor.white
        titleLabel.font = UIFont.boldSystemFont(ofSize: 17)
        titleLabel.text = title
        titleLabel.sizeToFit()
        
        let subtitleLabel = UILabel(frame: CGRect(x:0, y:18, width:0, height:0))
        subtitleLabel.backgroundColor = .clear
        subtitleLabel.textColor = .white
        subtitleLabel.font = UIFont.systemFont(ofSize: 12)
        subtitleLabel.text = subtitle
        subtitleLabel.sizeToFit()
        
        
        let titleView = UIView(frame: CGRect(x: 0, y: 0, width: max(titleLabel.frame.size.width, subtitleLabel.frame.size.width), height: 30))
        titleView.addSubview(titleLabel)
        titleView.addSubview(subtitleLabel)
        
        let widthDiff = subtitleLabel.frame.size.width - titleLabel.frame.size.width
        
        if widthDiff < 0 {
            let newX = widthDiff / 2
            subtitleLabel.frame.origin.x = abs(newX)
        } else {
            let newX = widthDiff / 2
            titleLabel.frame.origin.x = newX
        }
        
        return titleView
    }
    
    func selectAllRows(_ tableView: UITableView) {
        for section in 0..<tableView.numberOfSections {
            for row in 0..<tableView.numberOfRows(inSection: section) {
                tableView.selectRow(at: IndexPath(row: row, section: section), animated: false, scrollPosition: .none)
            }
        }
    }
    
    func deselectAllRows(_ tableView: UITableView) {
        for section in 0..<tableView.numberOfSections {
            for row in 0..<tableView.numberOfRows(inSection: section) {
                tableView.deselectRow(at: IndexPath(row: row, section: section), animated: false)
            }
        }
    }
    
    
    func getAlertSheet() -> UIAlertController {
        let alertController = UIAlertController(title: nil, message: "(selectedCounter) Message", preferredStyle: .actionSheet)
        
        let cancelAction = UIAlertAction(title: "Cancel", style: .cancel) { (action) in
            // ...
        }
        alertController.addAction(cancelAction)
        
        
        let markAsUnReadAction = UIAlertAction(title: "Mark as Unread", style: .default) { (action) in
        }
        alertController.addAction(markAsUnReadAction)
        
        let flag = UIAlertAction(title: "Flag", style: .default) { (action) in
            //
        }
        alertController.addAction(flag)
        
        let markAsRead = UIAlertAction(title: "Mark as Read", style: .default) { (action) in
            //
        }
        alertController.addAction(markAsRead)

        return alertController
    }


    func enableButtons(_ markBtn: UIBarButtonItem,_ selectAllBtn: UIBarButtonItem,_ deleteBtn: UIBarButtonItem) {
        selectedCounter+=1
        notificationIsRead = true
        print(selectedCounter)
            markBtn.isEnabled = true
            selectAllBtn.isEnabled = true
            deleteBtn.isEnabled = true
        
    }

    func disableButtons(_ markBtn: UIBarButtonItem,_ selectAllBtn: UIBarButtonItem,_ deleteBtn: UIBarButtonItem) {
        selectedCounter -= 1
        notificationIsRead = false
        if selectedCounter == 0 {
            markBtn.isEnabled = false
            selectAllBtn.isEnabled = false
            deleteBtn.isEnabled = false
        }
        
    }
}

ViewController:

import UIKit
class NotificationsViewController: UIViewController, ViewControllerDelegate {
    
    @IBOutlet weak var notificationsTableView: UITableView!
    @IBOutlet weak var toolBar: UIToolbar!
    @IBOutlet weak var markButton: UIBarButtonItem!
    @IBOutlet weak var selectAllButton: UIBarButtonItem!
    @IBOutlet weak var deleteButton: UIBarButtonItem!
    
    private var notificationsViewModel : NotificationsViewModel!
    
    private var dataSource : NotificationTableViewDataSource<NotificationCell,Notification>!
    
    var tableViewDelegate: TableViewDelegate?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        callToViewModelForUIUpdate()
        configureTableView()
        configureEditButton()
        self.navigationItem.titleView = notificationsViewModel.setTitle(title: "Notifications", subtitle: "1 New")
        
    }
    
    func callToViewModelForUIUpdate(){
        self.notificationsViewModel =  NotificationsViewModel()
        self.notificationsViewModel.bindNotificationsViewModelToController = {
            self.updateDataSource()
        }
    }
    
    
    func updateDataSource(){
        self.dataSource = NotificationTableViewDataSource(cellIdentifier: "notificationCell", notifications: self.notificationsViewModel.notificationsData, configureCell: { (cell, nvm) in
            cell.titleLabel.text = nvm.title
            cell.imageView?.image = nvm.image
            cell.dateLabel.text = nvm.date
            cell.teamLabel.text = nvm.team
            cell.notificationBadge.isHidden = nvm.isRead
        })

        self.notificationsTableView.dataSource = self.dataSource
        self.notificationsTableView.reloadData()
        
    }
    
    func configureTableView() {
        notificationsTableView.rowHeight = 80
        notificationsTableView.allowsMultipleSelectionDuringEditing = true
        self.tableViewDelegate = TableViewDelegate(withDelegate: self)
        self.notificationsTableView.delegate = self.tableViewDelegate
        self.toolBar.isHidden = true
        self.markButton.isEnabled = false
        self.deleteButton.isEnabled = false
    }
    
    
    func configureEditButton() {
        self.navigationItem.rightBarButtonItem = editButtonItem
        self.navigationItem.rightBarButtonItem?.tintColor = .white
    }
    
    
    @IBAction func markBtnPressed(_ sender: UIBarButtonItem) {
        //  UIAlert Pops up
        self.present(notificationsViewModel.getAlertSheet(), animated: true, completion: nil)
        
    }
    
    @IBAction func selectAllBtnPressed(_ sender: UIBarButtonItem) {
        //  Selects/Diselect All The Rows In Our TableView.
        if sender.title == "Select All"{
            notificationsViewModel.selectAllRows(self.notificationsTableView)
            markButton.isEnabled = true
            deleteButton.isEnabled = true
            sender.title = "Deselect All"
        } else {
            notificationsViewModel.deselectAllRows(self.notificationsTableView)
            sender.title = "Select All"
            markButton.isEnabled = false
            deleteButton.isEnabled = false
        }
    }
    
    
    @IBAction func deleteBtnPressed(_ sender: UIBarButtonItem) {
        //  Deletes a row
        print("Delete Button Is Pressed")
        
    }
    
    override func setEditing(_ editing: Bool, animated: Bool) {
        super.setEditing(editing, animated: animated)
        self.notificationsTableView.setEditing(editing, animated: animated)
        if editing {
            //Section of when we are in Editing Mode:
            toolBar.isHidden = false
            self.navigationItem.rightBarButtonItem?.title = "Cancel"
            toolBar.toolBarAnimation(self.toolBar)
        } else {
            //Section of when we are NOT in Editing Mode:
            toolBar.toolBarDissapearAnimation(self.toolBar)
            self.navigationItem.rightBarButtonItem?.title = "Edit"
            toolBar.toolBarDissapearAnimation(self.toolBar)
        }
    }
    
    
    func selectedCell(row: Int) {
        if isEditing {
            notificationsViewModel.enableButtons(self.markButton, self.selectAllButton, self.deleteButton)
        }
    }
    
    
    func diselectedCell(row: Int) {
        if isEditing {
            notificationsViewModel.disableButtons(self.markButton, self.selectAllButton, self.deleteButton)
        }
    }
}

TableViewDataSource File:

import Foundation
import UIKit

class NotificationTableViewDataSource<CELL : UITableViewCell,T> : NSObject, UITableViewDataSource {
    
    private var cellIdentifier : String!
    private var notifications : [T]!
    var configureCell : (CELL, T) -> () = {_,_ in }
    
    
    init(cellIdentifier : String, notifications : [T], configureCell : @escaping (CELL, T) -> ()) {
        self.cellIdentifier = cellIdentifier
        self.notifications =  notifications
        self.configureCell = configureCell
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        notifications.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        
         let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as! CELL
        
        let item = self.notifications[indexPath.row]
        self.configureCell(cell, item)
        return cell
    }
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)
等待大神答复

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to MLink Developer Q&A Community for programmer and developer-Open, Learning and Share
...