4

来自 New Firebase 的扩展问题 检索数据并放在 tableView (Swift)

通过将 Firebase 代码移动到 viewDidLoad,Post 的所有文本部分都可以当前显示。但是我还是不能把图片放到tableView上。我检查了图像检索并且它是成功的,我想我从 Firebase 检索的图像不在 post 数组中。

这是我的修复代码:

  import UIKit
  import Firebase
  import FirebaseStorage

class timelineTableViewController: UITableViewController {
var posts = [Post]()
var databaseRef: FIRDatabaseReference!
var storageRef: FIRStorageReference!

override func viewDidLoad() {
    super.viewDidLoad()
    databaseRef = FIRDatabase.database().reference()
    storageRef = FIRStorage.storage().reference()
    let userPostRef = self.databaseRef.child("posts")
    userPostRef.queryOrderedByChild("time").observeEventType(.ChildAdded, withBlock: {(snapshot) in
        if let postAdd  = snapshot.value as? NSDictionary{

            let url = snapshot.value?["postPhoto"] as! String
            let userPhotoUrl = snapshot.value?["userPhoto"] as! String
            let myPost = Post(data: postAdd)

            FIRStorage.storage().referenceForURL(url).dataWithMaxSize(10 * 1024 * 1024, completion: { (data, error) in
                let postPhoto = UIImage(data: data!)

                                    })
            FIRStorage.storage().referenceForURL(userPhotoUrl).dataWithMaxSize(10 * 1024 * 1024, completion: { (data, error) in
                let userPhoto = UIImage(data: data!)
                                })

            self.posts.insert(myPost, atIndex: 0)
            self.tableView.reloadData()

        }




})

}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
    // #warning Incomplete implementation, return the number of sections
    return 1
}

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return posts.count


}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cellIdentifier = "postCell"
    let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath)as! timelineTableViewCell
    //Dispatch the main thread here
    dispatch_async(dispatch_get_main_queue()) {
        cell.usernameLabel.text = self.posts[indexPath.row].username
        cell.postText.text = self.posts[indexPath.row].postText
        cell.timeLabel.text = self.posts[indexPath.row].time
        cell.postPhoto.image = self.posts[indexPath.row].postPhoto
        cell.userPhoto.image = self.posts[indexPath.row].userPhoto


    }
    return cell
   }
   }

我的 Post 结构希望它可能会有所帮助!

struct  Post {
var username: String?
var postText: String?
var time: String?
var userPhoto: UIImage?
var postPhoto: UIImage?
var url: String?
var userPhotoUrl:String?
init(data: NSDictionary) {
   username = data["username"] as? String
   postText = data["postText"] as? String
    time = data["time"]as? String
    userPhoto = data["userPhoto"] as? UIImage
    postPhoto = data["postPhoto"] as? UIImage
    url = data["postPhoto"] as? String
    userPhotoUrl = data["userPhoto"] as? String
}

}

希望能得到一些建议!

4

3 回答 3

7

只需更改以下方法

func downloadPost(){
    let userPostRef = self.databaseRef.child("posts")

    userPostRef.queryOrderedByChild("time").observeEventType(.ChildAdded, withBlock: {(snapshot) in
        if let postAdd  = snapshot.value as? NSDictionary {
            print("\(snapshot.value)")
            let url = snapshot.value?["postPhoto"] as! String
            let userPhotoUrl = snapshot.value?["userPhoto"] as! String

            var myPost = Post(data: postAdd) //variable change to "var" because going to modify

            let url2 = NSURL(string: url)  //postPhoto URL
            let data = NSData(contentsOfURL: url2!) // this URL convert into Data
            if data != nil {  //Some time Data value will be nil so we need to validate such things 
             myPost.postPhoto = UIImage(data: data!)
            }


            let url3 = NSURL(string: userPhotoUrl)  //userPhoto URL
            let data2 = NSData(contentsOfURL: url3!)  //Convert into data
            if data2 != nil  {  //check the data
            myPost.userPhoto = UIImage(data: data2!)  //store in image
            }




            self.posts.insert(myPost, atIndex: 0)  // then add the "myPost"  Variable
            print(self.posts.count)
        }
        self.tableView.reloadData()  // finally going to load the collection of data in tableview
    })


}

它需要很多加载时间。因为转换图像并将其存储在主队列中。

另一种方法是存储 URL 并在 tableview 显示上访问 URL。可以在 imageview 中应用异步加载。

于 2016-07-08T20:03:24.190 回答
2

看起来这里的问题是您的帖子永远不会获取照片信息,因为这些照片是异步下载的。

使用伪代码,你正在做的是:

Get information from database
  Create post object
    Begin downloading post photo
      Populate post object with post photo
    Begin downloading user photo
      Populate post object with user photo
  Return post object

发生的事情是在照片下载之前返回 post 对象(因为dataWithMaxSize:completion:调用是异步的)。你最终需要做的事情看起来更像:

Get information from database
  Create post object
    Begin downloading post photo, etc.
      Begin downloading user photo, etc.
        Return post object, now that it's fully populated

这是一种通常被称为“回调地狱”的范例,因为您将异步代码嵌套得很深,并且它变得更难阅读和调试。JavaScript 发明了 Promises 来解决这个问题,但不幸的是 Swift 没有对类似的东西提供一流的支持(guard尽管这是朝着这个方向迈出的一个很好的举措)。有像Bolts这样的库使用看起来更同步的异步框架,但同样,代码变得更复杂了。

您可以做一些事情(添加信号量/互斥体并在创建对象之前等待下载完成),但这些都是非常高级的概念,在尝试这些之前我会掌握同步/异步编程。

于 2016-06-20T18:20:50.347 回答
1

删除这两行:

userPhoto = data["userPhoto"] as? UIImage
postPhoto = data["postPhoto"] as? UIImage

更新此代码:

FIRStorage.storage().referenceForURL(url).dataWithMaxSize(10 * 1024 * 1024, completion: { (data, error) in
     dispatch_async(dispatch_get_main_queue()) {
            myPost.postPhoto = UIImage(data: data!)
            self.tableView.reloadData()
     }

                                })
FIRStorage.storage().referenceForURL(userPhotoUrl).dataWithMaxSize(10 * 1024 * 1024, completion: { (data, error) in
     dispatch_async(dispatch_get_main_queue()) {
            myPost.userPhoto = UIImage(data: data!)
            self.tableView.reloadData()
            }
     })
于 2016-07-05T14:35:23.313 回答