【问题标题】:numberOfRowsInSection called but cellForRowAt not callednumberOfRowsInSection 已调用但 cellForRowAt 未调用
【发布时间】:2021-05-27 13:31:02
【问题描述】:

在我的应用程序中,我调用了一个 API 来获取一些数据并从中下载文件。下载后回调调用。在这种情况下,表格视图更新得很好。但是假设用户访问了屏幕并且在将内容下载回前一个屏幕并再次访问同一屏幕之前。在这种情况下,表视图未更新。仅当用户在未完成下载内容的情况下返回上一个控制器并再次出现在同一屏幕上时,我才会遇到此问题。

WarrantyVC.Swift

class WarrantyVC: UIViewController {
    
    // MARK: - Outlets
    ///
    @IBOutlet weak var warrantyTableView: UITableView!
    
    //Latum
    ///
    @IBOutlet weak var knowMoreButton: UIButton!
    
    // MARK: - Variables
    ///
    var warrantyDataSource: WarrantyDataSource!
    ///
    var viewModel: WarrantyViewModel?
   
    // MARK: - Controller life cycle
    ///
    override func viewDidLoad() {
        super.viewDidLoad()
        setupUI()
       getUserGuide()
    }
    

    ///
    deinit {
        viewModel = nil
    }
    
    // MARK: - Initializing UI methods
    ///
    func setupUI() {
        viewModel = WarrantyViewModel()
        warrantyDataSource = WarrantyDataSource(withTableView: warrantyTableView)
        warrantyDataSource.delegate = self
    }
    
    // MARK: - API methods
    ///
    func getUserGuide() {
        CommonMethods.showProgressHud(inView: self.view)
        warrantyDataSource.introVideoAndGuideArray.removeAll()
        viewModel?.getUserGuidefunc(userId: "\(DataManager.shared.user?.userId ?? 0)", motorId: selectedMotor?.MotorTypeId ?? 0,dmpModelId:selectedMotor?.dmpModelId ?? 0) { [self] (success, response) in
            CommonMethods.hideProgressHud()
            Console.log(response ?? [String: Any]())
            self.setupUI()
            if !success { /Show some message./ }
            let userGuides = UserGuideService.introVideoAndGuideArray
            if userGuides.count > 0 {
                var newUserGuideArray = [UserGuide]()
                for tempUserGuide in userGuides {
                    let userGuide = tempUserGuide
                    let userManual = userGuide.usermanual
                    let videolink = userGuide.videolink
                    if videolink.trim().count > 0 {
                        if let tempUserGuide = userGuide.copy() as? UserGuide {
                            tempUserGuide.usermanual = ""
                            tempUserGuide.videolink = videolink
                            newUserGuideArray.append(tempUserGuide)
                        }
                    }
                    if userManual.trim().count > 0 {
                        if let tempUserGuide = userGuide.copy() as? UserGuide {
                            tempUserGuide.usermanual = userManual
                            tempUserGuide.videolink = ""
                            newUserGuideArray.append(tempUserGuide)
                        }
                    }
                }
                 self.warrantyDataSource.introVideoAndGuideArray = newUserGuideArray
                DispatchQueue.main.async {
                    self.warrantyTableView.reloadData()
                }
            }
        }
    }

WarrantyDatasource.swift

protocol UserGuideDataSourceDelegate: class {
    ///
    func onOpenPDF()
    ///
    func onPlayVideo(_ videoURL: String)
}

/// This DataSource class use to show data of UserGuide in table.
class WarrantyDataSource: NSObject {
    
    // MARK: - Variables
    ///
    fileprivate let cellNibName = "warrantyCell"
    ///
    var userGuideTitle: [String] = ["Intro to ABC", “XYZ”]
    ///
    var userGuideImage: [UIImage] = [ imageLiteral(resourceName: "ic_play"),  imageLiteral(resourceName: "ic_pdf")]
    ///
    fileprivate let cellSpacingHeight: CGFloat = 12
    ///
    var introVideoAndGuideArray = [UserGuide]()
    ///
    weak var delegate: UserGuideDataSourceDelegate?
    ///
    var numberOfSections: Int = 0
    ///
    convenience init(withTableView tableView: UITableView) {
        self.init()
        tableView.delegate = self
        tableView.dataSource = self
    }
    
    ///
    @objc func onOpenPDF(_ sender: UIButton) {
        guard introVideoAndGuideArray.count > 0 else { return }
        delegate?.onOpenPDF()
    }
    
    ///
    @objc func onPlayVideo(_ sender: UIButton) {
        delegate?.onPlayVideo(introVideoAndGuideArray[sender.tag].videolink)
    }
    
    /// This function help to setup user menual cell
    ///
    /// - Parameters:
    ///   - cell: UserGuideCell
    ///   - indexPath: IndexPath
    func setUserGuidePDFCell(_ cell: WarrantyCell, _ indexPath: IndexPath) {
        cell.guideImageView.image =  imageLiteral(resourceName: "ic_default_pdf")
        guard introVideoAndGuideArray.count > 0 else { return }
        cell.guideLabel.text = introVideoAndGuideArray[indexPath.section].userGuideTitle
        cell.guideButton.setImage(userGuideImage[1], for: .normal)
        cell.guideButton.tag = indexPath.section
        cell.guideButton.addTarget(self, action: #selector(onOpenPDF(_:)), for: .touchUpInside)
    }
}

// MARK: - Extension Implementing UITableView DataSource Callbacks
///
extension WarrantyDataSource: UITableViewDataSource {
    // MARK: Extension Implementing UITableView DataSource methods
    ///
    func numberOfSections(in tableView: UITableView) -> Int {
        numberOfSections = introVideoAndGuideArray.count
        return introVideoAndGuideArray.count
    }
    ///
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 1
    }
    
    /// Set the spacing between sections
    func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
        return cellSpacingHeight
    }
    
    /// Make the background color show through
    func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
        let headerView = UIView()
        headerView.backgroundColor = UIColor.clear
        return headerView
    }
    
    ///
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        guard let cell = tableView.dequeueReusableCell(withIdentifier: cellNibName, for: indexPath) as? WarrantyCell else { return WarrantyCell() }
        if NetworkManager.sharedInstance.isReachable {
            let userGuide = introVideoAndGuideArray[indexPath.section]
            if userGuide.videolink.trim().count > 0 {
                cell.guideButton.setImage(userGuideImage[0], for: .normal)
                cell.guideButton.tag = indexPath.section
                cell.guideButton.addTarget(self, action: #selector(onPlayVideo(_:)), for: .touchUpInside)
                cell.guideLabel.text = introVideoAndGuideArray[indexPath.section].videoTitle
                let videoThumbnail = introVideoAndGuideArray[indexPath.section].vehicleVideoThumbnailLink
                cell.guideImageView.kf.setImage(with: URL.init(string: videoThumbnail), placeholder: nil, options: nil, progressBlock: nil, completionHandler: nil)
            } else {
                setUserGuidePDFCell(cell, indexPath)
            }
        } else {
            setUserGuidePDFCell(cell, indexPath)
        }
        return cell
    }
}

【问题讨论】:

  • 好吧,如果你弹出了一个 viewController,你应该取消正在运行的任务并在推送时再次调用 API,但是如果你正在持久化 API 结果,那么你可以在本地获取记录并在第二次推送时显示,如果是这样的话在需求范围内。
  • “数据没有重新开始下载”,它应该开始并且它不依赖于你之前的任务。您的代码中可能还有其他问题。

标签: ios swift


【解决方案1】:

当您第一次调用 getUserGuide API 并且在获取回调之前或在下载数据之前,您会弹出视图控制器并在同一控制器上再次推送。第二次 getUserGuide API 将调用,您将从第一次调用 API 请求中获得回调。因此产生了这个问题。

您可以通过如下更改实现来解决此问题;

当第一次调用 API 并且在下载完成之前用户尝试弹出视图控制器暂停下载时,将响应中的 resumeData 存储在 userdefault 中。当用户第二次尝试调用 API 时,检查您已经启动下载的相同链接。如果然后通过从用户默认值中提取恢复数据来恢复相同链接的下载。

我希望这种方式对你有用。快乐编码。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多