#StackBounty: #swift #ios Networking structure for Swift iOS app

Bounty: 50

I would like any constructive comments regarding the structure of this simple App that takes an API response and then displays on a table view.

The URL is written in a ConstantsAPI file

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

Displayed on a tableviewcontroller

class SitewideTableViewController: UITableViewController, DataManagerDelegate {
    var pwnedData = [BreachModel]()
    var session: URLSession!
    var task: URLSessionDownloadTask!

    override func viewDidLoad() {
        super.viewDidLoad()
        session = URLSession.shared
        task = URLSessionDownloadTask()
        DataManager.shared.delegate = self
        DataManager.shared.fetchBreaches()
    }

    func didDownloadBreaches() {
        DispatchQueue.main.async {
            self.pwnedData = DataManager.shared.sortedBreaches()
            self.tableView.reloadData()
        }
    }

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

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "Sitewide", for: indexPath)
        cell.textLabel?.text = pwnedData[indexPath.row].name
        return cell
    }
}

Using the following model

import Foundation

class BreachModel : Codable {
    let name : String
    let title : String
    let domain : String
    let breachDate : String
    let addedDate : String
    let modifiedData : String
    let pwnCount : Int
    let description: String

    private enum CodingKeys: String, CodingKey {
        case name = "Name"
        case title = "Title"
        case domain = "Domain"
        case breachDate = "BreachDate"
        case addedDate = "AddedDate"
        case modifiedData = "ModifiedDate"
        case pwnCount = "PwnCount"
        case description = "Description"
    }
}

With a Data manager that would manage all of the data

@objc protocol DataManagerDelegate: class {
    // optional delegate to practice
    @objc optional func didDownloadBreaches() // called when the manager has completed downloading all the breaches
}


    class DataManager {
        static let shared: DataManager = DataManager()
        public weak var delegate: DataManagerDelegate? = nil

        private var breaches = [BreachModel]()
        func fetchBreaches() {

            HTTPManager.shared.get(urlString: baseUrl + breachesExtensionURL, completionBlock:  { [weak self] (data: Data?) -> Void in
                let decoder = JSONDecoder()
                if let data = data{
                    print(data.count)
                    do {
                        self?.breaches = try decoder.decode([BreachModel].self, from: data)
                        self?.delegate?.didDownloadBreaches?()
                    } catch let error {
                        print ("Error in reading data", error)
                    }
                }
                }
            )
        }

        func sortedBreaches() -> [BreachModel] {
            return breaches.sorted{ a,b in a.name < b.name }
        }
    }

That calls a HTTP manager whose only responsibility is to call url’s

class HTTPManager {
    static let shared: HTTPManager = HTTPManager()
    public func get (urlString: String, completionBlock: ((Data?) -> Void)?) {
        let url = URL(string: urlString)
        if let usableUrl = url {
            let request = URLRequest(url: usableUrl)
            let task = URLSession.shared.dataTask(with: request, completionHandler: { (data, response, error) in
                completionBlock?(data)
            })
            task.resume()
        }
    }
}

So is this a reasonable extendable structure?
Should I have used dataTask or URLSessionDownloadTask?
Have I unwittingly introduced some memory leaks?

Any comments appreciated, I’m familiar with the Swift book but find other tutorials tend to just show the use of codable or an API and do not talk through the whole structure (at least not at an appropriate level for me). The code above does work, and I’m thinking of building upon it in the future but want to follow some form of best practice (no matter how trivial).

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


Get this bounty!!!

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.