Skip to main content
edited tags
Link
Toby Speight
  • 81.7k
  • 14
  • 101
  • 308
Simplify title to focus on purpose rather than mechanism
Source Link
Toby Speight
  • 81.7k
  • 14
  • 101
  • 308

Guidance on Swift Code Structure with Combine for Download List Implementation Show a list of downloads

I've been working on a Swift project that involves a seedbox app for my nasNAS, and I would appreciate some feedback on the code structure and especially on the placement of my observer. I've implemented a DownloadListViewModelDownloadListViewModel and a corresponding DownloadViewControllerDownloadViewController to display the list. The DownloadListViewModelDownloadListViewModel fetches data from an API periodically, and the DownloadViewControllerDownloadViewController 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 DownloadListViewModelDownloadListViewModel as it is now, or would it be more appropriate to move it into the DownloadViewControllerDownloadViewController? Your insights and suggestions on the overall code quality and best practices would be highly valuable.

Guidance on Swift Code Structure with Combine for Download List Implementation

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.

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.

Format code as a code block instead of as a blockquote to get the proper rendering.
Source Link
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)
    }
} }
    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)
        }
    } }
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)
    }
} }
    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)
        }
    } }
Source Link
Loading