Проблемы с заполнением UIPickerView массивом JSON с помощью Alamofire | стриж - PullRequest
0 голосов
/ 02 июля 2019

По сути, у меня есть textField, который при нажатии должен открыть UIPickerView с выбором, который приходит из JSON

Я отдельно работал над запуском UIPickerView при выборе UItextField и создании массивов из JSON в Swift, но у меня возникли некоторые проблемы при объединении.

Для JSON я использую Almofire просто потому, что это упрощает процесс и UIPickerView написано программно.

JSON, с которым я работаю, выглядит следующим образом:

[{“model”:”model1”},{“model":"model2”},
{“model":"model3”},{“model":"model4”},{“model":"model5”},{“model":"model6”}]

Пока что Almofire выглядит так:

        let url = NSURL(string: "https://www.test.com/test/test")

        let data = NSData(contentsOf: url! as URL)
        var tmpValues = try! JSONSerialization.jsonObject(with: data! as Data, options: JSONSerialization.ReadingOptions.mutableContainers) as! NSArray
        tmpValues = tmpValues as NSArray
        reloadInputViews()


        for candidate in tmpValues {
            if let cdict = candidate as? NSDictionary {

                //model is the column name in sql/json
                let model = cdict["model"]
                self.values.append(model! as AnyObject)


            }
        }

Запуск textField для открытия UIPickerView выполняется с использованием следующего кода:

import UIKit

class ViewController: UIViewController,UIPickerViewDataSource,UIPickerViewDelegate {


    @IBOutlet weak var TextField: UITextField!

    let model = ["model1","model2"]

    var pickerview = UIPickerView()

    override func viewDidLoad() {
        super.viewDidLoad()


        TextField.inputView = pickerview
        TextField.textAlignment = .center
        TextField.placeholder = "Select Your Model"

        pickerview.delegate = self
        pickerview.dataSource = self

        // Do any additional setup after loading the view, typically from a nib.
    }

    func numberOfComponents(in pickerView: UIPickerView) -> Int {
        return 1
    }

    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        return Names.count
    }

    func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
        return Names[row]
    }

    func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
        TextField.text = Names[row]
    }

}

Как заменить жестко запрограммированный массив ответом JSON?

1 Ответ

0 голосов
/ 02 июля 2019

Вы используете много плохих практик

  • Не используйте NSURL, NSData, NSArray, NSDictionary и AnyObject (для данных JSON) в Swift,Используйте нативные типы.
  • Не используйте .mutableContainers в Swift.Вариант бессмысленный.Не указывайте options параметр
  • Имена переменных Swift начинаются со строчной буквы.
  • Никогда загрузка данных с удаленного URL с синхронным Data(contentsOf.Используйте асинхронный URLSession

Наиболее эффективным решением является декодирование JSON с помощью Decodable

Вне класса объявляется структура

struct Model : Decodable {
    let model : String
}

Объявитьисточник выбора как переменная и во множественном числе

var models = [String]()

В viewDidLoad вставить в конце

let url = URL(string: "https://www.test.com/test/test")!
let dataTask = URLSession.shared.dataTask(with: url) { data, _, error in
    if let error = error { print(error); return }
    do { 
        let result = try JSONDecoder().decode([Model].self, from: data!)
        self.models = result.map{$0.model}
        DispatchQueue.main.async {
          self.pickerview.reloadAllComponents()
        }
    } catch { print(error) }
}
dataTask.resume()

Даже с JSONSerialization (без структуры Model) это довольнопросто

let url = URL(string: "https://www.test.com/test/test")!
let dataTask = URLSession.shared.dataTask(with: url) { data, _, error in
    if let error = error { print(error); return }
    do { 
        if let result = try JSONSerialization.jsonObject(with: data!) as? [[String:String]]
            self.models = result.compactMap{$0["model"]}
            DispatchQueue.main.async {
              self.pickerview.reloadAllComponents()
            }
        }
    } catch { print(error) }
}
dataTask.resume()

Методы источника данных выбора:

func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
    return models.count
}

func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
    return models[row]
}

func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
    TextField.text = models[row]
}

Alamofire излишне для простого запроса GET

...