Ios swift:collectionView单元格中的标签

Ios swift:collectionView单元格中的标签,ios,swift,uicollectionview,Ios,Swift,Uicollectionview,在我的collectionView中,我有7个部分和3个单元 单击单元格时下载文件的我的代码: enum DownloadStatus { case none case inProgress case completed case failed } struct item { var title : String! var downloadStatus : DownloadStatus = .none init(title: String

在我的collectionView中,我有7个部分和3个单元

单击单元格时下载文件的我的代码:

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))%"

                        }

                    }
}
我的下载管理器类:

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

}
但我有个问题。我的应用程序在此行崩溃-cell=self.collectionView?.cellForItem(at:indexPath)as!主视图单元


出现此问题:致命错误:在展开可选值时意外发现nil。如何修复它?

您面临的问题是由于单元重用。每次在集合或表格中滚动时,通常会取消旧单元格的显示。这意味着,无论何时显示新单元格
cellForRow
(表格)或
itemForRow
(集合),都必须有数据才能为单元格提供数据

如果只将有关下载过程的数据存储到计算单元中,则在调用
prepareforuse:
,system call时会丢失这些数据,因为计算单元被重置


另一种方法是使用静态单元格。因为静态单元格永远不会重置。但是,只有当你在屏幕上使用少量项目时,这才方便。如果您有数十个或数百个单元,那么性能将非常昂贵。

您必须保存进度值,而不是仅保存downloadTaskLocal。您应该为每次下载创建一个下载对象,并保存到阵列中。每个下载对象将负责下载一个任务。在下载对象中保留所有下载信息。例如进度等,以便在创建单元格时访问此数组以设置值。@vivekDas I更新问题。并在更新标题下添加新代码。如何修复它?永远不要在
cellForItemAt
之外调用
dequeueReusableCell
。它不能工作。与
cellForItemAt
不同,您无法将单元格返回框架。请使用like->as?@vadian抱歉。我不知道如何解决问题。你能告诉我更多的情况吗?也许你可以举个例子?