Skip to main content
4 of 4
edited tags
Toby Speight
  • 81.7k
  • 14
  • 101
  • 308

Show a list of downloads

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)
        }
    } }