Передача данных из Api в массив для отображения на экране

Суть такая есть менеджер для парса данных

    import Foundation


protocol NetworkDataManagerDelegate: AnyObject {
    func updateInterface( _: NetworkDataManager, with currenData: CurrentData)
}

class NetworkDataManager {
    weak var delegate: NetworkDataManagerDelegate?
    func fetchCurrentData() {
        let urlString = "https://run.mocky.io/v3/1d1cb4ec-73db-4762-8c4b-0b8aa3cecd4c"
        guard let url = URL(string: urlString) else {return}
        let urlSession = URLSession(configuration: .default)
        let task = urlSession.dataTask(with: url) { data, responce, error in
            if let data = data {
                if let currentData = self.parseJSON(withData: data){
                    self.delegate?.updateInterface(self, with: currentData)
                }
            }
        }
        
        task.resume()
    }
    
    func parseJSON(withData data: Data) -> CurrentData?{
        
        let decoder = JSONDecoder()
        do {
            let currentDataData = try decoder.decode(CurrentDataData.self, from: data)
            guard let currentData = CurrentData(currentDataData: currentDataData) else {return nil}
            return currentData
        } catch let error as NSError {
            print(error)
        }
        return nil
    }
    
}

На tableViewController предаю через протокол в котором есть класс updateInterface() вопрос такой как передать данные в массив cell что бы подтягивалось нужно кол-во ячеек? У ячеек есть отдельный viewController на который они собственно и подключены.

view для ячеек

    import UIKit

class CustomCell: UITableViewCell {

    @IBOutlet weak var skilsLable: UILabel!
    @IBOutlet weak var numbeLable: UILabel!
    @IBOutlet weak var nameLable: UILabel!
    
    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
    }

}

Вот и сам tableViewController

    class MyTableViewController: UITableViewController {

    var cell: [String] = []
    let network = NetworkDataManager()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        network.fetchCurrentData()
        network.delegate = self

        tableView.rowHeight = 150
        self.title = "Team of Developer"
    }

    // MARK: - Table view data source

    override func numberOfSections(in tableView: UITableView) -> Int {
        // #warning Incomplete implementation, return the number of sections
        return 1
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        // #warning Incomplete implementation, return the number of rows
        return cell.count
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! CustomCell
        return cell
    }
}


extension MyTableViewController: NetworkDataManagerDelegate{
    func updateInterface(_: NetworkDataManager, with currenData: CurrentData) {
        
    }
    
    
}

введите сюда описание изображения


Ответы (1 шт):

Автор решения: schmidt9

Вы не привели в вопросе модель данных, предположим она такая, хотя конечно CurrentDataData лучше бы переименовать или вообще обойтись без него, использовав сразу CurrentData

class CurrentData {
    var currentDataData: CurrentDataData?
    
    init?(currentDataData: CurrentDataData?) {
        self.currentDataData = currentDataData
    }
}

struct Employee : Decodable {
    var name: String
    var phone_number: String
    var skills: [String]
}

struct Company : Decodable {
    var name: String
    var employees: [Employee]
}

struct CurrentDataData : Decodable {
    var company: Company
}

Также я подкорректировал вызов делегата, который лучше сделать сразу в основном потоке

    func fetchCurrentData() {
        let urlString = "https://run.mocky.io/v3/1d1cb4ec-73db-4762-8c4b-0b8aa3cecd4c"
        guard let url = URL(string: urlString) else {return}
        let urlSession = URLSession(configuration: .default)
        let task = urlSession.dataTask(with: url) { data, responce, error in
            if let data = data {
                if let currentData = self.parseJSON(withData: data){
                    DispatchQueue.main.async {
                        self.delegate?.updateInterface(self, with: currentData)
                    }
                }
            }
        }
        
        task.resume()
    }

Ну и соответствующие правки в контроллере

class MyTableViewController: UITableViewController {

    var data: CurrentDataData?
    let network = NetworkDataManager()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        tableView.register(UINib(nibName: "CustomCell", bundle: nil), forCellReuseIdentifier: "Cell")
        tableView.rowHeight = 150
        
        network.delegate = self
        network.fetchCurrentData()

        self.title = "Team of Developer"
    }

    // MARK: - Table view data source

    override func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return data?.company.employees.count ?? 0
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! CustomCell
        
        guard let employees = data?.company.employees else {
            return cell
        }
        
        let employee = employees[indexPath.row]
        
        cell.nameLable.text = employee.name
        cell.numbeLable.text = employee.phone_number
        cell.skilsLable.text = employee.skills.joined(separator: ",")
        
        return cell
    }
}

extension MyTableViewController: NetworkDataManagerDelegate{
    func updateInterface(_: NetworkDataManager, with currenData: CurrentData) {
        data = currenData.currentDataData
        tableView.reloadData()
    }
}

При этом и тут можно предложить ряд улучшений:

  • вместо делегирования использовать замыкание, что упростит код
    func fetchCurrentData(_ completion: @escaping (CurrentData) -> Void) {
        let urlString = "https://run.mocky.io/v3/1d1cb4ec-73db-4762-8c4b-0b8aa3cecd4c"
        guard let url = URL(string: urlString) else {return}
        let urlSession = URLSession(configuration: .default)
        let task = urlSession.dataTask(with: url) { data, responce, error in
            if let data = data {
                if let currentData = self.parseJSON(withData: data){
                    DispatchQueue.main.async {
                        completion(currentData)
                    }
                }
            }
        }
        
        task.resume()
    }
    network.fetchCurrentData {
        self.data = $0.currentDataData
        self.tableView.reloadData()
    }
  • вместо прямого доступа к аутлетам в ячейке увеличить инкапсуляцию и передавать туда данные, а сами аутлеты сделать приватными
class CustomCell: UITableViewCell {
    
    @IBOutlet private weak var skilsLable: UILabel!
    @IBOutlet private weak var numbeLable: UILabel!
    @IBOutlet private weak var nameLable: UILabel!
    
    var employee: Employee? {
        didSet {
            skilsLable.text = employee?.name
            numbeLable.text = employee?.phone_number
            nameLable.text = employee?.skills.joined(separator: ",")
        }
    }

}
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! CustomCell
        
        guard let employees = data?.company.employees else {
            return cell
        }
        
        cell.employee = employees[indexPath.row]
        
        return cell
    }
→ Ссылка