iosswiftmodel-view-controllerdesign-patternscocoa-design-patterns

How to implement simple MVC design pattern in Swift?


I am new to MVC design pattern. I created "DataModel" it will make an API call, create data, and return data to the ViewController using Delegation and "DataModelItem" that will hold all data. How to call a DataModel init function in "requestData" function. Here is my code:

protocol DataModelDelegate:class {
    func didRecieveDataUpdata(data:[DataModelItem])
    func didFailUpdateWithError(error:Error)
}

class DataModel: NSObject {
    weak var delegate : DataModelDelegate?
    func requestData() {

    }
    private func setDataWithResponse(response:[AnyObject]){
        var data = [DataModelItem]()
        for item in response{
            if let tableViewModel = DataModelItem(data: item as? [String : String]){
                data.append(tableViewModel)
            }
        }
        delegate?.didRecieveDataUpdata(data: data)
    }
}

And for DataModelItem:

class DataModelItem{
    var name:String?
    var id:String?

    init?(data:[String:String]?) {
        if let data = data, let serviceName = data["name"] , let serviceId = data["id"] {
            self.name = serviceName
            self.id = serviceId
        }
        else{
            return nil
        }
    }
}

Controller:

class ViewController: UIViewController {
    private let dataSource = DataModel()
    override func viewDidLoad() {
        super.viewDidLoad()
        dataSource.delegate = self
    }

    override func viewWillAppear(_ animated: Bool) {
        dataSource.requestData()
    }

}
extension ViewController : DataModelDelegate{
    func didRecieveDataUpdata(data: [DataModelItem]) {
        print(data)
    }

    func didFailUpdateWithError(error: Error) {
        print("error:  \(error.localizedDescription)")
    }


}

Solution

  • I am just sharing my answer here and I am using a codable. It will be useful for anyone:

    Model:

    import Foundation
    
    struct DataModelItem: Codable{
        struct Result : Codable {
            let icon : String?
            let name : String?
            let rating : Float?
            let userRatingsTotal : Int?
            let vicinity : String?
    
            enum CodingKeys: String, CodingKey {
                case icon = "icon"
                case name = "name"
                case rating = "rating"
                case userRatingsTotal = "user_ratings_total"
                case vicinity = "vicinity"
            }
        }
        let results : [Result]?
    }
    

    NetWork Layer :

    import UIKit
    
    protocol DataModelDelegate:class {
        func didRecieveDataUpdata(data:[String])
        func didFailUpdateWithError(error:Error)
    }
    
    class DataModel: NSObject {
        weak var delegate : DataModelDelegate?
        var theatreNameArray = [String]()
        var theatreVicinityArray = [String]()
        var theatreiconArray = [String]()
        func requestData() {
            Service.sharedInstance.getClassList { (response, error) in
                if error != nil {
                    self.delegate?.didFailUpdateWithError(error: error!)
                } else if let response = response{
                    self.setDataWithResponse(response: response as [DataModelItem])
                }
            }
        }
    
        private func setDataWithResponse(response:[DataModelItem]){
            for i in response[0].results!{
                self.theatreNameArray.append(i.name!)
                self.theatreVicinityArray.append(i.vicinity!)
                self.theatreiconArray.append(i.icon!)
    
            }
            delegate?.didRecieveDataUpdata(data: theatreNameArray)
            print("TheatreName------------------------->\(self.theatreNameArray)")
            print("TheatreVicinity------------------------->\(self.theatreVicinityArray)")
            print("Theatreicon------------------------->\(self.theatreiconArray)")
    
        }
    }
    

    Controller :

    class ViewController: UIViewController {
        private let dataSource = DataModel()
        override func viewDidLoad() {
            super.viewDidLoad()
            dataSource.delegate = self
        }
    
        override func viewWillAppear(_ animated: Bool) {
            dataSource.requestData()
        }
    
    }
    extension ViewController : DataModelDelegate{
        func didRecieveDataUpdata(data: [DataModelItem]) {
            print(data)
        }
    
        func didFailUpdateWithError(error: Error) {
            print("error:  \(error.localizedDescription)")
        }
    
    
    }
    

    APIManager :

    class Service : NSObject{
        static let sharedInstance = Service()    
        func getClassList(completion: (([DataModelItem]?, NSError?) -> Void)?) {
            guard let gitUrl = URL(string: "") else { return }
            URLSession.shared.dataTask(with: gitUrl) { (data, response
                , error) in
                guard let data = data else { return }
                do {
                    let decoder = JSONDecoder()
                    let gitData = try decoder.decode(DataModelItem.self, from: data)
                    completion!([gitData],nil)
    
                } catch let err {
                    print("Err", err)
                    completion!(nil,err as NSError)
                }
                }.resume()
        }
    }