简体   繁体   English

swift:collectionView单元格中的标签

[英]swift: Label in collectionView cell

I have 7 sections and 3 cels in section in my collectionView. 我的collectionView中有7个部分和3个cels。

My code to download file when cell was clicked: 单击单元格时下载文件的代码:

enum DownloadStatus {
    case none
    case inProgress
    case completed
    case failed
}
struct item {
    var title : String!
    var downloadStatus : DownloadStatus = .none

    init(title: String) {
        self.title = title
    }
}

var downloadQ = [Int: [Int]]()

typealias ProgressHandler = (Int, Float) -> ()
var items = [[item]]()
var tableId = 0
var onProgress : ProgressHandler?

override func viewDidLoad() {
        super.viewDidLoad()

items = [
        [item(title: "item 2"),item(title: "item 2"),item(title: "item 2")],
        [item(title: "item 2"),item(title: "item 2"),item(title: "item 2")],
        [item(title: "item 2"),item(title: "item 2"),item(title: "item 2")],
        [item(title: "item 2"),item(title: "item 2"),item(title: "item 2")],
        [item(title: "item 2"),item(title: "item 2"),item(title: "item 2")],
        [item(title: "item 2"),item(title: "item 2"),item(title: "item 2")],
        [item(title: "item 2"),item(title: "item 2"),item(title: "item 2")]
    ]
}

func numberOfSections(in collectionView: UICollectionView) -> Int {
        return media.count
    }

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return media[section].count
    }

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {

var item = self.items[indexPath.section][indexPath.row]
                    downloadQ[indexPath.section]?.append(indexPath.row)

                    var theArray = downloadQ[indexPath.section] ?? [Int]()
                    theArray.append(indexPath.row)
                    downloadQ[indexPath.section] = theArray

                    // Create the actions

                    let url = URL(string: "link")!

                    let downloadManager = DownloadManager()
                    downloadManager.identifier = indexPath.row
                    downloadManager.tableId = indexPath.section
                    downloadManager.folderPath = "folder"
                    let downloadTaskLocal =  downloadManager.activate().downloadTask(with: url)
                    downloadTaskLocal.resume()

                    var cell = self.collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! MasterViewCell
                    cell = self.collectionView?.cellForItem(at: indexPath) as! MasterViewCell
                    cell.label?.isHidden = false

                    downloadManager.onProgress = { (row, tableId, progress) in

                        DispatchQueue.main.async {
                            let appDelegate = UIApplication.shared.delegate as! AppDelegate

                            if appDelegate.masterVC == nil {
                                return
                            }

                            if appDelegate.masterVC.tableId != tableId {
                                return
                            }

                            let indexpath = IndexPath.init(row: row, section: indexPath.section)
                            var cell = self.collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! MasterViewCell
                            cell = appDelegate.masterVC.collectionView.cellForItem(at: indexpath) as! MasterViewCell

                            cell.label?.text = "\(CGFloat(progress))%"

                        }

                    }
}

My Download manager class: 我的下载管理员课程:

import Foundation
import UIKit

extension URLSession {
    func getSessionDescription () -> Int {
        // row id
        return Int(self.sessionDescription!)!
    }

    func getDebugDescription () -> Int {
        // table id
        return Int(self.debugDescription)!
    }
}

class DownloadManager : NSObject, URLSessionDelegate, URLSessionDownloadDelegate {



    static var shared = DownloadManager()
    var identifier : Int = -1
    var tableId : Int = -1
    var folderPath : String = ""
    typealias ProgressHandler = (Int, Int, Float) -> ()


    var onProgress : ProgressHandler? {
        didSet {
            if onProgress != nil {
                let _ = activate()
            }
        }
    }

    override init() {
        super.init()
    }

    func activate() -> URLSession {
        let config = URLSessionConfiguration.background(withIdentifier: "\(Bundle.main.bundleIdentifier!).background.\(NSUUID.init())")

        let urlSession = URLSession(configuration: config, delegate: self, delegateQueue: OperationQueue())
        urlSession.sessionDescription = String(identifier)
        urlSession.accessibilityHint = String(tableId)

        return urlSession
    }

    private func calculateProgress(session : URLSession, completionHandler : @escaping (Int, Int, Float) -> ()) {
        session.getTasksWithCompletionHandler { (tasks, uploads, downloads) in
            let progress = downloads.map({ (task) -> Float in
                if task.countOfBytesExpectedToReceive > 0 {
                    return Float(task.countOfBytesReceived) / Float(task.countOfBytesExpectedToReceive)
                } else {
                    return 0.0
                }
            })

            //print("tbale id \(session.accessibilityHint ?? "hit")")

            let stringNumb = (session.accessibilityHint ?? "hit")
            let someNumb = Int(stringNumb as String) // 1357 as integer

            let string1 = (session.sessionDescription ?? "hit")
            let some1 = Int(string1 as String) // 1357 as integer

            if let idx = downloadQ[someNumb!]?.index(of: some1!) {
                downloadQ[someNumb!]?.remove(at: idx)
                //print("remove:\(downloadQ)")
            }

            completionHandler(session.getSessionDescription(), Int(session.accessibilityHint!)!, progress.reduce(0.0, +))
        }
    }

    func urlSession(_ session: URLSession,
                    downloadTask: URLSessionDownloadTask,
                    didFinishDownloadingTo location: URL){

        let stringNumb = (session.accessibilityHint ?? "hit")
        let someNumb = Int(stringNumb as String) // 1357 as integer

        let string1 = (session.sessionDescription ?? "hit")
        let some1 = Int(string1 as String) // 1357 as integer

        if let idx = downloadQ[someNumb!]?.index(of: some1!) {
            downloadQ[someNumb!]?.remove(at: idx)
            //print("remove:\(downloadQ)")
        }

        let fileName = downloadTask.originalRequest?.url?.lastPathComponent
        let path = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true)
        let documentDirectoryPath:String = path[0]
        let fileManager = FileManager()
        var destinationURLForFile = URL(fileURLWithPath: documentDirectoryPath.appending("/\(folderPath)"))


        do {
            try fileManager.createDirectory(at: destinationURLForFile, withIntermediateDirectories: true, attributes: nil)
            destinationURLForFile.appendPathComponent(String(describing: fileName!))
            try fileManager.moveItem(at: location, to: destinationURLForFile)
        }catch(let error){
            print(error)
        }



    }

    func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {

        let stringNumb = (session.accessibilityHint ?? "hit")
        let someNumb = Int(stringNumb as String) // 1357 as integer

        let string1 = (session.sessionDescription ?? "hit")
        let some1 = Int(string1 as String) // 1357 as integer

        if let idx = downloadQ[someNumb!]?.index(of: some1!) {
            downloadQ[someNumb!]?.remove(at: idx)
            //print("remove:\(downloadQ)")
        }

        if totalBytesExpectedToWrite > 0 {
            if let onProgress = onProgress {
                calculateProgress(session: session, completionHandler: onProgress)
            }
            let progress = Float(totalBytesWritten) / Float(totalBytesExpectedToWrite)
            //debugPrint("Progress \(downloadTask) \(progress)")

        }
    }

    func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {

        let stringNumb = (session.accessibilityHint ?? "hit")
        let someNumb = Int(stringNumb as String) // 1357 as integer

        let string1 = (session.sessionDescription ?? "hit")
        let some1 = Int(string1 as String) // 1357 as integer

        if let idx = downloadQ[someNumb!]?.index(of: some1!) {
            downloadQ[someNumb!]?.remove(at: idx)
            //print("remove:\(downloadQ)")
        }

        //debugPrint("Task completed: \(task), error: \(String(describing: error))")
    }

}

But I have a problem. 但我有一个问题。 My app crashes in this line - cell = self.collectionView?.cellForItem(at: indexPath) as! 我的应用程序崩溃在这一行 - cell = self.collectionView?.cellForItem(at:indexPath)as! MasterViewCell MasterViewCell

with this issue: Fatal error: Unexpectedly found nil while unwrapping an Optional value. 出现此问题:致命错误:在展开Optional值时意外发现nil。 How to fix it? 怎么解决?

The problem you are facing is due to cell reuse. 您面临的问题是由于细胞重用。 Each time you scroll in your collection or table, you usually deque the old cell. 每次在集合或表格中滚动时,通常会对旧单元格进行双击。 Which means whenever you are displaying new cell cellForRow (table), or itemForRow (collection), you'll have to have data for the cell to be able to feed it. 这意味着无论何时显示新单元格cellForRow (表格)或itemForRow (集合),您都必须拥有能够为其提供数据的单元格。

If you only store the data about your download process into the cell you'll lose them at the moment when prepareForReuse: , system call, gets called, because the cell gets reset. 如果您只将有关下载过程的数据存储到单元格中,那么当prepareForReuse:系统调用被调用时,您将丢失它们,因为单元格会被重置。

The other way around would be to use static cells. 另一种方法是使用静态单元格。 Because the static cells, never gets reset. 因为静态单元格永远不会被重置。 But that's handy only when you use a small number of items on the screen. 但是,只有当您在屏幕上使用少量项目时,这才有用。 If you have tens or hundreds of cells, then it gets very costly on performance. 如果你有数十或数百个单元,那么它的性能成本非常高。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM