在Swift

时间:2018-08-26 15:06:15

标签: ios swift mvvm

我正在尝试在我的应用中使用MVVM。我发现MVVM以不同的格式实现。因此,我应该使用哪种方法令人困惑。对于获取用户并在tableView中显示列表的情况,我有两种不同的实现。

模型定义为:

struct User: Decodable {
    var id: String?
    var name: String?
    var email: String?
}

对于网络抓取,我有以下课程。

class ServiceManager {

    static let sharedInstance = ServiceManager()

    func fetchUsers(completion: @escaping ([User]?, Error?) -> ()) {

        Alamofire.request(
            URL(string: UrlManager.getUsers)!,
            method: .get,
            encoding: JSONEncoding.default
            ).responseJSON { (response) -> Void in

                guard let responseCode = response.response?.statusCode else {
                    return
                }

                print(responseCode)

                switch responseCode {

                case 200:
                    do {
                        let users = try JSONDecoder().decode([User].self, from: response.data!)
                        completion(users, nil)
                    } catch let jsonErr {
                        print("ERR=", jsonErr.localizedDescription, "-->", jsonErr)
                        completion(nil, jsonErr)
                    }

                default:
                    completion(nil, "error" as? Error)

                }
            }
        }
    }

方法1 如下。

class ViewController: UIViewController {

    var userviewmodels = [UserViewModel]()

    private var selectedIndex: Int!

    @IBOutlet weak var tableView: UITableView!


    override func viewDidLoad() {
        super.viewDidLoad()

        tableView.delegate = self
        tableView.dataSource = self

        fetchUserData()
    }

    func fetchUserData() {
        ServiceManager.sharedInstance.fetchUsers { (users, err) in
            if let error = err {
                print("Failed to fetch: \(error)")
                return
            }
            self.userviewmodels = users?.map({return UserViewModel(user: $0)}) ?? []

            self.tableView.reloadData()
        }
    }

}

extension ViewController: UITableViewDataSource, UITableViewDelegate {

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return userviewmodels.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! UserTableViewCell

        let userViewModel = userviewmodels[indexPath.row]

        cell.userViewModel = userViewModel

        return cell
    }

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        selectedIndex = indexPath.row
        performSegue(withIdentifier: "showUserInfo", sender: nil)
    }

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "showUserInfo" {
            let userInfoViewController = segue.destination as! UserInfoViewController
            userInfoViewController.userviewmodel = self.userviewmodels[selectedIndex]
        }
    }
}

视图模型如下:

class UserViewModel {

    var name: String!
    var email: String!

    init(user: User) {
        self.name = user.name
        self.email = user.email
    }

}

tableview单元格:

class UserTableViewCell: UITableViewCell {

    @IBOutlet weak var labelName: UILabel!

    @IBOutlet weak var labelEmail: UILabel!

    var userViewModel: UserViewModel! {
        didSet {
            labelName.text = userViewModel.name
            labelEmail.text = userViewModel.email
        }
    }
}

接下来,下面给出 APPROACH 2

class ViewController: UIViewController {

    @IBOutlet weak var tableView: UITableView!

    private var userviewmodel = UserViewModel()

    private var selectedIndex: Int!

    override func viewDidLoad() {
        super.viewDidLoad()

        tableView.delegate = self
        tableView.dataSource = self

        userviewmodel.delegate = self
        userviewmodel.fetchUsers()
    }

}

extension ViewController: UITableViewDataSource, UITableViewDelegate {

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return userviewmodel.numberOfUsers()
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! UserTableViewCell

        cell.labelName.text = userviewmodel.getUserName(at: indexPath.row)
        cell.labelEmail.text = userviewmodel.getUserEmail(at: indexPath.row)

        return cell
    }

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        selectedIndex = indexPath.row
        performSegue(withIdentifier: "showUserInfo", sender: nil)
    }

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "showUserInfo" {
            let userInfoViewController = segue.destination as! UserInfoViewController
            userInfoViewController.userviewmodel = userviewmodel
            userInfoViewController.index = selectedIndex
        }
    }
}

extension ViewController: UserViewModelDelegate {
    func usersFetched () {
        tableView.reloadData()
    }
}

对应的视图模型为:

protocol UserViewModelDelegate: class {
    func usersFetched()
}

class UserViewModel {

    weak var delegate: UserViewModelDelegate?

    private var users = [User]() {
        didSet {
            delegate?.usersFetched()
        }
    }
} 

extension UserViewModel {

    func fetchUsers() {

        ServiceManager.sharedInstance.fetchUsers { (users, err) in
            if let error = err {
                print("Failed to fetch: \(error)")
                return
            }

            self.users = users!
        }
    }
}

extension UserViewModel {

    func numberOfUsers() -> Int {
        return users.count
    }

    func getUserName(at index: Int) -> String {
        return users[index].name!
    }

    func getUserEmail(at index: Int) -> String {
        return users[index].email!
    }
}

据我了解,ViewModel应该将要呈现的数据通知给ViewController。那么这是否意味着网络调用应该放在ViewModel中(如方法2)?

并且,假设我需要在不同的ViewController中修改用户信息(上述示例中触发的选择)。在那种情况下,将ViewModel对象传递给另一个ViewController是否有效,尤其是对于方法2?

我已经读过MVVM,最好使用RxSwift和RxCocoa,但我仍在学习中。那么我现在应该使用哪种方法:方法1,方法2或其他?

0 个答案:

没有答案