按时间戳对多个表视图单元格类型进行排序



>我想做的:从最新到最旧的顺序排列我所有的TableViewCells。

我的问题是什么:我可以按时间从同一类型订购单元格,尽管我无法通过一个公共值(时间(在同一部分中对它们进行排序。

这是我的代码:

import UIKit
import Firebase
class popularViewController: UIViewController, UITableViewDelegate, UITableViewDataSource{
@IBOutlet var table: UITableView!
//    var models = [PhotoPost]()
var texttt = [TextPost]()
var phots = [PhotoPost]()
var mixed = [MixedPhoto]()
var switchy = [Any]()
override func viewDidLoad() {
super.viewDidLoad()
gettingPosts()
table.register(popularTableViewCell.nib(), forCellReuseIdentifier: popularTableViewCell.identifier)
table.register(featuredTableViewCell.nib(), forCellReuseIdentifier: featuredTableViewCell.identifier)
table.register(textTableViewCell.nib(), forCellReuseIdentifier: textTableViewCell.identifier)
table.register(mixedTableViewCell.nib(), forCellReuseIdentifier: mixedTableViewCell.identifier)
table.delegate = self
table.dataSource = self
self.table.estimatedRowHeight = 225
self.table.rowHeight = UITableView.automaticDimension
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(true)
}
func numberOfSections(in tableView: UITableView) -> Int {
return 3
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if section == 0{
return mixed.count
}
else if section == 1{
return phots.count
}
else{
return texttt.count
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.section == 0{
let cell = tableView.dequeueReusableCell(withIdentifier: mixedTableViewCell.identifier, for: indexPath) as! mixedTableViewCell
cell.configure(with: self.mixed[indexPath.row])
return cell
}
else if indexPath.section == 1{
let cell = tableView.dequeueReusableCell(withIdentifier: popularTableViewCell.identifier, for: indexPath) as! popularTableViewCell
cell.configure(with: self.phots[indexPath.row])
return cell
}
else{
let cell = tableView.dequeueReusableCell(withIdentifier: textTableViewCell.identifier, for: indexPath) as! textTableViewCell
cell.configure(with: self.texttt[indexPath.row])
return cell
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "commentsVC")
vc.modalPresentationStyle = .fullScreen
self.navigationController?.pushViewController(vc, animated: true)
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
func gettingPosts(){
let db = Firestore.firestore()
let postsRef = db.collection("posts")
postsRef.addSnapshotListener { (querySnapshot, error) in
guard let snapshot = querySnapshot else {
print("Error fetching snapshots: (error!)")
return
}
snapshot.documentChanges.forEach { diff in
if (diff.type == .added){
let data = diff.document.data()
let Name = data["username"] as! String
let text = data["description"]
let likes = data["likes"] as! Int
let typ = data["postType"] as! Int
let pfp = data["profileImage"] as! String
let uid = data["uid"] as! String
let pic = data["picture"]
let time = data["time"] as! String
let pid = data["postID"] as! String
if typ == 0{                                                // Text post
let dasDing = TextPost(numberOfComments: 0, username: Name, timestampName: time, userImageName: pfp, textName: text as! String, postID: pid)
self.texttt.append(dasDing)
self.texttt.sort(by: { $0.timestampName > $1.timestampName })
}
if typ == 1{                                                // Text + Picture post
let Mixed = MixedPhoto(numberOfComments: 0, username: Name, timestampName: time, userImageName: pfp, textName: text as! String, postImageName: pic as! String, postID: pid)
self.mixed.append(Mixed)
self.mixed.sort(by: { $0.timestampName > $1.timestampName })
}
if typ == 2{                                                // Picture Post
let Foto = PhotoPost(numberOfComments: 0, username: Name, timestampName: time, userImageName: pfp, postImageName: pic as! String, postID: pid)
self.phots.append(Foto)
self.phots.sort(by: { $0.timestampName > $1.timestampName })
}
if typ == 3{                                                // Text + Video Post
}
if typ == 4{                                                // Video  Post
}
}
}
self.table.reloadData()
}
}
}
struct PhotoPost {
let numberOfComments: Int
let username: String
let timestampName: String
let userImageName: String
let postImageName: String
let postID: String
}
struct TextPost {
let numberOfComments: Int
let username: String
let timestampName: String
let userImageName: String
let textName: String
let postID: String
}
struct MixedPhoto {
let numberOfComments: Int
let username: String
let timestampName: String
let userImageName: String
let textName: String
let postImageName: String
let postID: String
}

注意现在,我在其自己的部分中订购了每种单元格类型,以便能够显示所有单元格类型,但这对我来说不是长期解决方案。我想把它们都放在一个部分。

这是另一种解决方案:

读完保罗和里克的回答后,我想到了另一个解决方案。

您可以按如下方式定义一个 Post 模型:

struct Post {
let numberOfComments: Int
let username: String
let timestampName: String
let userImageName: String
let postImageName: String?
let textName: String?
let postID: String
}

请注意,postImageName 和 textName 都是可选的。这将帮助您区分帖子类型。

接下来,您要声明一个 [Post] 类型的变量 allPosts:

var allPosts = [Post]()

您需要将其馈送到您的表视图:

func numberOfSections(in tableView: UITableView) -> Int {
return 1 // You only need one section. You can't omit this function btw.
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return allPosts.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let post = allPosts[indexPath.row]
if post.postImageName != nil && post.textName != nil {
let cell = tableView.dequeueReusableCell(withIdentifier: mixedTableViewCell.identifier, for: indexPath) as! mixedTableViewCell
cell.configure(with: post)
return cell
}
else if post.postImageName != nil {
let cell = tableView.dequeueReusableCell(withIdentifier: popularTableViewCell.identifier, for: indexPath) as! popularTableViewCell
cell.configure(with: post)
return cell
}
else if post.textName != nil {
let cell = tableView.dequeueReusableCell(withIdentifier: textTableViewCell.identifier, for: indexPath) as! textTableViewCell
cell.configure(with: post)
return cell
}
return UITableViewCell() // default: return empty cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "commentsVC")
vc.modalPresentationStyle = .fullScreen
self.navigationController?.pushViewController(vc, animated: true)
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}

最后,在 gettingPosts 函数中,您可以将每个项目分配给 allPosts,在重新加载 tableView 之前,您可以按时间戳对 allPosts 进行排序(并且不要忘记从主线程调用 reloadData(:

self.allPosts.sort(by: { $0.timestampName > $1.timestampName })
DispatchQueue.main.async {
self.tableView.reloadData()
}

编辑:在gettingPosts函数中,您需要将值提供给Post结构,而不是以前的模型。

let post = Post(numberOfComments: 0, username: Name, timestampName: time, userImageName: pfp, textName: text as? String, postImageName: pic as? String, postID: pid)
self.allPosts.append(dasDing)

还有一句话:必须有更好的方法来做到这一点。为什么不解码你的 JSON 呢?如果您有几种类型的帖子,这可能会变得混乱。如果您发布JSON结构,也许我们可以帮助您找到更好的解决方案。

你可以这样做,但你必须声明一个数组 allPosts 的类型为 Any:

var allPosts = [Any]()

您需要将其馈送到您的表视图:

func numberOfSections(in tableView: UITableView) -> Int {
return 1 // You only need one section. You can't omit this function btw.
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return allPosts.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let mixedPhoto = allPosts[indexPath.row] as? MixedPhoto {
let cell = tableView.dequeueReusableCell(withIdentifier: mixedTableViewCell.identifier, for: indexPath) as! mixedTableViewCell
cell.configure(with: mixedPhoto)
return cell
}
else if let photoPost = allPosts[indexPath.row] as? PhotoPost {
let cell = tableView.dequeueReusableCell(withIdentifier: popularTableViewCell.identifier, for: indexPath) as! popularTableViewCell
cell.configure(with: photoPost)
return cell
}
else if let textPost = allPosts[indexPath.row] as? TextPost {
let cell = tableView.dequeueReusableCell(withIdentifier: textTableViewCell.identifier, for: indexPath) as! textTableViewCell
cell.configure(with: textPost)
return cell
}
return UITableViewCell() // default: return empty cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "commentsVC")
vc.modalPresentationStyle = .fullScreen
self.navigationController?.pushViewController(vc, animated: true)
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}

最后,在 gettingPosts 函数中,您可以将每个项目分配给 allPosts,因为它的类型为 any,在重新加载 tableView 之前,您可以按时间戳对 allPosts 进行排序(并且不要忘记从主线程调用 reloadData(:

self.allPosts.sort(by: { $0.timestampName > $1.timestampName })
DispatchQueue.main.async {
self.tableView.reloadData()
}

您维护了三个不同的列表。要订购所有这些,您必须将它们组合在一个列表中。现在,您的所有模型都具有大部分通用数据。您可以将它们组合成一个协议,并让所有后续模型符合该协议。像这样:

protocol Post{
var numberOfComments: Int { get set }
var username: String {get set}
var timestampName: String {get set}
var userImageName: String {get set}
}
struct PhotoPost : Post{
var numberOfComments: Int
var username: String
var timestampName: String
var userImageName: String
let postImageName: String
let postID: String
}
struct TextPost : Post { ... }
struct MixedPhoto : Post { ... }

在你的UIViewController里,你应该有一个列表。

var oneListToRuleThemAll = [Post]()

func gettingPosts(){
snapshot.documentChanges.forEach{
//blah blah blah
oneListToRuleThemAll.append(PhotoPost(...))
}                   
//sort by timestamp and reload the table!
}

或者正如保罗在他的评论中建议的那样,你也可以走类(继承(路线!为了避免在每个子类中再次编写变量(但是您不能使用它的结构,并且必须将所有内容更改为类(。

最新更新