Новый Firebase извлекает данные и помещает в tableView (Swift)

Я сделал простую социальную сеть с новой Firebase и успешно сохранил строку с базой данных и изображение с хранилищем, но когда дело доходит до извлечения данных обратно в таблицу, наблюдаются необычные вещи!

все изображения возвращаются в случайном порядке и постоянно сдвигаются, но другая часть отображается идеально или когда я использую return posts.count tableView не показывает сообщение.

Надеюсь, что кто-то может дать мне предложение

    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()

}


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 {
    // #warning Incomplete implementation, return the number of rows
    return posts.count

}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cellIdentifier = "postCell"
    let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath)as! timelineTableViewCell

    let userPostRef = self.databaseRef.child("posts")
    userPostRef.observeEventType(.ChildAdded, withBlock: {(snapshot) in
        if let postAdd  = snapshot.value as? NSDictionary{
            let myPost = Post(data: postAdd)
            self.posts.insert(myPost, atIndex:0)

            cell.usernameLabel.text = self.posts[indexPath.row].username
            cell.postText.text = self.posts[indexPath.row].postText
            cell.timeLabel.text = self.posts[indexPath.row].time
            let url = snapshot.value?["postPhoto"] as! String
            let userPhotoUrl = snapshot.value?["userPhoto"] as! String

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

                })




        })
        }
    })

        return cell
    }

    }
 Xcodian Solangi01 мар. 2017 г., 08:56
Вы хотели бы обновить вопрос со структурами или tableviewcell или чем-то дополнительным к этому проекту? и не могли бы вы сделать снимок экрана контроллера вид

Ответы на вопрос(2)

Решение Вопроса

Здесь лучше всего заполнить свой источник данных tableView (массив posts) в вашем методе ViewDidLoad. Тогда ваш tableView не пытается сбросить данные, так как он обновляется.

Кроме того, поскольку вы добавляете наблюдателя .childAdded, ваше приложение будет уведомлено о любых добавлениях в firebase, поэтому, когда это произойдет, просто добавьте новые данные в массив posts и обновите tableView.

Нет причин постоянно извлекать данные из Firebase, поскольку они статичны до тех пор, пока они не изменятся. Поэтому загрузите один раз, а затем дождитесь этих изменений - вы можете рассмотреть возможность добавления (и удаления) события .childChanged на случай, если кто-то обновит их рис, например.

Firechat Приложение от Firebase является отличным ресурсом для понимания лучшего способа сделать это - если вы будете следовать этому шаблону проектирования, вы сможете избежать всех проблем с сетью и не беспокоиться о отдельных асинхронных вызовах.

Вы можете просто положиться на Firebase, чтобы позаботиться о себе.

Редактировать ... Ну, хотя это ссылка Firechat, кажется, что код Obj-C отсутствует (спасибо Firebase. Тьфу)

Итак, в свете этого, смотрите мой ответэтот вопрос поскольку у него есть шаблон для кода, который вам нужен.

 Johnny Hsieh18 июн. 2016 г., 17:12
@PaulBeusterien спасибо, я уже закончил этот проект, в этом уроке все еще есть какая-то ошибка в swift. И я не могу полностью понять все это. Я буду продолжать узнавать об этом. Спасибо за ваш ответ.
 Johnny Hsieh18 июн. 2016 г., 17:04
Спасибо! @ Джей, ты такой добрый! Спасибо за четкие инструкции, я знаю, где и как это исправить. Ура ответ, сделайте мне большую помощь!
 Paul Beusterien18 июн. 2016 г., 16:12
github.com/firebase/friendlychat включает в себя реализации Swift и Obj-C
 Johnny Hsieh21 июн. 2016 г., 05:09
Привет @Jay после исправления кода, все posts.cout и текст постов могут быть расположены и отображаться отлично. Но теперь я столкнулся с проблемой отправки. Объект post возвращается до того, как я смогу полностью загрузить фотографии из firebase. И я также отправляю отдельный вопрос с кодом обновления здесьstackoverflow.com/questions/37913871/... Извините за то, что задали так много вопросов, но, похоже, это из-за моих возможностей.
 Johnny Hsieh18 июн. 2016 г., 16:42
благодарю вас! Я по-прежнему быстрый новичок, метод сортировки действительно мне очень помогает, но я все еще не могу решить проблему с изображением и posts.count в tableView numberOfRowsInSection не может показать ни одного поста в tableView, у вас есть подсказка, спасибо вам, ребята ! Спасибо за ответ!
 Jay18 июн. 2016 г., 16:51
@JohnnyHsieh Метод сортировки в моем ответе был только половиной ответа. Вам нужно будет переместить ваш код Firebase в метод viewDidLoad, а затем изменить его, чтобы он больше походил на код в моем примере, чтобы сначала загрузить данные, а затем наблюдать их за будущими изменениями. Как только это будет сделано, ваш массив будет заполнен, и ваш tableView cellForRowAtIndexPath может заполнить ячейку из массива. Сделайте эти изменения и, по крайней мере, загрузите массив. Если у вас есть другая проблема, опубликуйте отдельный вопрос с обновленным кодом.

Вы испытываете проблемы с потоками.

Из яблочных документов:

Потоки и ваш пользовательский интерфейс Если ваше приложение имеет графический пользовательский интерфейс, рекомендуется, чтобы вы получали связанные с пользователем события и инициировали обновления интерфейса из основного потока вашего приложения. Такой подход помогает избежать проблем синхронизации, связанных с обработкой пользовательских событий и содержимым окна рисования. Некоторые платформы, такие как Какао, обычно требуют такого поведения, но даже для тех, которые этого не делают, сохранение этого поведения в основном потоке имеет преимущество, заключающееся в упрощении логики управления вашим пользовательским интерфейсом.

В вашем коде вы извлекаете данные асинхронно, что может привести к их извлечению из потока, отличного от основного потока, чтобы избежать этого, вы можете обернуть код, в котором вы установили свой интерфейс, вdispatch_async блок так:

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cellIdentifier = "postCell"
let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath)as! timelineTableViewCell

let userPostRef = self.databaseRef.child("posts")
userPostRef.observeEventType(.ChildAdded, withBlock: {(snapshot) in
    if let postAdd  = snapshot.value as? NSDictionary{
        let myPost = Post(data: postAdd)
        self.posts.insert(myPost, atIndex:0)

          //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

        }
          let url = snapshot.value?["postPhoto"] as! String
          let userPhotoUrl = snapshot.value?["userPhoto"] as! String
        FIRStorage.storage().referenceForURL(url).dataWithMaxSize(10 * 1024 * 1024, completion: { (data, error) in
             dispatch_async(dispatch_get_main_queue()){
            let postPhoto = UIImage(data: data!)
            cell.postPhoto.image = postPhoto
           }
             FIRStorage.storage().referenceForURL(userPhotoUrl).dataWithMaxSize(10 * 1024 * 1024, completion: { (data, error) in
            //Dispatch the main thread here
            dispatch_async(dispatch_get_main_queue()) {
                let userPhoto = UIImage(data: data!)
                cell.userPhoto.image = userPhoto
          }

        })
      })
    }
  })
    return cell
}

Обратите внимание, что смешивать ваш сетевой код и код пользовательского интерфейса, как это, не обязательно лучше всего. То, что вы могли бы сделать, это иметь функцию, которая загружает / отслеживает вашу конечную точку, а затем добавляет ее в массив, затем вызываетtableView.reloadData() и обновить взгляды.

Если вы хотите узнать немного больше о потоках и GCD, посмотрите на этоСессия WWDC

 Mike McDonald20 июн. 2016 г., 20:02
Как к сведению, все обратные вызовы возникают в основном потоке, если вы не укажете альтернативу черезFIRStorage.storage().setCallbackQueue() (firebase.google.com/docs/reference/ios/firebasestorage/...) Вероятно, проблема в том, что ячейка возвращается до завершения загрузки фотографии и поэтому не отображается.
 Chris21 июн. 2016 г., 17:44
@JohnnyHsieh содержит ли ваш текущий вопрос весь код, связанный с вашей проблемой (включая код ячейки tableView)? Если нет, не могли бы вы опубликовать это, и я посмотрю
 Johnny Hsieh21 июн. 2016 г., 20:21
Спасибо за ваш любезный ответ @Chris, вот мой код обновленияstackoverflow.com/questions/37913871/...
 Johnny Hsieh21 июн. 2016 г., 11:23
@Chris Я обновил свой код, чтобы переместить код firebase в viewDidLoad, текстовые части поста являются текущими, но все еще не могут вернуть фотографию, я использую асинхронный метод отправки, но все еще напрасно, я теперь предполагаю, что возвращение ячейки раньше изображения полностью загружены. Как мне решить эту проблему?
 Chris18 июн. 2016 г., 18:45
Нет проблем @JohnnyHsieh, рад, что это помогло
 Johnny Hsieh18 июн. 2016 г., 16:59
спасибо за вашу любезную инструкцию, я понимаю, что я проигнорировал проблему потока. Я новичок, только самообучающийся быстро в течение трех месяцев. Так что я, возможно, не очень знаком с этим правилом. Цените! Я хочу узнать больше об этом! Обязательно изучите сессию WWDC.

Ваш ответ на вопрос