MVVM in Swift iOS The 2019 Stack Overflow Developer Survey Results Are In ...

Sort list of array linked objects by keys and values

What can I do if neighbor is blocking my solar panels intentionally?

Could an empire control the whole planet with today's comunication methods?

Are spiders unable to hurt humans, especially very small spiders?

Can each chord in a progression create its own key?

What would this chord progression be called?

One-dimensional Japanese puzzle

Are there continuous functions who are the same in an interval but differ in at least one other point?

What to do when moving next to a bird sanctuary with a loosely-domesticated cat?

Why did Peik Lin say, "I'm not an animal"?

How to politely respond to generic emails requesting a PhD/job in my lab? Without wasting too much time

What was the last x86 CPU that did not have the x87 floating-point unit built in?

Didn't get enough time to take a Coding Test - what to do now?

Button changing its text & action. Good or terrible?

Did the new image of black hole confirm the general theory of relativity?

How do spell lists change if the party levels up without taking a long rest?

What aspect of planet Earth must be changed to prevent the industrial revolution?

My body leaves; my core can stay

Can the Right Ascension and Argument of Perigee of a spacecraft's orbit keep varying by themselves with time?

Accepted by European university, rejected by all American ones I applied to? Possible reasons?

Homework question about an engine pulling a train

Am I ethically obligated to go into work on an off day if the reason is sudden?

Can withdrawing asylum be illegal?

University's motivation for having tenure-track positions



MVVM in Swift iOS



The 2019 Stack Overflow Developer Survey Results Are In
Announcing the arrival of Valued Associate #679: Cesar Manara
Planned maintenance scheduled April 17/18, 2019 at 00:00UTC (8:00pm US/Eastern)





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ margin-bottom:0;
}







0












$begingroup$


I've been implementing MVVM in Swift. I've looked at several implementations, many of which violate some aspects of MVVM and wanted to have a go with my own version that contains a Web request service.



View:



class BreachView: UIView {
var nameLabel = UILabel()
public override init(frame: CGRect) {
let labelframe = CGRect(x: 0, y: 50, width: frame.width, height: 20)
nameLabel.frame = labelframe
nameLabel.backgroundColor = .gray
super.init(frame: frame)
self.addSubview(nameLabel)
backgroundColor = .red
}

required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}


ViewController
class ViewController: UIViewController {



var breachesViewModel: BreachViewModelType!
var breachView : BreachView?

// to be called during testing
init(viewModel: BreachViewModelType) {
breachesViewModel = viewModel
super.init(nibName: nil, bundle: nil)
}

// required when called from storyboard
required init?(coder aDecoder: NSCoder) {
breachesViewModel = BreachViewModel()
super.init(coder: aDecoder)
}

override func viewDidLoad() {
super.viewDidLoad()
breachesViewModel.fetchData{ [weak self] breaches in
guard let self = self else {return}
DispatchQueue.main.async {
self.updateUI()
}
}
}

func updateUI() {
breachView = BreachView(frame: view.frame)
breachesViewModel.configure(breachView!, number: 3)
view.addSubview(breachView!)
}


}



Protocol for dependency injection:



protocol BreachViewModelType {
func fetchData(completion: @escaping ([BreachModel]) -> Void)
func configure (_ view: BreachView, number index: Int)
}


ViewModel
class BreachViewModel : BreachViewModelType {
var breaches = BreachModel



init() {
// add init for ClosureHTTPManager here, to allow it to be teestable in the future
}

func fetchData(completion: @escaping ([BreachModel]) -> Void) {
ClosureHTTPManager.shared.get(urlString: baseUrl + breachesExtensionURL, completionBlock: { [weak self] result in
guard let self = self else {return}
switch result {
case .failure(let error):
print ("failure", error)
case .success(let dta) :
let decoder = JSONDecoder()
do
{
self.breaches = try decoder.decode([BreachModel].self, from: dta)
completion(try decoder.decode([BreachModel].self, from: dta))
} catch {
// deal with error from JSON decoding!
}
}
})
}

func numberItemsToDisplay() -> Int {
return breaches.count
}

func configure (_ view: BreachView, number index: Int) {
// set the name and data in the view
view.nameLabel.text = breaches[index].name
}

}


and HTTP manager



    class ClosureHTTPManager {
static let shared: ClosureHTTPManager = ClosureHTTPManager()

enum HTTPError: Error

{
case invalidURL
case invalidResponse(Data?, URLResponse?)
}

public func get(urlString: String, completionBlock: @escaping (Result<Data, Error>) -> Void) {
guard let url = URL(string: urlString) else {
completionBlock(.failure(HTTPError.invalidURL))
return
}

let task = URLSession.shared.dataTask(with: url) { data, response, error in
guard error == nil else {
completionBlock(.failure(error!))
return
}

guard
let responseData = data,
let httpResponse = response as? HTTPURLResponse,
200 ..< 300 ~= httpResponse.statusCode else {
completionBlock(.failure(HTTPError.invalidResponse(data, response)))
return
}

completionBlock(.success(responseData))
}
task.resume()
}
}


Calling the API from



let baseUrl : String = "https://haveibeenpwned.com/api/v2"
let breachesExtensionURL : String = "/breaches"


Any comments on whether the implementation conforms to MVVM or not, typos, changes etc. are appreciated.



Git link: https://github.com/stevencurtis/MVVMWithNetworkService









share









$endgroup$



















    0












    $begingroup$


    I've been implementing MVVM in Swift. I've looked at several implementations, many of which violate some aspects of MVVM and wanted to have a go with my own version that contains a Web request service.



    View:



    class BreachView: UIView {
    var nameLabel = UILabel()
    public override init(frame: CGRect) {
    let labelframe = CGRect(x: 0, y: 50, width: frame.width, height: 20)
    nameLabel.frame = labelframe
    nameLabel.backgroundColor = .gray
    super.init(frame: frame)
    self.addSubview(nameLabel)
    backgroundColor = .red
    }

    required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
    }
    }


    ViewController
    class ViewController: UIViewController {



    var breachesViewModel: BreachViewModelType!
    var breachView : BreachView?

    // to be called during testing
    init(viewModel: BreachViewModelType) {
    breachesViewModel = viewModel
    super.init(nibName: nil, bundle: nil)
    }

    // required when called from storyboard
    required init?(coder aDecoder: NSCoder) {
    breachesViewModel = BreachViewModel()
    super.init(coder: aDecoder)
    }

    override func viewDidLoad() {
    super.viewDidLoad()
    breachesViewModel.fetchData{ [weak self] breaches in
    guard let self = self else {return}
    DispatchQueue.main.async {
    self.updateUI()
    }
    }
    }

    func updateUI() {
    breachView = BreachView(frame: view.frame)
    breachesViewModel.configure(breachView!, number: 3)
    view.addSubview(breachView!)
    }


    }



    Protocol for dependency injection:



    protocol BreachViewModelType {
    func fetchData(completion: @escaping ([BreachModel]) -> Void)
    func configure (_ view: BreachView, number index: Int)
    }


    ViewModel
    class BreachViewModel : BreachViewModelType {
    var breaches = BreachModel



    init() {
    // add init for ClosureHTTPManager here, to allow it to be teestable in the future
    }

    func fetchData(completion: @escaping ([BreachModel]) -> Void) {
    ClosureHTTPManager.shared.get(urlString: baseUrl + breachesExtensionURL, completionBlock: { [weak self] result in
    guard let self = self else {return}
    switch result {
    case .failure(let error):
    print ("failure", error)
    case .success(let dta) :
    let decoder = JSONDecoder()
    do
    {
    self.breaches = try decoder.decode([BreachModel].self, from: dta)
    completion(try decoder.decode([BreachModel].self, from: dta))
    } catch {
    // deal with error from JSON decoding!
    }
    }
    })
    }

    func numberItemsToDisplay() -> Int {
    return breaches.count
    }

    func configure (_ view: BreachView, number index: Int) {
    // set the name and data in the view
    view.nameLabel.text = breaches[index].name
    }

    }


    and HTTP manager



        class ClosureHTTPManager {
    static let shared: ClosureHTTPManager = ClosureHTTPManager()

    enum HTTPError: Error

    {
    case invalidURL
    case invalidResponse(Data?, URLResponse?)
    }

    public func get(urlString: String, completionBlock: @escaping (Result<Data, Error>) -> Void) {
    guard let url = URL(string: urlString) else {
    completionBlock(.failure(HTTPError.invalidURL))
    return
    }

    let task = URLSession.shared.dataTask(with: url) { data, response, error in
    guard error == nil else {
    completionBlock(.failure(error!))
    return
    }

    guard
    let responseData = data,
    let httpResponse = response as? HTTPURLResponse,
    200 ..< 300 ~= httpResponse.statusCode else {
    completionBlock(.failure(HTTPError.invalidResponse(data, response)))
    return
    }

    completionBlock(.success(responseData))
    }
    task.resume()
    }
    }


    Calling the API from



    let baseUrl : String = "https://haveibeenpwned.com/api/v2"
    let breachesExtensionURL : String = "/breaches"


    Any comments on whether the implementation conforms to MVVM or not, typos, changes etc. are appreciated.



    Git link: https://github.com/stevencurtis/MVVMWithNetworkService









    share









    $endgroup$















      0












      0








      0





      $begingroup$


      I've been implementing MVVM in Swift. I've looked at several implementations, many of which violate some aspects of MVVM and wanted to have a go with my own version that contains a Web request service.



      View:



      class BreachView: UIView {
      var nameLabel = UILabel()
      public override init(frame: CGRect) {
      let labelframe = CGRect(x: 0, y: 50, width: frame.width, height: 20)
      nameLabel.frame = labelframe
      nameLabel.backgroundColor = .gray
      super.init(frame: frame)
      self.addSubview(nameLabel)
      backgroundColor = .red
      }

      required init?(coder aDecoder: NSCoder) {
      fatalError("init(coder:) has not been implemented")
      }
      }


      ViewController
      class ViewController: UIViewController {



      var breachesViewModel: BreachViewModelType!
      var breachView : BreachView?

      // to be called during testing
      init(viewModel: BreachViewModelType) {
      breachesViewModel = viewModel
      super.init(nibName: nil, bundle: nil)
      }

      // required when called from storyboard
      required init?(coder aDecoder: NSCoder) {
      breachesViewModel = BreachViewModel()
      super.init(coder: aDecoder)
      }

      override func viewDidLoad() {
      super.viewDidLoad()
      breachesViewModel.fetchData{ [weak self] breaches in
      guard let self = self else {return}
      DispatchQueue.main.async {
      self.updateUI()
      }
      }
      }

      func updateUI() {
      breachView = BreachView(frame: view.frame)
      breachesViewModel.configure(breachView!, number: 3)
      view.addSubview(breachView!)
      }


      }



      Protocol for dependency injection:



      protocol BreachViewModelType {
      func fetchData(completion: @escaping ([BreachModel]) -> Void)
      func configure (_ view: BreachView, number index: Int)
      }


      ViewModel
      class BreachViewModel : BreachViewModelType {
      var breaches = BreachModel



      init() {
      // add init for ClosureHTTPManager here, to allow it to be teestable in the future
      }

      func fetchData(completion: @escaping ([BreachModel]) -> Void) {
      ClosureHTTPManager.shared.get(urlString: baseUrl + breachesExtensionURL, completionBlock: { [weak self] result in
      guard let self = self else {return}
      switch result {
      case .failure(let error):
      print ("failure", error)
      case .success(let dta) :
      let decoder = JSONDecoder()
      do
      {
      self.breaches = try decoder.decode([BreachModel].self, from: dta)
      completion(try decoder.decode([BreachModel].self, from: dta))
      } catch {
      // deal with error from JSON decoding!
      }
      }
      })
      }

      func numberItemsToDisplay() -> Int {
      return breaches.count
      }

      func configure (_ view: BreachView, number index: Int) {
      // set the name and data in the view
      view.nameLabel.text = breaches[index].name
      }

      }


      and HTTP manager



          class ClosureHTTPManager {
      static let shared: ClosureHTTPManager = ClosureHTTPManager()

      enum HTTPError: Error

      {
      case invalidURL
      case invalidResponse(Data?, URLResponse?)
      }

      public func get(urlString: String, completionBlock: @escaping (Result<Data, Error>) -> Void) {
      guard let url = URL(string: urlString) else {
      completionBlock(.failure(HTTPError.invalidURL))
      return
      }

      let task = URLSession.shared.dataTask(with: url) { data, response, error in
      guard error == nil else {
      completionBlock(.failure(error!))
      return
      }

      guard
      let responseData = data,
      let httpResponse = response as? HTTPURLResponse,
      200 ..< 300 ~= httpResponse.statusCode else {
      completionBlock(.failure(HTTPError.invalidResponse(data, response)))
      return
      }

      completionBlock(.success(responseData))
      }
      task.resume()
      }
      }


      Calling the API from



      let baseUrl : String = "https://haveibeenpwned.com/api/v2"
      let breachesExtensionURL : String = "/breaches"


      Any comments on whether the implementation conforms to MVVM or not, typos, changes etc. are appreciated.



      Git link: https://github.com/stevencurtis/MVVMWithNetworkService









      share









      $endgroup$




      I've been implementing MVVM in Swift. I've looked at several implementations, many of which violate some aspects of MVVM and wanted to have a go with my own version that contains a Web request service.



      View:



      class BreachView: UIView {
      var nameLabel = UILabel()
      public override init(frame: CGRect) {
      let labelframe = CGRect(x: 0, y: 50, width: frame.width, height: 20)
      nameLabel.frame = labelframe
      nameLabel.backgroundColor = .gray
      super.init(frame: frame)
      self.addSubview(nameLabel)
      backgroundColor = .red
      }

      required init?(coder aDecoder: NSCoder) {
      fatalError("init(coder:) has not been implemented")
      }
      }


      ViewController
      class ViewController: UIViewController {



      var breachesViewModel: BreachViewModelType!
      var breachView : BreachView?

      // to be called during testing
      init(viewModel: BreachViewModelType) {
      breachesViewModel = viewModel
      super.init(nibName: nil, bundle: nil)
      }

      // required when called from storyboard
      required init?(coder aDecoder: NSCoder) {
      breachesViewModel = BreachViewModel()
      super.init(coder: aDecoder)
      }

      override func viewDidLoad() {
      super.viewDidLoad()
      breachesViewModel.fetchData{ [weak self] breaches in
      guard let self = self else {return}
      DispatchQueue.main.async {
      self.updateUI()
      }
      }
      }

      func updateUI() {
      breachView = BreachView(frame: view.frame)
      breachesViewModel.configure(breachView!, number: 3)
      view.addSubview(breachView!)
      }


      }



      Protocol for dependency injection:



      protocol BreachViewModelType {
      func fetchData(completion: @escaping ([BreachModel]) -> Void)
      func configure (_ view: BreachView, number index: Int)
      }


      ViewModel
      class BreachViewModel : BreachViewModelType {
      var breaches = BreachModel



      init() {
      // add init for ClosureHTTPManager here, to allow it to be teestable in the future
      }

      func fetchData(completion: @escaping ([BreachModel]) -> Void) {
      ClosureHTTPManager.shared.get(urlString: baseUrl + breachesExtensionURL, completionBlock: { [weak self] result in
      guard let self = self else {return}
      switch result {
      case .failure(let error):
      print ("failure", error)
      case .success(let dta) :
      let decoder = JSONDecoder()
      do
      {
      self.breaches = try decoder.decode([BreachModel].self, from: dta)
      completion(try decoder.decode([BreachModel].self, from: dta))
      } catch {
      // deal with error from JSON decoding!
      }
      }
      })
      }

      func numberItemsToDisplay() -> Int {
      return breaches.count
      }

      func configure (_ view: BreachView, number index: Int) {
      // set the name and data in the view
      view.nameLabel.text = breaches[index].name
      }

      }


      and HTTP manager



          class ClosureHTTPManager {
      static let shared: ClosureHTTPManager = ClosureHTTPManager()

      enum HTTPError: Error

      {
      case invalidURL
      case invalidResponse(Data?, URLResponse?)
      }

      public func get(urlString: String, completionBlock: @escaping (Result<Data, Error>) -> Void) {
      guard let url = URL(string: urlString) else {
      completionBlock(.failure(HTTPError.invalidURL))
      return
      }

      let task = URLSession.shared.dataTask(with: url) { data, response, error in
      guard error == nil else {
      completionBlock(.failure(error!))
      return
      }

      guard
      let responseData = data,
      let httpResponse = response as? HTTPURLResponse,
      200 ..< 300 ~= httpResponse.statusCode else {
      completionBlock(.failure(HTTPError.invalidResponse(data, response)))
      return
      }

      completionBlock(.success(responseData))
      }
      task.resume()
      }
      }


      Calling the API from



      let baseUrl : String = "https://haveibeenpwned.com/api/v2"
      let breachesExtensionURL : String = "/breaches"


      Any comments on whether the implementation conforms to MVVM or not, typos, changes etc. are appreciated.



      Git link: https://github.com/stevencurtis/MVVMWithNetworkService







      swift





      share












      share










      share



      share










      asked 2 mins ago









      stevenpcurtisstevenpcurtis

      1227




      1227






















          0






          active

          oldest

          votes












          Your Answer






          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "196"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: false,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: null,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f217371%2fmvvm-in-swift-ios%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          0






          active

          oldest

          votes








          0






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes
















          draft saved

          draft discarded




















































          Thanks for contributing an answer to Code Review Stack Exchange!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          Use MathJax to format equations. MathJax reference.


          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f217371%2fmvvm-in-swift-ios%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          is 'sed' thread safeWhat should someone know about using Python scripts in the shell?Nexenta bash script uses...

          How do i solve the “ No module named 'mlxtend' ” issue on Jupyter?

          Pilgersdorf Inhaltsverzeichnis Geografie | Geschichte | Bevölkerungsentwicklung | Politik | Kultur...