gpt4 book ai didi

ios - UICollectionView reloadData 只工作两次

转载 作者:行者123 更新时间:2023-12-04 13:08:43 27 4
gpt4 key购买 nike

我有一个 UIViewController呈现 UIDocumentPicker选择 PDF 文件,并包含 UICollectionView显示它们(每个单元格包含一个 PDFView 来这样做)。
这是代码:

import MobileCoreServices; import PDFKit; import UIKit

class ViewController: UIViewController {
var urls: [URL] = []
@IBOutlet weak var collectionView: UICollectionView!

@IBAction func pickFile() {
DispatchQueue.main.async {
let documentPicker = UIDocumentPickerViewController(documentTypes: [kUTTypePDF as String], in: .import)
documentPicker.delegate = self
documentPicker.modalPresentationStyle = .formSheet
self.present(documentPicker, animated: true, completion: nil)
}
}

override func viewDidLoad() {
collectionView.register(UINib(nibName: PDFCollectionViewCell.identifier, bundle: .main),
forCellWithReuseIdentifier: PDFCollectionViewCell.identifier)
}

init() { super.init(nibName: "ViewController", bundle: .main) }
required init?(coder: NSCoder) { fatalError() }
}

extension ViewController: UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: PDFCollectionViewCell.identifier, for: indexPath) as! PDFCollectionViewCell
cell.pdfView.document = PDFDocument(url: urls[indexPath.row])
return cell
}

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

func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAt indexPath: IndexPath) -> CGSize {
CGSize(width: 150, height: 150)
}
}

extension ViewController: UIDocumentPickerDelegate {
// MARK: PDF Picker Delegate
func documentPickerWasCancelled(_ controller: UIDocumentPickerViewController) {
controller.dismiss(animated: true, completion: nil)

}

func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
controller.dismiss(animated: true, completion: {
DispatchQueue.main.async {
self.urls.append(contentsOf: urls)
self.collectionView.reloadData()
}
})
}
}

class PDFCollectionViewCell: UICollectionViewCell {
static let identifier = "PDFCollectionViewCell"

@IBOutlet weak var pdfView: PDFView! { didSet { setPdfViewUI() } }

func setPdfViewUI() {
pdfView.displayMode = .singlePage
pdfView.autoScales = true
pdfView.displayDirection = .vertical
pdfView.isUserInteractionEnabled = false
}
}
现在,出于某种原因, collectionView.reloadData()实际上只工作两次。它第一次工作,然后第二次没有任何 react ,然后第三次使用三个预期元素再次更新集合 View ......
我意识到即使我调用 reloadData() ,发生这种情况时,不会调用 dataSource 和委托(delegate)方法 ( numberOfItems/ cellForItem )。
知道发生了什么吗?
感谢您的帮助!
编辑:我可以确保在 viewDidLoad 中没有任何其他代码/ appear方法,即 pickFile函数实际上被调用得很好,并且 url 被正确获取,使用 urls在调用 reloadData() 之前按原样更新数组.
另外,我在 UITableView 上都试过了。和 UICollectionView ,而且我在每种情况下都遇到了这个问题。我正在使用 PDFView 的事实感觉有点问题。 ,或使用文档选择器。

最佳答案

这是一个非常非常奇怪的错误,当您使用 PDFView 时会发生这种错误。在 UICollectionViewCell .我在以下环境中确认了这一点 -

  • Xcode 12.5
  • iPhone SE 2020 (iOS 14.6)
  • UICollectionView.reloadData()电话是 工作不可靠 PDFView添加为 UICollectionViewCell.contentView 内的 subview .
    我们还能尝试什么?
    出人意料的 UICollectionView.insertItems(at:)工作地点 UICollectionView.reloadData()不适用于这种情况。在此答案的末尾提供了工作代码示例,供其他任何试图重现/确认问题的人使用。
    为什么会发生这种情况?
    老实说不知道。 UICollectionView.reloadData()应该保证 UI 与您的数据源同步。让我们看看 reloadData() 的堆栈跟踪(当它在这种情况下工作时)& insertItems(at:) .
    ReloadData_StackTrace
    enter image description here
    InsertItemsAtIndexPaths_StackTrace
    enter image description here
    结论
  • reloadData()依赖 layoutSubviews()执行 UI 刷新。这是从 UIView 继承的喜欢 - UIView.layoutSubviews() > UIScrollView > UICollectionView .这是一个非常有名的 UI 事件,很容易被 UIView 的任何子类拦截。 . PDFView: UIView也可以这样做。 为什么会出现不一致的情况? 只有可以拆卸和检查 PDFKit.framework 的人可能知道这件事。这显然是 PDFView.layoutSubviews() 中的一个错误干扰它的 super View 的实现 layoutSubviews()执行。
  • insertItems(at:)在指定的 indexPath(s) 添加单元格的新实例,显然不依赖于 layoutSubviews()因此在这种情况下可以可靠地工作。

  • 示例代码
    import MobileCoreServices
    import PDFKit
    import UIKit

    class ViewController: UIViewController {

    // MARK: - Instance Variables
    private lazy var flowLayout: UICollectionViewFlowLayout = {
    let sectionInset = UIEdgeInsets(top: 20, left: 20, bottom: 20, right: 20)

    let layout = UICollectionViewFlowLayout()
    layout.scrollDirection = .vertical
    layout.sectionInset = sectionInset
    layout.itemSize = CGSize(width: 150, height: 150)
    layout.minimumInteritemSpacing = 20
    layout.minimumLineSpacing = 20

    return layout
    }()

    private lazy var pdfsCollectionView: UICollectionView = {
    let cv = UICollectionView(frame: self.view.bounds, collectionViewLayout: flowLayout)
    cv.autoresizingMask = [.flexibleWidth, .flexibleHeight]
    cv.backgroundColor = .red

    cv.dataSource = self
    cv.delegate = self
    return cv
    }()

    private lazy var pickFileButton: UIButton = {
    let button = UIButton(frame: CGRect(x: 300, y: 610, width: 60, height: 40)) // hard-coded for iPhone SE
    button.setTitle("Pick", for: .normal)
    button.setTitleColor(.white, for: .normal)
    button.backgroundColor = .purple

    button.addTarget(self, action: #selector(pickFile), for: .touchUpInside)
    return button
    }()

    private var urls: [URL] = []


    // MARK: - View Life Cycle
    override func viewDidLoad() {
    super.viewDidLoad()

    self.view.addSubview(pdfsCollectionView)
    pdfsCollectionView.register(
    PDFCollectionViewCell.self,
    forCellWithReuseIdentifier: PDFCollectionViewCell.cellIdentifier
    )

    self.view.addSubview(pickFileButton)
    }


    // MARK: - Helpers
    @objc private func pickFile() {
    let documentPicker = UIDocumentPickerViewController(documentTypes: [kUTTypePDF as String], in: .import)
    documentPicker.delegate = self
    documentPicker.modalPresentationStyle = .formSheet
    self.present(documentPicker, animated: true, completion: nil)
    }

    }

    extension ViewController: UICollectionViewDataSource, UICollectionViewDelegate {
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: PDFCollectionViewCell.cellIdentifier, for: indexPath) as! PDFCollectionViewCell
    cell.pdfView.document = PDFDocument(url: urls[indexPath.row])
    cell.contentView.backgroundColor = .yellow
    return cell
    }

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

    extension ViewController: UIDocumentPickerDelegate {
    func documentPickerWasCancelled(_ controller: UIDocumentPickerViewController) {
    controller.dismiss(animated: true, completion: nil)
    }

    func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {

    // CAUTION:
    // These urls are in the temporary directory - `.../tmp/<CFBundleIdentifier>-Inbox/<File_Name>.pdf`
    // You should move/copy these files to your app's document directory

    controller.dismiss(animated: true, completion: {
    DispatchQueue.main.async {
    let count = self.urls.count
    var indexPaths: [IndexPath] = []
    for i in 0..<urls.count {
    indexPaths.append(IndexPath(item: count+i, section: 0))
    }

    self.urls.append(contentsOf: urls)

    // Does not work reliably
    /*
    self.pdfsCollectionView.reloadData()
    */

    // Works reliably
    self.pdfsCollectionView.insertItems(at: indexPaths)
    }
    })
    }
    }


    class PDFCollectionViewCell: UICollectionViewCell {
    static let cellIdentifier = "PDFCollectionViewCell"

    lazy var pdfView: PDFView = {
    let view = PDFView(frame: self.contentView.bounds)
    view.displayMode = .singlePage
    view.autoScales = true
    view.displayDirection = .vertical
    view.isUserInteractionEnabled = false

    self.contentView.addSubview(view)
    view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
    view.backgroundColor = .yellow

    return view
    }()
    }

    关于ios - UICollectionView reloadData 只工作两次,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67988863/

    27 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com