下午好。我正在完成最后一年的项目,在我的项目中,我使用 Google Maps API
在 CollectionView
中显示结果。
如果我测试打印数组,结果是成功的,并且我得到了显示的数据。 有时应用程序运行得很好,如果我运行它,它会运行并正常工作,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 个项目时都会引发异常。
编辑 - 代码优化
- 您可以尝试通过解码为数组来优化
parseJSON
函数,避免使用 for 循环:
func parseJSON(bloodBankData: Data) {
let decoder = JSONDecoder()
do {
bloodBanksArray = try decoder.decode([BloodBanksData].self, from: bloodBankData)
} catch {
print(error)
}
}
- 您可以像这样更改
cellForItemAt
方法,避免对同一行项目的多次访问。
另外,对 placeholderImage 使用全局变量,因为它始终相同。
最后,尝试减小maxheight
和maxwidth
参数的值:
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/