在UITableView中按时间顺序排序Firebase帖子(最新的第一个)

时间:2018-04-25 11:25:29

标签: arrays swift uitableview firebase firebase-realtime-database

我正在尝试,并且已经有一段时间了,我将帖子排序为Firebase中的最新帖子。我知道Firebase在使用childByAutoId()创建时会自动执行此操作,但我认为这可能是我将数据调用到UITableView中的方式。

以下是将数据加载到我的数组中的代码:

阵列:

var posts = [[String : AnyObject]]()

功能'loadData()':

let uid = Auth.auth().currentUser?.uid
    Database.database().reference().child("userinfo").child(uid!).observeSingleEvent(of: .value, with: { (snapshot) in
        let value = snapshot.value as? NSDictionary
        let userFilter = value?["discover_filter"] as! String

        if userFilter == "__" {
            Database.database().reference().child("posts").queryLimited(toLast: 50).observeSingleEvent(of: .value, with: { (snapshot) in

                self.posts.removeAll()

                if let postsDictionary = snapshot.value as? [String: AnyObject] {
                    for post in postsDictionary {
                        self.posts.append(post.value as! [String : AnyObject])

                    }
                    DispatchQueue.main.async {
                        self.postsTableView.reloadData()
                    }
                }
            })
        }else {
            Database.database().reference().child("posts").queryOrdered(byChild: "combinedstring").queryEqual(toValue: userFilter).queryLimited(toLast: 50).observeSingleEvent(of: .value, with: { (snapshot) in

                self.posts.removeAll()

                if let postsDictionary = snapshot.value as? [String: AnyObject] {
                    for post in postsDictionary {
                        self.posts.append(post.value as! [String : AnyObject])
                    }
                    DispatchQueue.main.async {
                        self.postsTableView.reloadData()
                    }
                }
            })
        }
    })

我自己试图解决这个问题,但是我无法解决这个问题,我尝试了很多不同的方法,但得出的结论是我只需要帮助 - 我很新,并且只是学习Swift的6个月了(我自己作为我学位项目的一部分)。

如果还有其他要求,请告诉我。

提前谢谢!

Firebase JSON结构:

"posts" : {
"-LAxSTwPhGO9NStRFGK3" : {
  "activity" : "lol",
  "combinedstring" : "League of Legends_PC_Beginner",
  "communication" : "Mic",
  "console" : "PC",
  "description" : "Description...",
  "game" : "League of Legends",
  "gameimage" : "League of Legends.jpg",
  "key" : "-LAxSTwPhGO9NStRFGK3",
  "lfglfm" : "Looking for Group",
  "skill" : "Beginner",
  "timestamp" : 1524670787479,
  "uid" : "TgtlcIcd29gN2GEHLOO1QvGhAQA2",
  "username" : "danielrjjones"
},
"-LAxSbp8ilXUVY7yFG_C" : {
  "activity" : "lol",
  "combinedstring" : "Fifa 17_Xbox One_Beginner",
  "communication" : "Mic",
  "console" : "Xbox One",
  "description" : "Description...",
  "game" : "Fifa 17",
  "gameimage" : "Fifa 17.jpg",
  "key" : "-LAxSbp8ilXUVY7yFG_C",
  "lfglfm" : "Looking for Members",
  "skill" : "Beginner",
  "timestamp" : 1524670823883,
  "uid" : "TgtlcIcd29gN2GEHLOO1QvGhAQA2",
  "username" : "danielrjjones"
}
}

用于创建帖子的代码:

import UIKit
import Firebase
import FirebaseDatabase

class CreatePostViewController: UIViewController, UITextFieldDelegate, UIPickerViewDataSource, UIPickerViewDelegate {

@IBOutlet weak var gameTextField: UITextField!
@IBOutlet weak var activityTextField: UITextField!
@IBOutlet weak var consoleTextField: UITextField!
@IBOutlet weak var skillTextField: UITextField!
@IBOutlet weak var communicationTextField: UITextField!
@IBOutlet weak var lfglfmTextField: UITextField!
@IBOutlet weak var rulesTextView: UITextView!
@IBOutlet weak var descriptionTextView: UITextView!
@IBOutlet weak var createButton: UIButton!

var gameValue = String()

var console = ["Select Console", "Nintendo DS", "Nintendo Switch", "PC", "PS Vita", "Playstation 3", "Playstation 4", "Xbox 360", "Xbox One"]
var skill = ["Select Playing Type", "Beginner", "Experienced", "Veteran", "Pro"]
var communication = ["Select Communication","Mic", "No Mic"]
var lfglfm = ["Select LFG/LFM", "Looking for Group", "Looking for Members"]

var itemSelected = ""
var gameimage = ""
var combinedString = ""

weak var pickerView: UIPickerView?
weak var textField: UITextField?

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view.

    //allow tap on screen to remove text field input from screen
    self.view.addGestureRecognizer(UITapGestureRecognizer(target: self.view, action: #selector(UIView.endEditing(_:))))

    //UIPICKER
    let pickerView = UIPickerView()
    pickerView.delegate = self
    pickerView.dataSource = self

    gameTextField.delegate = self
    consoleTextField.delegate = self
    skillTextField.delegate = self
    communicationTextField.delegate = self
    lfglfmTextField.delegate = self

    //set pickerview for other text fields
    pickerView.showsSelectionIndicator = true

    let toolBar = UIToolbar()
    toolBar.barStyle = UIBarStyle.default
    toolBar.isTranslucent = true
    toolBar.tintColor = UIColor(red:0.00, green:0.45, blue:1.00, alpha:1.0)
    toolBar.sizeToFit()

    let doneButton = UIBarButtonItem(title: "Done", style: UIBarButtonItemStyle.plain, target: self, action: #selector(CreatePostViewController.donePicker))
    let spaceButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.flexibleSpace, target: nil, action: nil)
    let cancelButton = UIBarButtonItem(title: "Cancel", style: UIBarButtonItemStyle.plain, target: self, action: #selector(CreatePostViewController.donePicker))

    toolBar.setItems([cancelButton, spaceButton, doneButton], animated: false)
    toolBar.isUserInteractionEnabled = true

    gameTextField.inputView = pickerView
    gameTextField.inputAccessoryView = toolBar
    consoleTextField.inputView = pickerView
    consoleTextField.inputAccessoryView = toolBar
    skillTextField.inputView = pickerView
    skillTextField.inputAccessoryView = toolBar
    communicationTextField.inputView = pickerView
    communicationTextField.inputAccessoryView = toolBar
    lfglfmTextField.inputView = pickerView
    lfglfmTextField.inputAccessoryView = toolBar

    // pickerview = pickerview
    self.pickerView = pickerView

    //extra styling
    let navImg = UIImage(named: "nav-bar")
    navigationController?.navigationBar.setBackgroundImage(navImg, for: .default)

    //createButton.colourBorder()

}

override func viewDidAppear(_ animated: Bool) {
    gameTextField.text = gameValue
    gameTextField.resignFirstResponder()
}

@objc func donePicker() {
    textField?.resignFirstResponder()
    self.view.endEditing(true)
}

//pickerview code
func textFieldDidBeginEditing(_ textField: UITextField) {
    if textField == gameTextField {
        return
    }else {
        self.pickerView?.reloadAllComponents()
    }
}

func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
    if consoleTextField.isFirstResponder{
        return console.count
    }else if skillTextField.isFirstResponder{
        return skill.count
    }else if communicationTextField.isFirstResponder{
        return communication.count
    }else if lfglfmTextField.isFirstResponder{
        return lfglfm.count
    }
    return 0
}

func numberOfComponents(in pickerView: UIPickerView) -> Int {
    return 1
}

func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
    if consoleTextField.isFirstResponder{
        return console[row]
    }else if skillTextField.isFirstResponder{
        return skill[row]
    }else if communicationTextField.isFirstResponder{
        return communication[row]
    }else if lfglfmTextField.isFirstResponder{
        return lfglfm[row]
    }
    return nil
}

func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
    if consoleTextField.isFirstResponder{
        let itemselected = console[row]
        consoleTextField.text = itemselected
    }else if skillTextField.isFirstResponder{
        let itemselected = skill[row]
        skillTextField.text = itemselected
    }else if communicationTextField.isFirstResponder{
        let itemselected = communication[row]
        communicationTextField.text = itemselected
    }else if lfglfmTextField.isFirstResponder{
        let itemselected = lfglfm[row]
        lfglfmTextField.text = itemselected
    }
}

@IBAction func createPostTapped(_ sender: UIButton) {

    if gameTextField.text == "" || consoleTextField.text == "" || skillTextField.text == "" || communicationTextField.text == "" || lfglfmTextField.text == "" {
        let alert = UIAlertController(title: "Oops...", message: "You must fill out all fields to create a post. Please try again!", preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
        self.present(alert, animated: true, completion: nil)
    } else if consoleTextField.text == "Select Console" || skillTextField.text == "Select Playing Type" || communicationTextField.text == "Select Communication" || lfglfmTextField.text == "Select LFG/LFM" {
        let alert = UIAlertController(title: "Oh no!", message: "Please select a value to create a post.", preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
        self.present(alert, animated: true, completion: nil)
    } else {

        if let uid = Auth.auth().currentUser?.uid {
            Database.database().reference().child("usernames").child(uid).observeSingleEvent(of: .value, with: {
                (snapshot) in
                if let userDictionary = snapshot.value as? [String: AnyObject] {
                    for user in userDictionary {
                        if let username = user.value as? String {
                            if let game = self.gameTextField.text {
                                if let activity = self.activityTextField.text {
                                    if let console = self.consoleTextField.text {
                                        if let skill = self.skillTextField.text {
                                            if let communication = self.communicationTextField.text {
                                                if let lfglfm = self.lfglfmTextField.text {
                                                    if let description = self.descriptionTextView.text {

                                                        let gameimage = "\(self.gameTextField.text!).jpg"
                                                        let combinedString = "\(self.gameTextField.text!)_\(self.consoleTextField.text as! String)_\(self.skillTextField.text as! String)"

                                                        let timeStamp = ServerValue.timestamp() as! [String:Any]

                                                        let refer = Database.database().reference().child("posts").childByAutoId()
                                                        let ref = refer.key

                                                        let postObject: Dictionary<String, Any> = [
                                                            "uid" : uid,
                                                            "username" : username,
                                                            "game" : game,
                                                            "activity" : activity,
                                                            "console" : console,
                                                            "skill" : skill,
                                                            "communication" : communication,
                                                            "lfglfm" : lfglfm,
                                                            "description" : description,
                                                            "gameimage" : gameimage,
                                                            "combinedstring" : combinedString,
                                                            "timestamp" : timeStamp,
                                                            "key" : ref,
                                                            ]

                                                        refer.setValue(postObject)

                                                        //Database.database().reference().child("posts").childByAutoId().setValue(postObject)

                                                        let alert = UIAlertController(title: "Success!", message: "Your post was added successfully.", preferredStyle: .alert)
                                                        alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { (action) in
                                                            //code will run when ok button is pressed
                                                            let vc = self.storyboard?.instantiateViewController(withIdentifier: "LoggedInVC")
                                                            self.present(vc!, animated: true, completion: nil)
                                                        }))
                                                        self.present(alert, animated: true, completion: nil)

                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            })
        }
    }
}
}

2 个答案:

答案 0 :(得分:0)

(根据对答案的评论)解决方案是为每个&#34; post&#34;添加类型编号的特定字段(例如,称为timestamp)并分配值创建时间戳的乘以-1

时间戳的建议值是纪元时间,请参阅Get Unix Epoch Time in Swift

然后根据此字段值对您进行排序,例如:

Database.database().reference().child("posts").queryOrdered(byChild: "timestamp")...

通过这种方式,最新的帖子将首先出现

答案 1 :(得分:0)

这应该有效:

Database.database().reference().child("posts").queryOrderedByKey().queryLimited(toLast: 50).observeSingleEvent(of: .value, with: { (snapshot: DataSnapshot) in
    self.posts.removeAll()
    for child in snapshot.children.allObjects as [DataSnapshot] {
        self.posts.append(child.value as? [String: AnyObject])
    }

    DispatchQueue.main.async {
        self.postsTableView.reloadData()
    }
})

的变化:

  1. 明确调用queryOrderedByKey()以明确我们希望按键排序结果。
  2. 在闭包中循环snapshot.children,因为过早转换为[String: AnyObject]会丢失订购信息。