Словарь вызывает ошибку индекса вне диапазона в Swift - PullRequest
0 голосов
/ 28 апреля 2018

Извините, если об этом уже спрашивают, но я не нашел решения для этого. Я новичок в Swift, поэтому, пожалуйста, потерпите меня. Я не могу понять, почему я получаю ошибку Тема 1: Неустранимая ошибка: Индекс выходит за пределы . Я использовал тот же метод раньше при отображении TXT-файла, с которым у меня никогда не возникало проблем, так что это впервые. Я пытаюсь отобразить координаты в виде текстовых деталей с указанием даты и времени в виде текста в самих ячейках.

Date and Time

Latitude, Longitude

Нечто подобное выше (представьте, что в клетке)

Ниже приведен мой код для программы

import UIKit
import MapKit

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {



//Array to store the list
var storeCoordinates = [String:  String]()
var arrayClient = NSMutableArray()
var readings: [String] = [" "]

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.



    //Get path of where the file is
    let path = Bundle.main.path(forResource: "gps_coords", ofType: "csv")

    //Use filemanager to check if the file exist to avoid crashing if it doesn't exist
    let fileMgr = FileManager.default

    //Display the number of line counts we have
    if fileMgr.fileExists(atPath: path!){
        do {
            let fulltext = try String(contentsOfFile: path!, encoding: String.Encoding.utf8)

            readings = fulltext.components(separatedBy: "\n") as [String]

            for i in 0..<readings.count{
                let listData = readings[i].components(separatedBy: ";") as [String]

                storeCoordinates["Latitude"] = "\(listData[0])"
                storeCoordinates["Longitude"] = "\(listData[1])"
                storeCoordinates["DateAndTime"] = "\(listData[2])"

                arrayClient.add(storeCoordinates)
            }
        } catch let error as NSError {
            print("Error: \(error)")
        }
    }
    self.title = "Number of entries: \(arrayClient.count)"
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return arrayClient.count
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "cellReuseIdentifier", for: indexPath)

    let client = arrayClient[indexPath.row] as AnyObject

    cell.textLabel?.text = "\(client.object(forKey: "DateAndTime")!)"
    cell.detailTextLabel?.text = "\(client.object(forKey: "Latitude")!) \(client.object(forKey: "Longitude")!)"

    return cell

}

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

}

Ошибка у меня на storeCoordinates["Latitude"] = "\(listData[0])" Используя точки останова, он показывает, что значение Локатора не пусто вместе с Longitude и DateAndTime, но если я пытаюсь запустить приложение в симуляторе, оно выдает ошибку Поток 1: Фатальная ошибка: Индекс выходит за пределы . Пока не повезло, пытаясь понять, как это исправить. Если бы вы могли помочь мне разобраться, это бы много значило для меня. Пожалуйста и спасибо.

Ответы [ 2 ]

0 голосов
/ 28 апреля 2018

Я считаю ненадежный формат CSV источником проблемы.

Это краткое руководство по использованию лучшего формата (JSON) и более надежного источника данных.

Часть 1: конвертировать CSV в JSON

  1. Создание новой пустой игровой площадки (нажмите ⌥⇧⌘N ) для платформы macOS
  2. Нажмите ⌘0 , чтобы отобразить навигатор проекта детской площадки.
  3. ⌥-перетащите файл CSV из навигатора проекта основного проекта в папку Resources на игровой площадке.
  4. Вставьте следующий код в игровую площадку, он основан на вашем коде для анализа CSV. Он конвертирует CSV в JSON и создает файл gps_coords.json на рабочем столе. Вы получите фатальную ошибку, если пропустите какое-либо поле.

    struct Coordinate : Encodable {
        let latitude, longitude, dateAndTime : String
    }
    
    let url = Bundle.main.url(forResource: "gps_coords", withExtension: "csv")!
    let fulltext = try! String(contentsOf: url, encoding: .utf8)
    let lines = fulltext.components(separatedBy: .newlines)
    let coordinates = lines.map { paragraph -> Coordinate in
        let components = paragraph.components(separatedBy: ";")
        if components.count != 3 { fatalError("Each line must contain all three fields")}
        return Coordinate(latitude: components[0], longitude: components[1], dateAndTime: components[2])
    }
    do {
        let data = try JSONEncoder().encode(coordinates)
        let homeURL = URL(fileURLWithPath: NSHomeDirectory())
        let destinationURL = homeURL.appendingPathComponent("Desktop/gps_coords.json")
        try data.write(to: destinationURL)
    } catch { print(error) }
    

Часть 2. Реализация нового файла

  1. Закройте игровую площадку. Это больше не нужно.
  2. Перетащите новый файл с рабочего стола в навигатор проекта (убедитесь, что установлен флажок Copy If Needed).
  3. Измените класс ViewController на

    import UIKit
    import MapKit
    
    struct Coordinate : Decodable {
        let latitude, longitude, dateAndTime : String
    }
    
    class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
    
        var arrayClient = [Coordinate]()
    
        override func viewDidLoad() {
            super.viewDidLoad()
            let url = Bundle.main.url(forResource: "gps_coords", withExtension: "json")!
            let data = try! Data(contentsOf: url)
            arrayClient = try! JSONDecoder().decode([Coordinate].self, from: data)
            self.title = "Number of entries: \(arrayClient.count)"
            tableView.reloadData()
        }
    
        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return arrayClient.count
        }
    
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            let cell = tableView.dequeueReusableCell(withIdentifier: "cellReuseIdentifier", for: indexPath)
            let client = arrayClient[indexPath.row]
    
            cell.textLabel?.text = client.dateAndTime
            cell.detailTextLabel?.text = client.latitude + " " + client.longitude
            return cell           
        }
    }
    

    Примечание: Отсутствует выход UITableView, и я добавил строку для перезагрузки данных. Также убедитесь, что delegate и datasource подключены в Интерфейсном Разработчике из табличного представления к ViewController.

  4. Удалить файл CSV.

Новый код использует структуру Coordinate в качестве источника данных и очень удобно декодирует JSON с помощью JSONDecoder. Обратите внимание, что для получения значений из словаря отсутствуют приведенные типы и громоздкая подписка на ключи.

0 голосов
/ 28 апреля 2018

Как и в комментарии, упомянутом @ vadian , вы не можете получить 0-й индекс. Но вы добавляете несколько проверок.

Обновите ваш код следующим образом:

Некоторые обновления -

Использовать массив на основе swift [[String: String]], а не NSMutableArray

Инициализируйте storeCoordinates для каждого цикла цикла и проверьте, есть ли в вашем listData больше 3 элементов или нет

class AViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
    //Array to store the list
    var arrayClient = [[String: String]]()
    var readings: [String] = []

    override func viewDidLoad() {
        super.viewDidLoad()

        //Get path of where the file is
        let path = Bundle.main.path(forResource: "gps_coords", ofType: "csv")

        //Use filemanager to check if the file exist to avoid crashing if it doesn't exist
        let fileMgr = FileManager.default

        //Display the number of line counts we have
        if fileMgr.fileExists(atPath: path!){
            do {
                let fulltext = try String(contentsOfFile: path!, encoding: String.Encoding.utf8)

                readings = fulltext.components(separatedBy: "\n") as [String]

                for i in 0..<readings.count {
                    // Check if you can get data from `readings[i]`
                    let listData = readings[i].components(separatedBy: ";") as [String]
                    if listData.count == 3 {
                        var storeCoordinates = [String: String]()
                        storeCoordinates["Latitude"] = "\(listData[0])"
                        storeCoordinates["Longitude"] = "\(listData[1])"
                        storeCoordinates["DateAndTime"] = "\(listData[2])"
                        arrayClient.append(storeCoordinates)
                    }
                }
            } catch let error as NSError {
                print("Error: \(error)")
            }
        }
        self.title = "Number of entries: \(arrayClient.count)"
    }

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

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return arrayClient.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cellReuseIdentifier", for: indexPath)

        let client = arrayClient[indexPath.row]
        if let dateTime = client["DateAndTime"], let latitude = client["DateAndTime"], let longitude = client["DateAndTime"] {
            cell.textLabel?.text = "\(dateTime)"
            cell.detailTextLabel?.text = "\(latitude) \(longitude)"
        }

        return cell
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...