由 LPLinkView 和 UIImageView 组成的单元格的 CollectionView 速度很慢,并且在滚动时重新加载数据
CollectionView with Cells made up of LPLinkView's and UIImageView's is Slow and Reloads Data While Scrolling
我有一个 UICollectionView
有两种类型的细胞;一些从 URL 加载图像,另一些从 URL 加载元数据并用 LPLinkView
.
显示它
下面是我通过 LPLinkView
显示数据的单元格代码:
import UIKit
import LinkPresentation
class LinkItemLinkPreviewCell: UICollectionViewCell {
static let identifier = "kLinkPreviewCollectionViewCell"
var linkView: LPLinkView?
var urlMetadata: LPLinkMetadata?
@IBOutlet var containerView: UIView? = UIView()
@IBOutlet var titleLabel: UILabel? = UILabel()
@IBOutlet var dateLabel: UILabel? = UILabel()
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.clipsToBounds = true
self.autoresizesSubviews = true
self.layer.cornerRadius = 20
}
override func prepareForReuse() {
super.prepareForReuse()
}
var linkItem: LinkPostDataObject? {
didSet {
titleLabel?.text = linkItem?.postTitle ?? ""
let df = DateFormatter()
df.dateFormat = "yyyy-MM-dd hh:mm"
dateLabel?.text = df.string(from: toDate((linkItem?.timeSent)!/1000)!)
let provider = LPMetadataProvider()
let url = URL(string: linkItem!.url)
if url != nil {
provider.startFetchingMetadata(for: URL(string: linkItem!.url)!) { (metadata, error) in
if let md = metadata {
DispatchQueue.main.async { [self] in
linkView = LPLinkView()
linkView?.metadata = md
linkView!.frame = containerView!.frame
containerView?.addSubview(linkView!)
linkView!.isUserInteractionEnabled = false
urlMetadata = metadata
}
}
}
}
}
}
}
下面是 UICollectionViewCell
的代码,显示来自 URL 的图像:
import UIKit
class LinkItemImageCell: UICollectionViewCell {
static let identifier = "kImageCollectionViewCell"
@IBOutlet var imageView: UIImageView? = UIImageView()
@IBOutlet var titleLabel: UILabel? = UILabel()
@IBOutlet var dateLabel: UILabel? = UILabel()
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.clipsToBounds = true
self.autoresizesSubviews = true
self.layer.cornerRadius = 20
}
override func prepareForReuse() {
super.prepareForReuse()
}
var linkItem: LinkPostDataObject? {
didSet {
titleLabel?.text = linkItem?.postTitle ?? ""
let df = DateFormatter()
df.dateFormat = "yyyy-MM-dd hh:mm"
dateLabel?.text = df.string(from: toDate((linkItem?.timeSent)!/1000)!)
if linkItem?.url.isImage() == true {
let url = URL(string: linkItem!.url)
url!.getImageData(from: url!) { (data, response, error) in
guard let data = data, error == nil else { return }
DispatchQueue.main.async() { [self] in
imageView?.image = UIImage(data: data)
}
}
}
}
}
}
下面是我的 ViewController:
的代码
import UIKit
class LinkCollectionViewController : UIViewController, UICollectionViewDelegate,UICollectionViewDataSource {
@IBOutlet weak var collectionView: UICollectionView!
@IBOutlet weak var collectionNameLabel: UILabel!
@IBOutlet weak var collectionSubTitleLabel: UILabel!
@IBOutlet weak var collectionCreatorLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
let backButton = UIBarButtonItem()
backButton.title = "Inbox"
self.navigationController?.navigationBar.topItem?.backBarButtonItem = backButton
collectionNameLabel.text = airlockStore.selectedChannel.channelName
collectionSubTitleLabel.text = airlockStore.selectedChannel.channelDescription
collectionCreatorLabel.text = airlockStore.selectedChannel.creator
collectionView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
collectionView.alwaysBounceVertical = true
collectionView.register(UINib(nibName: "LinkImageItemCell", bundle: nil), forCellWithReuseIdentifier: "kImageCollectionViewCell")
collectionView.register(UINib(nibName: "LinkItemLinkPreviewCell", bundle: nil), forCellWithReuseIdentifier: "kLinkPreviewCollectionViewCell")
collectionView.reloadItems(at: collectionView.indexPathsForVisibleItems)
collectionView.reloadData()
NotificationCenter.default.addObserver(self, selector: #selector(self.updateLinkCollection), name: Notification.Name("Link_Collection_Updated"), object: nil)
}
override func viewWillAppear(_ animated: Bool) {
self.navigationController?.setNavigationBarHidden(false, animated: animated)
}
@objc func updateLinkCollection() {
collectionView.reloadData()
collectionView.reloadItems(at: collectionView.indexPathsForVisibleItems)
}
// MARK: - UICollectionViewDataSource Delegate
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return airlockStore.selectedChannel.linkPosts.count
}
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return 1
}
// MARK: - UICollectionViewDelegate
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
//Image
if airlockStore.selectedChannel.linkPosts.reversed()[indexPath.item].url.isImage() == true {
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: LinkItemImageCell.identifier, for: indexPath) as? LinkItemImageCell
else { preconditionFailure("Failed to load collection view cell") }
cell.linkItem = airlockStore.selectedChannel.linkPosts.reversed()[indexPath.item]
return cell
}
//URL
else {
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: LinkItemLinkPreviewCell.identifier, for: indexPath) as? LinkItemLinkPreviewCell
else { preconditionFailure("Failed to load collection view cell") }
cell.linkItem = airlockStore.selectedChannel.linkPosts.reversed()[indexPath.item]
return cell
}
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
self.performSegue(withIdentifier: "GoToLinkBlockViewController", sender: self)
airlockStore.selectedLinkBlock = airlockStore.selectedChannel.linkPosts.reversed()[indexPath.item]
guard let cell: LinkItemLinkPreviewCell = collectionView.cellForItem(at: indexPath)! as? LinkItemLinkPreviewCell else {
return
}
airlockStore.selectedLinkBlock.urlMetadata = cell.urlMetadata
}
}
我注意到带有 LPLinkView
的单元格显示数据的速度非常慢,而且滚动 UICollectionView
时会发生很多刷新。
感谢任何关于我如何提高性能的想法或指导;真的只是试图在我滚动时不重新加载单元格的 images/URL。
我没有时间研究你的代码,所以我的回答很笼统:
当您的 table view/collection 视图显示必须通过网络获取的数据时,将该数据加载到您的数据模型中,而不是单元格中。当网络加载完成并且模型中的条目更新时,告诉相应的单元格重新加载。
如果您将数据加载到单元格中,滚动时,之前加载的数据将会丢失,如果向后滚动,则必须重新加载。理想情况下,将加载的数据保存到缓存目录中的文件中,这样如果用户关闭视图控制器然后重新打开它,它仍然可用。
如果您将下载的数据安装到您的模型中,那么当您滚动并向后滚动时,单元格将在显示后立即正确呈现。
我有一个 UICollectionView
有两种类型的细胞;一些从 URL 加载图像,另一些从 URL 加载元数据并用 LPLinkView
.
下面是我通过 LPLinkView
显示数据的单元格代码:
import UIKit
import LinkPresentation
class LinkItemLinkPreviewCell: UICollectionViewCell {
static let identifier = "kLinkPreviewCollectionViewCell"
var linkView: LPLinkView?
var urlMetadata: LPLinkMetadata?
@IBOutlet var containerView: UIView? = UIView()
@IBOutlet var titleLabel: UILabel? = UILabel()
@IBOutlet var dateLabel: UILabel? = UILabel()
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.clipsToBounds = true
self.autoresizesSubviews = true
self.layer.cornerRadius = 20
}
override func prepareForReuse() {
super.prepareForReuse()
}
var linkItem: LinkPostDataObject? {
didSet {
titleLabel?.text = linkItem?.postTitle ?? ""
let df = DateFormatter()
df.dateFormat = "yyyy-MM-dd hh:mm"
dateLabel?.text = df.string(from: toDate((linkItem?.timeSent)!/1000)!)
let provider = LPMetadataProvider()
let url = URL(string: linkItem!.url)
if url != nil {
provider.startFetchingMetadata(for: URL(string: linkItem!.url)!) { (metadata, error) in
if let md = metadata {
DispatchQueue.main.async { [self] in
linkView = LPLinkView()
linkView?.metadata = md
linkView!.frame = containerView!.frame
containerView?.addSubview(linkView!)
linkView!.isUserInteractionEnabled = false
urlMetadata = metadata
}
}
}
}
}
}
}
下面是 UICollectionViewCell
的代码,显示来自 URL 的图像:
import UIKit
class LinkItemImageCell: UICollectionViewCell {
static let identifier = "kImageCollectionViewCell"
@IBOutlet var imageView: UIImageView? = UIImageView()
@IBOutlet var titleLabel: UILabel? = UILabel()
@IBOutlet var dateLabel: UILabel? = UILabel()
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.clipsToBounds = true
self.autoresizesSubviews = true
self.layer.cornerRadius = 20
}
override func prepareForReuse() {
super.prepareForReuse()
}
var linkItem: LinkPostDataObject? {
didSet {
titleLabel?.text = linkItem?.postTitle ?? ""
let df = DateFormatter()
df.dateFormat = "yyyy-MM-dd hh:mm"
dateLabel?.text = df.string(from: toDate((linkItem?.timeSent)!/1000)!)
if linkItem?.url.isImage() == true {
let url = URL(string: linkItem!.url)
url!.getImageData(from: url!) { (data, response, error) in
guard let data = data, error == nil else { return }
DispatchQueue.main.async() { [self] in
imageView?.image = UIImage(data: data)
}
}
}
}
}
}
下面是我的 ViewController:
的代码import UIKit
class LinkCollectionViewController : UIViewController, UICollectionViewDelegate,UICollectionViewDataSource {
@IBOutlet weak var collectionView: UICollectionView!
@IBOutlet weak var collectionNameLabel: UILabel!
@IBOutlet weak var collectionSubTitleLabel: UILabel!
@IBOutlet weak var collectionCreatorLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
let backButton = UIBarButtonItem()
backButton.title = "Inbox"
self.navigationController?.navigationBar.topItem?.backBarButtonItem = backButton
collectionNameLabel.text = airlockStore.selectedChannel.channelName
collectionSubTitleLabel.text = airlockStore.selectedChannel.channelDescription
collectionCreatorLabel.text = airlockStore.selectedChannel.creator
collectionView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
collectionView.alwaysBounceVertical = true
collectionView.register(UINib(nibName: "LinkImageItemCell", bundle: nil), forCellWithReuseIdentifier: "kImageCollectionViewCell")
collectionView.register(UINib(nibName: "LinkItemLinkPreviewCell", bundle: nil), forCellWithReuseIdentifier: "kLinkPreviewCollectionViewCell")
collectionView.reloadItems(at: collectionView.indexPathsForVisibleItems)
collectionView.reloadData()
NotificationCenter.default.addObserver(self, selector: #selector(self.updateLinkCollection), name: Notification.Name("Link_Collection_Updated"), object: nil)
}
override func viewWillAppear(_ animated: Bool) {
self.navigationController?.setNavigationBarHidden(false, animated: animated)
}
@objc func updateLinkCollection() {
collectionView.reloadData()
collectionView.reloadItems(at: collectionView.indexPathsForVisibleItems)
}
// MARK: - UICollectionViewDataSource Delegate
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return airlockStore.selectedChannel.linkPosts.count
}
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return 1
}
// MARK: - UICollectionViewDelegate
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
//Image
if airlockStore.selectedChannel.linkPosts.reversed()[indexPath.item].url.isImage() == true {
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: LinkItemImageCell.identifier, for: indexPath) as? LinkItemImageCell
else { preconditionFailure("Failed to load collection view cell") }
cell.linkItem = airlockStore.selectedChannel.linkPosts.reversed()[indexPath.item]
return cell
}
//URL
else {
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: LinkItemLinkPreviewCell.identifier, for: indexPath) as? LinkItemLinkPreviewCell
else { preconditionFailure("Failed to load collection view cell") }
cell.linkItem = airlockStore.selectedChannel.linkPosts.reversed()[indexPath.item]
return cell
}
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
self.performSegue(withIdentifier: "GoToLinkBlockViewController", sender: self)
airlockStore.selectedLinkBlock = airlockStore.selectedChannel.linkPosts.reversed()[indexPath.item]
guard let cell: LinkItemLinkPreviewCell = collectionView.cellForItem(at: indexPath)! as? LinkItemLinkPreviewCell else {
return
}
airlockStore.selectedLinkBlock.urlMetadata = cell.urlMetadata
}
}
我注意到带有 LPLinkView
的单元格显示数据的速度非常慢,而且滚动 UICollectionView
时会发生很多刷新。
感谢任何关于我如何提高性能的想法或指导;真的只是试图在我滚动时不重新加载单元格的 images/URL。
我没有时间研究你的代码,所以我的回答很笼统:
当您的 table view/collection 视图显示必须通过网络获取的数据时,将该数据加载到您的数据模型中,而不是单元格中。当网络加载完成并且模型中的条目更新时,告诉相应的单元格重新加载。
如果您将数据加载到单元格中,滚动时,之前加载的数据将会丢失,如果向后滚动,则必须重新加载。理想情况下,将加载的数据保存到缓存目录中的文件中,这样如果用户关闭视图控制器然后重新打开它,它仍然可用。
如果您将下载的数据安装到您的模型中,那么当您滚动并向后滚动时,单元格将在显示后立即正确呈现。