ViewController class ViewController: UIViewController {
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!)
}
}
}
ViewModel class BreachViewModel : BreachViewModelType { var breaches = BreachModel
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
}
}
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()
}
}