Swift TableView ImageView + Label = 致命错误:索引超出范围

Posted

技术标签:

【中文标题】Swift TableView ImageView + Label = 致命错误:索引超出范围【英文标题】:Swift TableView ImageView + Label = Fatal Error: Index out of range 【发布时间】:2020-06-11 10:58:27 【问题描述】:

我正在使用 tableview 来显示项目的标题,包括图像。 我正在使用 FirebaseStorage 和 FirebaseDatabase。

问题是,当我只有 一个 保护时,我一点击标题就会收到“致命错误:索引超出范围”。 当我有多个项目时,您可以在视频中看到发生了什么。

也许有人可以帮助我,因为索引处理有问题。 :)

import UIKit
import Kingfisher
import Foundation
import FirebaseStorage
import FirebaseDatabase

class HomeViewController: UIViewController  

    // MARK: - Properties

    @IBOutlet weak var tableView: UITableView!
    @IBOutlet weak var addProject: UIButton!


    var posts = [Post]()



    var textToBeSent: String = ""
    override func viewDidLoad() 
        super.viewDidLoad()

        UserService.posts(for: User.current)  (posts) in
            self.posts = posts
            self.tableView.reloadData()
        

        Utilities.addShadowtoButton(addProject)

    

    func configureTableView() 
        // remove separators for empty cells
        tableView.tableFooterView = UIView()
        // remove separators from cells
        tableView.separatorStyle = .none
    
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) 
        if segue.identifier == "toDetails" 
            let destVC = segue.destination as! ShowProjectDetailsViewController
            destVC.post = sender as? Post
        
    


extension Collection where Indices.Iterator.Element == Index 
             public subscript(safe index: Index) -> Iterator.Element? 
               return (startIndex <= index && index < endIndex) ? self[index] : nil
             
          

// MARK: - UITableViewDataSource

extension HomeViewController: UITableViewDataSource 

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) 
        let post = posts[indexPath.row]
        performSegue(withIdentifier: "toDetails", sender: post)

    

  func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
      return 2
  

    func numberOfSections(in tableView: UITableView) -> Int 
        return posts.count
    

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
        let post = posts[indexPath.section]

        switch indexPath.row 
        case 0:

            let cell = tableView.dequeueReusableCell(withIdentifier: "PostImageCell") as! PostImageCell
            let imageURL = URL(string: post.imageURL)
            cell.postImageView.kf.setImage(with: imageURL)

            return cell

        case 1:

            let cell = tableView.dequeueReusableCell(withIdentifier: "PostSubCell") as! PostSubCell
            cell.projectName.text = post.projectTitle

            return cell


        default:
            fatalError("Error: unexpected indexPath.")
        
    



// MARK: - UITableViewDelegate

extension HomeViewController: UITableViewDelegate 

    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat 
        switch indexPath.row 
        case 0:

           let post = posts[indexPath.section]
           return post.imageHeight

        case 1:

       return PostSubCell.height

        default:
            fatalError()
        
    
    



import Foundation
import FirebaseAuth.FIRUser
import FirebaseDatabase
import FirebaseUI
import FirebaseAuth


struct UserService 

         static func posts(for user: User, completion: @escaping ([Post]) -> Void) 

            let ref = Database.database().reference().child("posts").child(user.uid)

            ref.observe(DataEventType.value, with:  (snapshot) in
               guard let snapshot = snapshot.children.allObjects as? [DataSnapshot] else 
                   return completion([])
            

            let posts = snapshot.reversed().compactMap(Post.init)
            completion(posts)
        )
    




import Foundation
import UIKit
import FirebaseDatabase.FIRDataSnapshot

class Post 

//      Next let's add properties to store all the additional information we need. Add the following to your post class.
    var key: String?

       let imageURL: String
       let imageHeight: CGFloat
       let creationDate: Date
       let imageName: String
       let projectTitle: String
       let projectLocation: String
       let projectDescription: String
       let projectBeginn: String
       let projectEnd: String


//    You'll get some compiler errors for not having any initializers or default values for certain properties. Let's go ahead and fix that:

    init(imageURL: String, imageName: String, imageHeight: CGFloat, projectTitle: String, projectLocation: String, projectDescription: String, projectBeginn: String, projectEnd: String) 
        self.imageURL = imageURL
        self.imageName = imageName
        self.imageHeight = imageHeight
        self.creationDate = Date()
        self.projectTitle = projectTitle
        self.projectLocation = projectLocation
        self.projectDescription = projectDescription
        self.projectBeginn = projectBeginn
        self.projectEnd = projectEnd
    

    var dictValue: [String : Any] 
        let createdAgo = creationDate.timeIntervalSince1970

        return ["image_url" : imageURL,
                "image_name" : imageName,
                "image_height" : imageHeight,
                "created_at" : createdAgo,
                "projectTitle" : projectTitle,
                "projectLocation" : projectLocation,
                "projectDescription" : projectDescription,
                "projectBeginn" : projectBeginn,
                "projectEnd": projectEnd ]

    
    init?(snapshot: DataSnapshot) 
        guard let dict = snapshot.value as? [String : Any],
            let imageURL = dict["image_url"] as? String,
            let imageName = dict["image_name"] as? String,
            let imageHeight = dict["image_height"] as? CGFloat,
            let createdAgo = dict["created_at"] as? TimeInterval,
            let projectTitle = dict["projectTitle"] as? String,
            let projectLocation = dict["projectLocation"] as? String,
            let projectDescription = dict["projectDescription"] as? String,
            let projectBeginn = dict["projectBeginn"] as? String,
            let projectEnd = dict["projectEnd"] as? String




            else  return nil 

        self.key = snapshot.key
        self.imageURL = imageURL
        self.imageName = imageName
        self.imageHeight = imageHeight
        self.creationDate = Date(timeIntervalSince1970: createdAgo)
        self.projectTitle = projectTitle
        self.projectLocation = projectLocation
        self.projectDescription = projectDescription
        self.projectBeginn = projectBeginn
        self.projectEnd = projectEnd

       
  


感谢您的帮助!

【问题讨论】:

在您的didSelect 中,您使用的是indexPath.row,但每个帖子只有一个部分,所以我认为您应该使用indexPath.section 通过使用上面的代码,布局在您的项目中根据您的需要正确显示?? 【参考方案1】:

您由[Post] 创建了您的numberOfSection。您还可以在点击indexPath.row 时分配performSegue。所以它会抛出一个错误,你必须在didSelectItem()方法中使用indexPath.section而不是indexPath.row

例如

 func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)   
 
     let post = posts[indexPath.section] // Use here section instead of row
     performSegue(withIdentifier: "toDetails", sender: post)

 

【讨论】:

欢迎快乐 coading :)

以上是关于Swift TableView ImageView + Label = 致命错误:索引超出范围的主要内容,如果未能解决你的问题,请参考以下文章

Swift3 iOS - Navigation TitleView 中的圆形 ImageView 保持显示正方形?

cell.imageView!.frame 大小变化。迅速

swift中选择后UITableViewCell布局错误

TableViewCell 不显示 imageView

迅速;带有tableView的scrollView可行吗?

编辑 tableView 时自定义单元格 imageView 移到左侧