2017-07-27 40 views
2

我有一個帶有用戶列表的UITableView。當你點擊一行時,用戶的uid被傳遞給UIViewController詳細視圖。製作URLRequest以檢索用戶(用戶名,頭像等)的數據。但是,詳細視圖不一致地更新信息。有時會顯示用戶的姓名,頭像等,但其他時間它什麼也不顯示,或只顯示用戶名或只顯示頭像等。Swift 3/iOS UIView在檢索遠程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

,請致電viewWillAppear獲取用戶喜歡這樣的:

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

然後,更改這裏像我一樣的代碼,在fetchUser函數的末尾不使用reloadView功能你有,相反,更新在主線程的UI元素。我也改變了它,所以你沒有兩次更新UI,因爲fetchUserif 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() 
+0

謝謝蒂米!這固定它!我花了很多小時試圖弄清楚。我想我對多線程感到困惑。非常感謝您的幫助和修改後的代碼示例! –

+0

沒問題,很高興我可以幫忙:) – Timmy

1

兩個建議:

  1. 嚴格地說,所有訪問UIView對象應該是在主線程上。您正在調度reloadView的主線程,但應該也可以在您設置標籤上的「用戶名」和「淨值」值時執行此操作
  2. 您是否確定標籤爲空?它可能是一個自動佈局問題呢? (嘗試設置標籤爲黃色,背景顏色來檢查,他們是正確的大小,有時自動佈局能夠壓制觀點下降到什麼,如果有衝突的約束)首先
+0

感謝馬修的建議。你的第一個建議是對的。我正在混淆多線程以及它是如何工作的。非常感激! –