ios - fatal error : Index out of range: file Swift/ContiguousArrayBuffer. swift,第 444 行,有时可以工作

标签 ios json swift

下午好。我正在完成最后一年的项目,在我的项目中,我使用 Google Maps APICollectionView 中显示结果。

如果我测试打印数组,结果是成功的,并且我得到了显示的数据。 有时应用程序运行得很好,如果我运行它,它会运行并正常工作,75% 的时间我会收到 fatal error :索引超出范围:文件 Swift/ContigouslyArrayBuffer.swift,第 444 行。

非常感谢任何帮助,非常感谢。

    import Foundation

// MARK: - BloodBanksData
struct BloodBanksData: Codable {
    let results: [Result]

    enum CodingKeys: String, CodingKey {
        case results
    }
}

// MARK: - Result
struct Result: Codable {
    let geometry: Geometry
    let name: String
    let openingHours: OpeningHours?
    let photos: [Photo]?
    let rating: Double
    let vicinity: String

    enum CodingKeys: String, CodingKey {
        case geometry, name
        case openingHours = "opening_hours"
        case photos
        case rating
        case vicinity
    }
}

// MARK: - Geometry
struct Geometry: Codable {
    let location: Location
}

// MARK: - Location
struct Location: Codable {
    let lat, lng: Double
}

// MARK: - OpeningHours
struct OpeningHours: Codable {
    let openNow: Bool

    enum CodingKeys: String, CodingKey {
        case openNow = "open_now"
    }
}

// MARK: - Photo
struct Photo: Codable {
    let photoReference: String

    enum CodingKeys: String, CodingKey {
        case photoReference = "photo_reference"
    }
}

我的模型:

import Foundation
struct BloodBanksModel {
    let name: String
    let photo: String
    let open_now: Bool
    let longitude: Double
    let latitude: Double
    let vincinity: String
    let rating: Double
}

我的经理类(class):

import Foundation

class BloodBanksManager {
    var bloodBanksArray = [BloodBanksModel]()
    
    
    //MARK: - Decoding JSON
    func performRequest(){
        if let url = URL(string: "https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=XX,XX&radius=1000.0&rankby=prominence&sensor=true&key=XXXXX&keyword=blood") {
            
            let session = URLSession(configuration: .default)
            
            let task = session.dataTask(with: url) { (data, response, error) in
                if error != nil {
                    print(error!)
                    return
                }
                
                if let safeData = data {
                    self.parseJSON(bloodBankData: safeData)
                }
            }
            task.resume()
        }
    }
    
    func parseJSON(bloodBankData: Data) {
        let decoder = JSONDecoder()
        
        do {
        let decodedData = try decoder.decode(BloodBanksData.self, from: bloodBankData)
            for i in 0...decodedData.results.count - 1 {
                bloodBanksArray.append(BloodBanksModel(name: decodedData.results[i].name, photo: decodedData.results[i].photos?[0].photoReference ?? decodedData.results[0].photos![0].photoReference, open_now: decodedData.results[i].openingHours?.openNow ?? false, longitude: decodedData.results[i].geometry.location.lng, latitude: decodedData.results[i].geometry.location.lat, vincinity: decodedData.results[i].vicinity, rating: decodedData.results[i].rating))
            }
            
        } catch {
            print(error)
        }
    }
    
}

我的 View Controller :

   var bloodBanksManager = BloodBanksManager()
    override func viewDidLoad() {
            super.viewDidLoad()
    ...
    bloodBanksManager.performRequest()
    ...
    }
// MARK: - UICollectionViewDataSource Methods
extension LandingViewController: UICollectionViewDataSource {
    func numberOfSections(in collectionView: UICollectionView) -> Int {
        return 1
    }
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 3
    }
    
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: K.BloodBanks.bloodBankCellIdentifier, for: indexPath) as! BloodBanksCell
 cell.bloodBankName.text = self.bloodBanksManager.bloodBanksArray[indexPath.row].name
        cell.bloodBankImageView.sd_setImage(with: URL(string: "https://maps.googleapis.com/maps/api/place/photo?photoreference=\(bloodBanksManager.bloodBanksArray[indexPath.row].photo)&sensor=false&maxheight=1000&maxwidth=1000&key=XXX"), placeholderImage: #imageLiteral(resourceName: "bloodbank4"))
        
        return cell
    }
    
}

最佳答案

您应该将 numberOfItemsInSection 方法更改为:

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return self.bloodBanksManager.bloodBanksArray.count
}

通过返回 3,您假设数组的长度始终为 3 个项目,因此每当您的 bloodBanksArray 超过 3 个项目时都会引发异常。

编辑 - 代码优化

  1. 您可以尝试通过解码为数组来优化 parseJSON 函数,避免使用 for 循环:
func parseJSON(bloodBankData: Data) {
    let decoder = JSONDecoder()
        
    do {
        bloodBanksArray = try decoder.decode([BloodBanksData].self, from: bloodBankData)
    } catch {
        print(error)
    }
}
  • 您可以像这样更改 cellForItemAt 方法,避免对同一行项目的多次访问。
    另外,对 placeholderImage 使用全局变量,因为它始终相同。
    最后,尝试减小 maxheightmaxwidth 参数的值:
  • let placeholderImage = #imageLiteral(resourceName: "bloodbank4")
    
    ...
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: K.BloodBanks.bloodBankCellIdentifier, for: indexPath) as! BloodBanksCell
        let bloodBankItem = self.bloodBanksManager.bloodBanksArray[indexPath.row]
        cell.bloodBankName.text = bloodBankItem.name
    
        let maxImageSize = 500
        guard let imgUrl = URL(string: "https://maps.googleapis.com/maps/api/place/photo?photoreference=\(bloodBankItem.photo)&sensor=false&maxheight=\(maxImageSize)&maxwidth=\(maxImageSize)&key=XXX") else {
            return cell
        }
        cell.bloodBankImageView.sd_setImage(with: imgUrl, placeholderImage: placeholderImage)
            
        return cell
    }
    

    加载缓慢的其他原因可能是: 3. 网速慢 4. 用于加载图像的库未使用延迟加载,有关 UITableView/UICollectionView 上延迟加载的更多信息,请参阅 this

    关于ios - fatal error : Index out of range: file Swift/ContiguousArrayBuffer. swift,第 444 行,有时可以工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67473325/

    相关文章:

    ios - Service和Viewcontroller之间如何通信?

    iphone 开发 : caching images with asyncimageview library

    ios - 使用手势识别器和 swift 查找发件人标签

    ios - 激活元素时如何获取indexpath.row?

    ios - 当我快速滚动时,CollectionViewCell 显示错误的图像

    iphone - 强制后台应用程序在 iOS 模拟器中终止

    java - HSSFCell 读取空错误?

    javascript - Angularjs - JSON 对象编辑

    c# - 从 ASP.NET Controller 返回动态 jsonobject

    ios - 如何隐藏标签?