索引超出范围Firebase存储

时间:2018-06-21 20:21:25

标签: ios swift firebase firebase-storage

我有以下代码。我正在尝试将图像上传到Firebase Storage并在对应的单元格中填充每个图像。当我运行程序时,出现致命错误:索引超出了范围:

cell.adImageView.image = fotografiiProfil[nrTotalProduse - indexPath.row - 1]

您能找到结果为什么会这样吗?

import UIKit
import Firebase
import FirebaseFirestore
import FirebaseStorage

class AnunturiViewController: UITableViewController {

    // MARK: - Properties
    /*****************************************/

    var anunturi: [Produs] = [Produs]()

    var docRef: CollectionReference!
    var docRefNrTotalProduse: DocumentReference!

    let imageNames = ["sneakers", "tshirt", "hoodie", "jacket", "pants", "accessory"]

    let activityIndicator = UIActivityIndicatorView()

    var fotografiiProfil: [UIImage] = []

    var nrTotalProduse: Int = 0
    var isDone: Bool!

    // MARK: - Application Methods
    /*****************************************/

    override func viewDidLoad() {
        super.viewDidLoad()

        isDone = false

        activityIndicator.activityIndicatorViewStyle = .gray
        activityIndicator.center = self.view.center
        activityIndicator.hidesWhenStopped = true
        activityIndicator.startAnimating()
        self.view.addSubview(activityIndicator)

        self.tableView.tableFooterView = UIView(frame: CGRect(x: 0, y: 0, width: self.view.frame.width, height: 49))

        docRefNrTotalProduse = Firestore.firestore().collection("anunturi").document("anunturi")

        reloadTableView()
    }

    // MARK: - TableView Delegate and DataSource Methods
    /*****************************************/

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "ADCell") as! ADTableViewCell
        if isDone == true {
            print(indexPath.row)
            cell.adImageView.image = fotografiiProfil[nrTotalProduse - indexPath.row - 1]
            cell.numeLabel.text = self.anunturi[nrTotalProduse - indexPath.row - 1].nume
            cell.descriereLabel.text = self.anunturi[nrTotalProduse - indexPath.row - 1].descriere
            cell.marimeLabel.text = self.anunturi[nrTotalProduse - indexPath.row - 1].marime
            cell.locatieLabel.text = self.anunturi[nrTotalProduse - indexPath.row - 1].locatie
            cell.pretLabel.text = self.anunturi[nrTotalProduse - indexPath.row - 1].pret
            switch self.anunturi[nrTotalProduse - indexPath.row - 1].categorie {
            case "sneakers":
                cell.categorieImageView.image = UIImage(named: self.imageNames[0])
                break
            case "tricouri":
                cell.categorieImageView.image = UIImage(named: self.imageNames[1])
                break
            case "bluze":
                cell.categorieImageView.image = UIImage(named: self.imageNames[2])
                break
            case "jachete":
                cell.categorieImageView.image = UIImage(named: self.imageNames[3])
                break
            case "pantaloni":
                cell.categorieImageView.image = UIImage(named: self.imageNames[4])
                break
            case "accesorii":
                cell.categorieImageView.image = UIImage(named: self.imageNames[5])
                break
            default:
                break
            }
        }
        return cell
    }

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

    override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 164.0
    }

    // MARK: - IBACtions
    /*****************************************/

    @IBAction func onRefreshButtonPressed(_ sender: UIBarButtonItem) {
        reloadTableView()
    }

    // MARK: - Fetch Data From Firestore
    /*****************************************/

    func reloadTableView() {
        fetchDataForNumberOfProducts()
    }

    func fetchData() {
        anunturi.removeAll()
        docRef = Firestore.firestore().collection("anunturi")
        docRef.getDocuments() { (querySnapshot, error) in
            if let error = error {
                print("Error getting documents: \(error)")
            } else {
                for document in querySnapshot!.documents {
                    let data = document.data()
                    if document == querySnapshot?.documents.last {
                        self.fetchImages()
                    } else {
                        let produs = Produs(nume: (data["nume"] as? String)!,
                                            descriere: (data["descriere"] as? String)!,
                                            marime: (data["marime"] as? String)!,
                                            produsNou: (data["produsNou"] as? Bool)!,
                                            fotografii: (data["fotografii"] as? [String])!,
                                            locatie: (data["locatie"] as? String)!,
                                            livrezTara: (data["livrezTara"] as? Bool)!,
                                            email: (data["email"] as? String)!,
                                            telefon: (data["telefon"] as? String)!,
                                            pret: (data["pret"] as? String)!,
                                            autor: (data["autor"] as? String)!,
                                            categorie: (data["categorie"] as? String)!)
                        self.anunturi.append(produs)
                    }
                }
            }
        }
    }

    func fetchImages() {
        for i in 0...(nrTotalProduse - 1) {
            let storage = Storage.storage()
            let storageRef = storage.reference()
            let imageRef = storageRef.child("fotografii/" + anunturi[i].fotografii[0])
            imageRef.getData(maxSize: 1024 * 1024 * 1024) { (data, error) in
                if error != nil {
                    print(error!.localizedDescription)
                } else {
                    self.fotografiiProfil.append(UIImage(data: data!)!)
                    if i == self.nrTotalProduse - 1 {
                        self.doneFetching()
                    }
                }
            }
        }
    }

    func doneFetching() {
        isDone = true
        tableView.reloadData()
        activityIndicator.stopAnimating()
    }

    func fetchDataForNumberOfProducts() {
        docRefNrTotalProduse = Firestore.firestore().collection("anunturi").document("anunturi")

        docRefNrTotalProduse.getDocument { (snapshot, error) in
            if error != nil { print(error ?? "0") }
            else {
                let data = snapshot?.data()
                self.nrTotalProduse = data!["numarAnunturi"] as! Int
                self.fetchData()
            }
        }
    }

}

3 个答案:

答案 0 :(得分:0)

fotografiiProfil[]的索引不能小于0。

var num = indexPath.row -1
if nrTotalProduce = num && num < fotografiiProfil.count {
   cell.adImageView.image = fotografiiProfil[num]
}

答案 1 :(得分:0)

评估索引:nrTotalProduse - indexPath.row - 1。 它不能低于0或超出数组fotografiiProfil的最后一项(长度-1)。

在实际分配索引值之前添加索引值的打印内容将有助于您调试代码。

添加:

print(indexPath.row)
print(nrTotalProduse)
print(nrTotalProduse - indexPath.row - 1)

答案 2 :(得分:0)

基于我们试图解决帖子中错误的困惑,我决定举一个例子说明我已经完成了自己的工作(至少我认为自己正在做的事情) 。有一些清理工作将使您的代码更易于理解和更高效。首先,我不确定为什么要进行数学运算而不是使用indexPath.row来计算数组的索引。那正是您的问题所在。这段代码有望清除如何使您的数据共享相同的索引,从而避免您进行计算。

首先,我定义了一个类(与您一样)来保存数据库中存储的数据。这是该课程:

class Angel {
    var name: String? 
    var email: [String]? // multiple Emails
    var phone: [String]? // multiple Numbers
    var photo: UIImage? // variable to hold image 
    var filepath: String? // variable to hold image URL 
}

接下来,我创建了一个数据源单例,以在应用程序的所有页面之间共享数据。此数据源还有更多内容,但就本示例而言,这是您需要查看的内容:

class PageDataSource {
    /**
     Store for Angel, User, CRUD, and Checkin info
     */

    var angels = [Angel]() // array to hold the Angel objects
    var crudIsAvailable: Bool? // check for connection stored variable

    // singleton for global access
    static let sharedInstance = PageDataSource()
    private init() {}
}

将Angel对象存储到Firebase之后,我不得不编写一种方法来检索它:

// Read function to download the data from Firebase 
func readAngels(completion:  @escaping (_ error: NSError?) -> Void)  {
    if PageDataSource.sharedInstance.crudIsAvailable == true { // check for connection
        Database.database().reference().child("angels").child(id).observeSingleEvent(of: .value) { (snapshot) in
            print(snapshot)
            var angels = [Angel]() // array to store firebase data 
            if let snapshots = snapshot.children.allObjects as? [DataSnapshot] {
                for snap in snapshots { // loop through each angel object stored in the database
                    var angel = Angel()
                    if let dict = snap.value as? Dictionary<String, AnyObject> {
                        angel.name = dict["name"] as? String ?? ""
                        angel.email = dict["email"] as? [String] ?? [""]
                        angel.phone = dict["phone"] as? [String] ?? [""]
                        angel.filepath = dict["photo"] as? String ?? "" // get filepath for photo download 

                        angels.append(angel) // add new angel to array 
                    }
                }
                PageDataSource.sharedInstance.angels = angels // set new array of angels as the loaded angels in singleton
                completion(nil)
            } else {
                completion(NSError(domain: "Error reading Snapshots", code: 99, userInfo: nil))
            }
        }
    } else {
        completion(NSError(domain: "Unavailable", code: 0, userInfo: nil))
    }
}

调用readAngels()函数:

// using the readAngels() function to load angels
readAngels(completion: { (err) in
    if err != nil {
        print(err!.localizedDescription)
    } else {
        // do proper segue. No angels = sign up, 1 or more = login
        if PageDataSource.sharedInstance.angels.count == 0 {
            // User exists but no angels have been stored
            self.performSegue(withIdentifier: "signUpSegue", sender: self)
        } else {
            // Stored angels detected, proceed with app flow
            self.performSegue(withIdentifier: "logInSegue", sender: self)
        }
    }
}) 

调用readAngels()函数后,我将加载tableView。布置单元格后,我读取了存储在数据源中的数据并填充了单元格。如果在数据源中有一张已经被解码的照片被立即加载。如果没有,我使用filepath中的datasource来检索图像:

// tableView function to populate cells
// this will load images asyncronously as the cells are displayed on the screen
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = UITableViewCell(style: .default, reuseIdentifier: "CellID") // set cell for reuse 
    // check for image already loaded in Datasource
    if let pic = PageDataSource.sharedInstance.angels[indexPath.row].photo  {
        // if image is already available set imageView content 
        cell.imageView?.image = pic
        cell.setNeedsLayout()
        // if no image in Datasource pull it from firebase storage
    } else if let imgURL = PageDataSource.sharedInstance.angels[indexPath.row].filepath {
        Storage.storage().reference(forURL: imgURL).getData(maxSize: INT64_MAX, completion: { (data, error) in
            guard error == nil else {
                print("error downloading: \(error!)")
                return
            }
            // render
            let img = UIImage.init(data: data!)
            // store to datasource
            PageDataSource.sharedInstance.angels[indexPath.row].photo = img
            // display  img
            if cell == tableView.cellForRow(at: indexPath){
                DispatchQueue.main.async {
                    cell.imageView?.image = img
                    cell.setNeedsLayout()
                }
            }
        })
    } else {
        cell.imageView?.image = UIImage(contentsOfFile: "Placeholder.png")
    }
    // set text
    cell.textLabel?.text = PageDataSource.sharedInstance.angels[indexPath.row].name
    return cell
}