使用 Alamofire 使用 JSON 数组填充 UIPickerView 时遇到问题 |迅速

Posted

技术标签:

【中文标题】使用 Alamofire 使用 JSON 数组填充 UIPickerView 时遇到问题 |迅速【英文标题】:Trouble populating UIPickerView with JSON array using Alamofire | Swift 【发布时间】:2019-07-02 18:28:54 【问题描述】:

基本上我有一个 textField 按下时需要打开一个 UIPickerView 并带有来自 JSON 的选择

在选择 UItextField 并在 Swift 中从 JSON 创建数组时,我分别处理了触发 UIPickerView 的工作,但在组合时遇到了一些麻烦。

对于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 响应替换硬编码数组?

【问题讨论】:

请不要在 Swift 中使用 NSURLNSDataNSArrayNSDictionary.mutableContainersAnyObject(用于 JSON 数据)。使用本机类型。 Swift 变量名以小写字母开头。并且从不使用同步 Data(contentsOf 从远程 URL 加载数据。不要那样做。 我很欣赏这些指针,为什么“使用同步 Data(contentsOf”从远程 URL 加载数据是不好的 它阻塞了线程。这会导致糟糕的用户体验。想象一下服务器目前不可用...... 【参考方案1】:

你使用了很多不好的做法

不要在 Swift 中使用 NSURLNSDataNSArrayNSDictionaryAnyObject(用于 JSON 数据)。使用原生类型。 不要在 Swift 中使用 .mutableContainers。该选项毫无意义。省略options 参数 Swift 变量名以小写字母开头。 永远不会使用同步 Data(contentsOf 从远程 URL 加载数据。使用异步URLSession

最有效的解决方案是使用Decodable解码JSON

在类之外声明结构

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 请求来说太过分了

【讨论】:

哦,当然,我没有想到这一点。你熟悉如何在 UIPickerView 中实现 JSON 响应吗? 声明modelvariable,将结果赋值给modelself.model = result.map$0.model并在DispatchQueue闭包中重新加载picker数据:self.pickerview.reloadAllComponents() 您能否在回答中详细说明这一点?我以前做过类似的事情,但没有奏效。 如果在 Alamofire 中也是 JSON Post 请求,我可以做什么:let parameters: Parameters = ["customer": "\(Customer)"] Alamofire.request(url, method: .post, parameters: parameters).responseString response in print(response) 例如,没有它我可以完成吗? 您的问题没有提到 POST 请求。你也可以用URLSession 来做。顺便说一句,Alamofire 很大程度上基于URLSession

以上是关于使用 Alamofire 使用 JSON 数组填充 UIPickerView 时遇到问题 |迅速的主要内容,如果未能解决你的问题,请参考以下文章

如何使用来自 Alamofire 的 JSON 数据填充 tableview?

使用 AlamoFire 获取数据以根据 UISearchBar 值填充 UITableView

使用 Alamofire 响应填充表视图

使用多个 Alamofire 链接请求填充 tableview

Alamofire:使用 JSON 数据更新数组的值

使用 alamofire swift 发布 json 数组