简体   繁体   中英

How to store the parsed data in the array?

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM