提问者:小点点

解析json时无法将数据设置为变量


我目前正在尝试将解析json得到的数据设置为RawDataCategory文件中的ViewController变量,该文件对json进行解码。

下面是我如何调用CategoryViewController中的静态方法

class CategoryViewController: UIViewController {

    @IBOutlet weak var tableView: UITableView!
    
    var categoryProducts: [Datum]? // this is the variable i want with data i get
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        
        tableView.dataSource = self
        tableView.delegate = self
  
        Datum.fetchProducts { (categoryProductsFromJSON) -> () in   // here i call a static function.. i will paste the code below

            self.categoryProducts = categoryProductsFromJSON  //here i set value

            print(self.categoryProducts?[0].name) // if i try to print the value in the scope i can access it. and it shows with no problem
        }

            print(categoryProducts?[0].name)  //here is the problem. when i get out of the scope it return nil. 
   
    }
}

我可以访问作用域中的变量,但不知何故,当我试图在外部调用它时,它会打印nil

下面是我调用的静态函数(方法),以获取已解码的JSON:


    static func fetchProducts(_ completionHandler: @escaping ([Datum]) -> ()) { 

        guard let url = URL(string: "http://localhost:8888/dayhandan/public/api/v1/category/1") else { return }

        let session = URLSession(configuration: .default)

        let task  =  session.dataTask(with: url, completionHandler: { (data, response, error) -> Void in

            if error != nil {
                print("error")
                return
            }

            do {
                print("no error so far")
                guard let data = data else { return }

                let rawData = try JSONDecoder().decode(CategoryRawData.self, from: data)

                DispatchQueue.main.async(execute: { () -> Void in
                    completionHandler(rawData.data ?? [])
                })

            } catch let err {
                print(err)
            }
        })
        task.resume()
    }


我在解码JSON时没有得到任何错误。 实际上,我可以将它传递给我的ViewContoller。 总体上没有错误。 当我在作用域之外调用categoryproducts时,它就变成了零。

这是使用解码数据的好方法吗。 如果是的话,有人能帮我解决这个问题吗。 或者有人能指出一个好的方法来使用解码数据。 谢谢你抽出时间


共2个答案

匿名用户

这是因为您在后台线程中加载数据,当viewDidLoad运行时,它会立即打印CategoryProducts?[0].name,而无需等待下面的代码。 您的加载数据异步,因此程序不等待完成并切换到其他代码打印(categoryproducts?[0].name)

DispatchQueue.main.async(execute: { () -> Void in
                    completionHandler(rawData.data ?? [])
                })

分类产品? 仍为空,因为上载尚未完成。

如果您用sync更改,或将打印如下:

 DispatchQueue.main.asyncAfter(deadline: .now() + 10) {
                 print(categoryProducts?[0].name) 
            }

你会看到区别。

10秒延迟是为了确保加载完成

匿名用户

您应该只尝试在完成处理程序中使用FetchProducts的结果,因为完成处理程序将在将来的某个时间点执行。 完成处理程序之外的任何内容都将立即执行。

相关问题