I've been working on a Swift project that involves a seedbox app for my NAS, and I would appreciate some feedback on the code structure and especially on the placement of my observer. I've implemented a DownloadListViewModel
and a corresponding DownloadViewController
to display the list. The DownloadListViewModel
fetches data from an API periodically, and the DownloadViewController
updates its UI accordingly.
I'm specifically concerned about whether I've placed the observer in the right location within the code. Should it stay in the DownloadListViewModel
as it is now, or would it be more appropriate to move it into the DownloadViewController
? Your insights and suggestions on the overall code quality and best practices would be highly valuable.
Here's a snippet of the relevant code:
class DownloadListViewModel: ObservableObject {
@Published var downloadList: [Data] = []
let qnapApi = ApiClientQnap.shared
var timer: Timer?
init() {
timer = Timer.scheduledTimer(withTimeInterval: 3, repeats: true, block: { _ in
print("update!")
self.fetchDownloads()
})
}
deinit {
timer?.invalidate()
}
func fetchDownloads() {
// Appel de l'api qui va remplir notre tableau
qnapApi.performQuery { queryList in
if let queryList = queryList {
// Hop on récupère la liste
self.downloadList = queryList.data ?? []
} else {
print("Erreur lors de la récupération de la liste de téléchargement.")
}
}
} }
struct DownloadViewControllerRepresentable: UIViewControllerRepresentable {
@State var data: [Data] = []
var onSelected: ((Data) -> Void)?
@StateObject var viewModel = DownloadListViewModel()
func makeUIViewController(context: Context) -> DownloadViewController {
let tableViewController = DownloadViewController()
tableViewController.onSelected = { selectedData in
self.onSelected?(selectedData)
}
return tableViewController
}
func updateUIViewController(_ uiViewController: DownloadViewController, context: Context) {
uiViewController.updateData(viewModel.downloadList)
}
func updateData(_ newData: [Data]) {
self.data = newData
} }
class DownloadViewController: UITableViewController {
var data: [Data] = []
var onSelected: ((Data) -> Void)?
private var dataSource: UITableViewDiffableDataSource<Int, Data>!
override func viewDidLoad() {
super.viewDidLoad()
let nib = UINib(nibName: "DownloadViewCell", bundle: nil)
tableView.register(nib, forCellReuseIdentifier: "DownloadViewCell")
dataSource = UITableViewDiffableDataSource<Int, Data>(tableView: tableView) { tableView, indexPath, dataItem in
let cell = tableView.dequeueReusableCell(withIdentifier: "DownloadViewCell", for: indexPath) as! DownloadViewCell
cell.myLabel.text = dataItem.source_name
cell.updateProgressView((dataItem.progress!) / 100)
return cell
}
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return data.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "DownloadViewCell", for: indexPath) as! DownloadViewCell
cell.myLabel.text = data[indexPath.row].source_name
cell.updateProgressView(Float(data[indexPath.row].progress!) / 100)
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let selectedData = data[indexPath.row]
onSelected?(selectedData)
tableView.deselectRow(at: indexPath, animated: true)
}
func updateData(_ newData: [Data]) {
DispatchQueue.main.async {
self.data = newData
var snapshot = NSDiffableDataSourceSnapshot<Int, Data>()
snapshot.appendSections([0])
snapshot.appendItems(newData)
self.dataSource.apply(snapshot, animatingDifferences: true)
}
} }