Swift 3/iOS 检索远程 JSON 数据后 UIView 未更新

Swift 3/iOS UIView not updating after retrieving remote JSON data

我有一个包含用户列表的 UITableView。当您点击一行时,用户的 uid 将传递到 UIViewController 详细信息视图。 URLRequest 用于检索用户的 JSON 数据(用户名、头像等)。但是,详细视图不一致地更新信息。有时会显示用户名、头像等,但有时什么也不显示,或者只显示用户名或只显示头像等

fetchUser() 方法中,我有一个 print("Username: \(self.user.username)") 显示 100% 的时间正在检索正确的数据,但它不会 100% 的时间显示在视图中.

如有任何帮助,我们将不胜感激。

谢谢!

class ProfileViewController: UIViewController {

    @IBOutlet weak var avatarImageView: UIImageView!
    @IBOutlet weak var usernameLabel: UILabel!
    @IBOutlet weak var networthLabel: UILabel!

    var user: User!
    var uid: Int?

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
        fetchUser()
    }

    func reloadView() {
        self.usernameLabel.text = user.username
        self.networthLabel.text = "$" + NumberFormatter.localizedString(from: Int((user.networth)!)! as NSNumber, number: NumberFormatter.Style.decimal)
        self.avatarImageView.downloadImage(from: user.avatar!)
        circularImage(photoImageView: self.avatarImageView)
    }

    func fetchUser() {
        // Post user data to server
        let myUrl = NSURL(string: "http://localhost/test/profile")
        let urlRequest = NSMutableURLRequest(url: myUrl! as URL);
        urlRequest.httpMethod = "POST"

        let postString = "uid=\(uid!)"

        urlRequest.httpBody = postString.data(using: String.Encoding.utf8)

        let task = URLSession.shared.dataTask(with: urlRequest as URLRequest) { (data, response, error) in

            if (error != nil) {
                print("error=\(String(describing: error))")
                return
            } // end if

            self.user = User()

            do {

                let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? [String : AnyObject]

                if let parseJSON = json?["data"] as? [[String : AnyObject]] {

                    for userFromJson in parseJSON {

                        let userData = User()

                        if let uid = userFromJson["uid"] as? String,
                            let username = userFromJson["username"] as? String,
                            let networth = userFromJson["networth"] as? String,
                            let avatar = userFromJson["avatar"] as? String {

                            userData.uid = Int(uid)
                            userData.username = username
                            userData.networth = networth
                            userData.avatar = avatar

                            self.usernameLabel.text = username
                            self.networthLabel.text = networth
                            self.avatarImageView.downloadImage(from: avatar)
                            circularImage(photoImageView: self.avatarImageView)

                        } // end if

                        self.user = userData

                    } // end for

                } // end if

                DispatchQueue.main.async {
                    print("Username: \(self.user.username)")
                    self.reloadView()
                }

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

    }

两条建议:

  1. 严格来说,所有对UIView对象的访问都应该在主线程上。您正在分派到主线程以调用 reloadView,但是当您在标签
  2. 上设置 "username" 和 "net worth" 值时,也应该这样做
  3. 确定标签是空白的吗?它可能是一个自动布局问题吗? (尝试将标签的背景颜色设置为黄色,以检查它们的大小是否正确。有时,如果存在冲突约束,自动布局可以将视图压缩为空)

首先,像这样调用 viewWillAppear 中的获取用户:

override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) fetchUser() }

然后,像我一样更改这里的代码,不要使用你的 reloadView 功能,而是在 [= 结束时更新主线程上的 UI 元素14=] 函数。我也改变了它所以你没有更新 UI 两次,因为你在 fetchUser 中的 if let uid = ... 语句底部有 4 行更新了 UI 元素' t 在主线程中,这就是为什么在我的版本中我删除了那 4 行代码。如果这对你有用,请告诉我。

let task = URLSession.shared.dataTask(with: urlRequest as URLRequest) { (data, response, error) in

        if (error != nil) {
            print("error=\(String(describing: error))")
            return
        } // end if

        self.user = User()

        do {

            let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? [String : AnyObject]

            if let parseJSON = json?["data"] as? [[String : AnyObject]] {

                for userFromJson in parseJSON {

                    let userData = User()

                    if let uid = userFromJson["uid"] as? String,
                        let username = userFromJson["username"] as? String,
                        let networth = userFromJson["networth"] as? String,
                        let avatar = userFromJson["avatar"] as? String {

                        userData.uid = Int(uid)
                        userData.username = username
                        userData.networth = networth
                        userData.avatar = avatar

                    } // end if

                    self.user = userData

                } // end for

            } // end if

            DispatchQueue.main.async {
                self.usernameLabel.text = user.username
                self.networthLabel.text = "$" + NumberFormatter.localizedString(from: Int((user.networth)!)! as NSNumber, number: NumberFormatter.Style.decimal)
                self.avatarImageView.downloadImage(from: user.avatar!)
                circularImage(photoImageView: self.avatarImageView)
            }

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