1

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)")
    }


}

3 Answers 3

4

How to implement simple MVC design pattern in Swift?

As a generic answer, in iOS development you're already doing this implicitly! Dealing with storyboard(s) implies the view layer and controlling the logic of how they work and how they are connected to the model is done by creating view controller, that's the default flow.

For your case, let's clarify a point which is: according to the standard MVC, by default the responsible layer for calling an api should be -logically- the view controller. However for the purpose of modularity, reusability and avoiding to create massive view controllers we can follow the approach that you are imitate, that doesn't mean that its the model responsibility, we can consider it a secondary helper layer (MVC-N for instance), which means (based on your code) is DataModel is not a model, its a "networking" layer and DataModelItem is the actual model.


How to call a DataModel init function in "requestData" function

It seems to me that it doesn't make scene. What do you need instead is an instance from DataModel therefore you could call the desired method.

In the view controller:

let object = DataModel()
object.delegate = self // if you want to handle it in the view controller itself
object.requestData()
Sign up to request clarification or add additional context in comments.

3 Comments

Please read MVC wiki and discussion
Thanks for your answer Ahamad. But my request is i have to call a DataModel init function in networking model "requestData" function.
@Bill I understand your point. However, please check: developer.apple.com/library/archive/documentation/General/…, you can clearly read that "A model class shouldn't depend on anything other than other model classes".
2

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()
    }
}

1 Comment

Shall we achieve MVC Pattern without delegate as you mention? what is the advantage for delegate in this code? this is my confusion. Thank you.
-1

I would recommend using a singleton instance for DataModel, since this would be a class you would be invoking from many points in your application. You may refer its documentation at : Managing Shared resources using singleton With this you wont need to initialise this class instance every time you need to access data.

7 Comments

Do you think that there is a question we might ask: Why singletons or why not? :)
Sure. Singleton object reference is an approach to implement single source data availability in MVC. A data model in MVC is the source to drive content in application, keeping it singleton gives all View controllers to consume data from any invocation point. Not making Data or its controller as singleton will introduce redundancy of calls, initialisers, memory leaks in this case. Every developer is free to choose though. It's my recommendation as I find it practical for data. Please let me know if you have more questions regarding the approach.
I understand the appeal of a singletons, but it’s generally frowned upon for data models.
I agree on data model, but above example data model class is interacting with network + saving data & behaving as a network layer as well, so was the approach to use singleton came in.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.