为啥调用 reloadRows 后,heightForRowAt 没有在数组中找到值?

Posted

技术标签:

【中文标题】为啥调用 reloadRows 后,heightForRowAt 没有在数组中找到值?【英文标题】:Why doesntnt heightForRowAt find a value in the array after reloadRows is called?为什么调用 reloadRows 后,heightForRowAt 没有在数组中找到值? 【发布时间】:2018-01-15 18:11:30 【问题描述】:

为什么函数heightForRowAt 总是找到包含行高的数组,该数组最初设置为 nil,即使在重新加载行后仍然为零。

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

    let downloadURL = URL(string: self.imageURLS[indexPath.row])


    if cell.cellImageView.image == nil
        URLSession.shared.dataTask(with: downloadURL!)  (data, _, _) in
            if let data = data 
                let image = UIImage(data: data)
                DispatchQueue.main.async 
                    cell.setCellImage(image:image!)
                    self.rowHeights?.insert((cell.imageView?.frame.height)!, at: indexPath.row)
                    tableView.reloadRows(at: [indexPath], with: .top)
                
            
            .resume()
    
    return cell


override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat 
    guard let rowHeights = self.rowHeights else
        print("returned nil")
        return 500.0
    
    print("the array exists at \(indexPath.row) with value: \(rowHeights[indexPath.row])")
    return rowHeights[indexPath.row]


更新的 TableViewController

import UIKit
import Firebase
import FirebaseStorageUI

class TableViewController: UITableViewController 
var images:[UIImage]! = [#imageLiteral(resourceName: "rininger_2.jpg")]
var imageURLS:[String] = [String]()
var rowHeights:[CGFloat] = [CGFloat]()
var listener:ListenerRegistration?

override func viewDidLoad() 
    super.viewDidLoad()
    tableView.dataSource = self
    tableView.delegate = self
    listener = Firestore.firestore().collection("Posts").addSnapshotListener
        querySnapshot, error in
        guard let snapshot = querySnapshot else 
            print("Error fetching snapshots: \(error!)")
            return
        
        snapshot.documentChanges.forEach  diff in
            if (diff.type == .added) 
                print("New data: \(diff.document.data())")
            
            if (diff.type == .modified) 
                print("Modified data: \(diff.document.data())")
            
            if (diff.type == .removed) 
                print("Removed data: \(diff.document.data())")
            

            guard let newImageURL = diff.document.data()["imageDownloadURL"] as? String else
                print("Failed to get image download URL")
                return
            
            print("downloadURL: \(newImageURL)")
            self.imageURLS.insert(newImageURL, at: 0)
            let indexPath = IndexPath(row: 0, section: 0)
            self.tableView.insertRows(at: [indexPath], with: .top)


        

    
    tableView.estimatedRowHeight = 100.0
    tableView.rowHeight = UITableViewAutomaticDimension



override func numberOfSections(in tableView: UITableView) -> Int 
    return 1


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



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

    let downloadURL = URL(string: self.imageURLS[indexPath.row])


    if cell.cellImageView.image == nil
        URLSession.shared.dataTask(with: downloadURL!)  (data, _, _) in
            if let data = data 
                let image = UIImage(data: data)
                self.images.insert(image, at: indexPath.row)
                DispatchQueue.main.async 
                    cell.setCellImage(image:image!)
                   // self.rowHeights.insert((cell.imageView?.frame.height)!, at: indexPath.row)
                   //tableView.reloadData()
                   tableView.reloadRows(at: [indexPath], with: .top)
                
            
            .resume()
    
    return cell


override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat 
    print("UITableViewAutomaticDimension: \(UITableViewAutomaticDimension)")
    return UITableViewAutomaticDimension

【问题讨论】:

你是怎么申报的? @Sh_Khan 它在UITableViewController 类的顶部声明为var rowHeights:[CGFloat]? = nil,并且不在cellForRowAtheightForRowAt 之外使用 必须像那样 var rowHeights = [CGFloat]() 为什么还要发布另一个问题(两天内现在有 8 个)而不是更新您的 previous question? 请注意,如果先加载第二张图片,您可能会崩溃...(请参阅此处的说明:***.com/questions/48170210/… 【参考方案1】:

您的代码存在大量问题

1-首先你必须下载,保存图像,然后重新加载表格

2- 秒您应该使用自动表格视图高度来完成此操作,而不是像您当前所做的那样使用高度数组

解决1

   NSString *getImagePath = [documentsPath stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.jpeg",n1.Id]];

    if([[NSFileManager defaultManager] fileExistsAtPath:getImagePath])
    
        UIImage *img = [UIImage imageWithContentsOfFile:getImagePath];
        cell.leftImageV.image =img;
        [cell.activity stopAnimating];
        cell.activity.hidden=YES;
    
    else
    

        [cell.activity startAnimating];
         cell.activity.hidden=NO;

        cell.leftImageV.image = nil;

        NSLog(@"xdasdxsadxa %@",n1.mainImgStr);

        dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

        dispatch_async(concurrentQueue, ^
            __block NSData * imageData  = nil;
            dispatch_sync(concurrentQueue, ^ 

                imageData = [[NSData alloc] initWithContentsOfURL: [NSURL URLWithString:n1.mainImgStr]];

                //Add the file name
                [imageData writeToFile:getImagePath atomically:YES]; //Write the file

            );

            dispatch_sync(dispatch_get_main_queue(), ^

                if(imageData)
                 
                    [self.tableView reloadData];

                 
            );
        ); 

解决 2

要设置行高和估计行高的自动尺寸,请确保执行以下步骤,自动尺寸对单元格/行高布局有效。我刚刚测试了以下步骤和代码并且工作正常。

分配和实现 tableview 数据源和委托 将UITableViewAutomaticDimension 分配给rowHeight 和estimatedRowHeight 实现委托/数据源方法(即heightForRowAt 并向其返回值UITableViewAutomaticDimension

-

@IBOutlet weak var table: UITableView!

override func viewDidLoad() 
    super.viewDidLoad()

    // Don't forget to set dataSource and delegate for table
    table.dataSource = self
    table.delegate = self

    // Set automatic dimensions for row height
    table.rowHeight = UITableViewAutomaticDimension
    table.estimatedRowHeight = UITableViewAutomaticDimension




// UITableViewAutomaticDimension calculates height of label contents/text
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat 
    return UITableViewAutomaticDimension

【讨论】:

在我下载图像并配置单元格后,我应该如何保存单元格。我是否使用另一个数组。另外我应该把 UIAutomaticDimension 放在哪里,当我最初尝试时,我发现所有 rowHeights 的大小都与estimatedRowHeight 相同 你必须保存图像而不是单元格,钩住单元格图像的纵横比约束并根据cellForRow中检索到的图像大小(宽度/高度)进行更改 我添加了更新后的 TableViewController 并进行了一些编辑,我添加了一个数组来保存图像并使用 UITableViewAutomaticDimension 来设置 rowHeights 但它仍在加载带有空格的图像并多次加载同一行.我是否正确实施了修改? 在文件中缓存图像,因为当您离开该视图控制器时不必再次下载它们【参考方案2】:

在向其添加值之前,请确保 rowHeights 数组已初始化 例如:

cell.setCellImage(image:image!)

if self.rowHeights == nil rowHeights = [CGFloat]() 

self.rowHeights?.insert((cell.imageView?.frame.height)!, at: indexPath.row)

【讨论】:

以上是关于为啥调用 reloadRows 后,heightForRowAt 没有在数组中找到值?的主要内容,如果未能解决你的问题,请参考以下文章

我可以在 micRowAve IndexPath... 中调用 reloadRows At IndexPath... 吗?

自定义 UITableViewCell 中的操作按钮调用的 UITableView reloadRows() 总是落后一步

UITableView - reloadRows 方法创建奇怪的滚动错误

什么 tableView.reloadRows(at: [indexPath], with: .none) 会像这样崩溃?

tableView.reloadRows(at:[indexPath],带有:.none)会像这样崩溃吗?

Swift tableView.reloadRows 删除单元格