【问题标题】:Swift 3/iOS UIView not updating after retrieving remote JSON data检索远程 JSON 数据后,Swift 3/iOS UIView 未更新
【发布时间】:2018-01-03 19:30:23
【问题描述】:

我有一个带有用户列表的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()

    }

【问题讨论】:

    标签: ios json swift uiview reload


    【解决方案1】:

    首先,像这样在viewWillAppear 中调用fetch user:

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

    然后,像我一样更改此处的代码,不要使用您拥有的reloadView 函数,而是在fetchUser 函数的末尾更新主线程上的UI 元素。我还对其进行了更改,因此您不会两次更新 UI,因为您在 fetchUser 中的 if let uid = ... 语句的底部有 4 行更新了不在主线程中的 UI 元素,这就是为什么在我的版本中我删除了那 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()
    

    【讨论】:

    • 谢谢你,蒂米!这解决了它!我浪费了很多时间试图弄清楚。我想我对多线程感到困惑。非常感谢您的帮助和修改后的代码示例!
    • 没问题很高兴我能帮上忙 :)
    【解决方案2】:

    两个建议:

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

    【讨论】:

    • 感谢马修的建议。你的第一个建议是对的。我对多线程及其工作方式感到困惑。非常感谢!
    猜你喜欢
    • 2015-11-16
    • 2015-04-24
    • 1970-01-01
    • 1970-01-01
    • 2018-01-05
    • 2015-01-05
    • 1970-01-01
    • 2019-02-01
    • 1970-01-01
    相关资源
    最近更新 更多