Передача данных из 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 шт):
Вы не привели в вопросе модель данных, предположим она такая, хотя конечно 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
}
