gpt4 book ai didi

ios - 这是使用 heightForRowAt 的正确方法吗?

转载 作者:行者123 更新时间:2023-11-28 06:05:53 24 4
gpt4 key购买 nike

我正在尝试根据下载图像的大小实现动态大小的行高。我遇到的问题是当函数 heightForRowAt 运行时图像没有被下载。实现此代码的正确方法是什么。 images是UIImage的数组,rowHeights是CGFloat类型的数组,imageURLS是imageURLS的字符串数组。

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Reuse", for: indexPath) as! TableViewCell

// Configure the cell...

///////////////////////
if(cell.cellImageView.image == nil){
let downloadURL = URL(string: self.imageURLS[indexPath.row])

URLSession.shared.dataTask(with: downloadURL!) { (data, _, _) in
if let data = data {
let image = UIImage(data: data)
DispatchQueue.main.async {
cell.cellImageView.image = image
cell.cellImageView.contentMode = .scaleAspectFit
self.images.insert(image!, at: 0)
let aspectRatio = Float((cell.cellImageView?.image?.size.width)!/(cell.cellImageView?.image?.size.height)!)
print("aspectRatio: \(aspectRatio)")
tableView.rowHeight = CGFloat(Float(UIScreen.main.bounds.width)/aspectRatio)
print("tableView.rowHeight: \(tableView.rowHeight)")
self.rowHeights.insert(CGFloat(Float(UIScreen.main.bounds.width)/aspectRatio), at: 0)
tableView.reloadRows(at: [indexPath], with: .top)
}
}
}.resume()
}


///////////////////////
return cell
}

//What is the proper way to implement this function
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
print("Im in height for row")
return CGFloat(0.0)
}

最佳答案

如果您的异步请求可能会改变单元格的高度,您不应该直接更新单元格,而应该完全重新加载单元格。

因此,heightForRowAtcellForRowAt 将在检索图像之前为每个可见单元格调用一次。由于尚未检索到图像,heightForRowAt 将不得不返回一些适用于没有图像的单元格的固定值。 cellForRowAt 应该检测到图像尚未被检索并启动该过程。但是当图像检索完成后,cellForRowAt 应该调用 reloadRows(at:with:) 而不是直接更新单元格。 .这将为该行再次启动该过程,包括再次触发 heightForRowAt 调用。但这一次,图像应该在那里,所以 heightForRowAt 现在可以返回适当的高度,cellForRowAt 现在可以只更新 ImageView 而无需进一步的网络请求。

例如:

class ViewController: UITableViewController {

private var objects: [CustomObject]!

override func viewDidLoad() {
super.viewDidLoad()

objects = [
CustomObject(imageURL: URL(string: "https://upload.wikimedia.org/wikipedia/commons/e/e8/Second_Life_Landscape_01.jpg")!),
CustomObject(imageURL: URL(string: "https://upload.wikimedia.org/wikipedia/commons/7/78/Brorfelde_landscape_2.jpg")!)
]
}

let imageCache = ImageCache()

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! CustomCell
let imageURL = objects[indexPath.row].imageURL
if let image = imageCache[imageURL] {
// if we got here, we found image in our cache, so we can just
// update image view and we're done

cell.customImageView.image = image
} else {
// if we got here, we have not yet downloaded the image, so let's
// request the image and then reload the cell

cell.customImageView.image = nil // make sure to reset the image view

URLSession.shared.dataTask(with: imageURL) { data, _, error in
guard let data = data, error == nil else {
print(error ?? "Unknown error")
return
}
if let image = UIImage(data: data) {
self.imageCache[imageURL] = image
DispatchQueue.main.async {
// NB: This assumes that rows cannot be inserted while this asynchronous
// request is underway. If that is not a valid assumption, you will need to
// go back to your model and determine what `IndexPath` now represents
// this row in the table.

tableView.reloadRows(at: [indexPath], with: .middle)
}
}
}.resume()
}
return cell
}

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return objects.count
}

override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
let imageURL = objects[indexPath.row].imageURL
if let image = imageCache[imageURL] {
let size = image.size
return view.bounds.size.width * size.height / size.width
} else {
return 0
}
}
}

其中一个简单的图像缓存(与您的问题无关,但为了完整起见我包括在内)如下:

class ImageCache {
private let cache = NSCache<NSURL, UIImage>()

private var observer: NSObjectProtocol!

init () {
observer = NotificationCenter.default.addObserver(forName: .UIApplicationDidReceiveMemoryWarning, object: nil, queue: nil) { [weak self] _ in
self?.cache.removeAllObjects()
}
}

deinit {
NotificationCenter.default.removeObserver(observer)
}

subscript(key: URL) -> UIImage? {
get {
return cache.object(forKey: key as NSURL)
}
set (newValue) {
if let image = newValue {
cache.setObject(image, forKey: key as NSURL)
} else {
cache.removeObject(forKey: key as NSURL)
}
}
}
}

关于ios - 这是使用 heightForRowAt 的正确方法吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48252362/

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