I have a database on Firebase. I parse some data that I want to store in the array of structures:
postData.swift
struct postData {
let Title: String
let Subtitle: String
let imgURL: String
let Date: String
init(Title: String, Subtitle: String, imgURL: String, Date: String) {
self.Title = Title
self.Subtitle = Subtitle
self.imgURL = imgURL
self.Date = Date
}
}
This array will be used for creating a collectionViewCells inside a tableViewCells . Inside my ViewController I created a global array var dataPosts:[postData] = []
where I will store parsed data. Here is a function I made:
var dataPosts:[postData] = []
...
override func viewDidLoad() {
super.viewDidLoad()
tableView = UITableView(frame: self.view.bounds, style: .grouped)
tableView.delegate = self
tableView.dataSource = self
...
tableView.register(PostCell.self, forCellReuseIdentifier: PostTableID)
parsePosts()
print(dataPosts.count) // prints 0
}
func parsePosts() {
let databaseRef = Database.database().reference(withPath: "Посты")
var data:[postData]
databaseRef.observeSingleEvent(of: .value) { (snapshot) in
for child in snapshot.children {
let snap = child as! DataSnapshot
let res = snap.value as! [String: Any]
let title = res["Заголовок"] as! String
let subtitle = res["Подзаголовок"] as! String
let img = res["URL"] as! String
let date = res["Дата"] as! String
self.dataPosts.append(postData(Title: title, Subtitle: subtitle, imgURL: img, Date: date))
print(self.dataPosts.count, " - inside cycle") // prints 1
}
}
data = dataPosts
print(data.count, " - inside function") // prints 0
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dataPosts.count
}
Is there any way to store it in the array? Or I should use something from OOP (I'm a beginner)? Thanks
First of all please name structs with starting uppercase letter and variables with starting lowercase letter. The init
method is not needed
struct PostData {
let title: String
let subtitle: String
let imgURL: String
let date: String
}
and
var dataPosts : [PostData] = []
Actually you have only to reload the table view after the loop inside the closure which receives the data asynchronously. The temporary array data
is not needed.
func parsePosts() {
let databaseRef = Database.database().reference(withPath: "Посты")
databaseRef.observeSingleEvent(of: .value) { (snapshot) in
for child in snapshot.children {
let snap = child as! DataSnapshot
let res = snap.value as! [String: Any]
let title = res["Заголовок"] as! String
let subtitle = res["Подзаголовок"] as! String
let img = res["URL"] as! String
let date = res["Дата"] as! String
self.dataPosts.append(PostData(title: title, subtitle: subtitle, imgURL: img, date: date))
print(self.dataPosts.count, " - inside cycle") // prints 1
}
self.tableView.reloadData()
}
}
And delete
print(dataPosts.count) // prints 0
in viewDidLoad
, it's useless.
This is only a suggestion, instead of creating a struct
create a NSObject
class instead:
import UIKit
class PostData: NSObject {
@objc var title: String?
@objc var subtitle: String?
@objc var imgUrl: String?
@objc var date: String?
init(dictionary: [String: AnyObject]) {
self.title = dictionary["title"] as? String
self.subtitle = dictionary["subtitle"] as? String
self.imgUrl = dictionary["imgUrl"] as? String
self.date = dictionary["date"] as? String
}
}
Make sure that the dictionary values such as the title, subtitle, etc. match with your firebase database values names. I think that yours may be:
init(dictionary: [String: AnyObject]) {
self.title = dictionary["Заголовок"] as? String
self.subtitle = dictionary["Подзаголовок"] as? String
self.imgUrl = dictionary["URL"] as? String
self.date = dictionary["Дата"] as? String
}
This way now when reading data you can initialize a PostData object with the dictionary from snapshot and append it to your array (If using it).
EXAMPLE:
// Here you had already observed a single event
if let postDict = snapshot.value as? [String: AnyObject] {
let postData = PostData(dictionary: postDict)
// append to array if needed
self.postsData.append(newElement: postData)
}
REMEMBER that with your object we are working with optionals values, that means that you may need to use guard let
or if let
statements to make sure this properties are not nil (this may not be the case if this are correctly parsed with your firebase database).
EXAMPLE:
// Let's suppose that you need to access to the "title" property
// This dictionary is a hardcoded dictionary, yours may be downloaded from your database
let dictionary: [String: AnyObject] = [
"title": "a title" as AnyObject,
"subtitle": "a subtitle" as AnyObject,
"imgUrl": "an imgUrl" as AnyObject,
"date": "a date" as AnyObject
]
let postData = PostData(dictionary: dictionary)
// THIS IS THE INCORRECT WAY
let postTitle = postData.title
print(postTitle!) /* The print statement does not require a non-optional value, but may print something like: Optional("a title"), in your case you may want a non-optional value */
// THIS IS THE CORRECT WAY
if let postTitle = postData.title {
print(postTitle) // Prints: "a title"
}
// ALTERNATIVE TO CORRECT WAY
guard let postTitle = postData.title else { return }
print(postTitle) // Prints: "a title"
This may helps you to write less lines of code and make it simple to understand.
COMPLETE EXAMPLE:
var postsDataArray = [PostData]()
func parsePosts() {
let databaseRef = Database.database().reference(withPath: "Посты")
databaseRef.observeSingleEvent(of: .value) { (snapshot) in
if let postDict = snapshot.value as? [String: AnyObject] {
let postData = PostData(dictionary: postDict)
self.postsDataArray.append(newElement: postData)
}
self.tableView.reloadData()
}
}
This last example is using PostData as a NSObject
class as I showed you on the example above.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.