Creating an array out of Firebase Dictionary - arrays

I am trying to retrieve a dictionary from Firebase and extract each value from the dictionary and append it to an empty array, but my code doesn't work. I haven't even added the code for appending it to an array and when I run it, "error" is printed in the console.
This is what it looks like inside Firebase
And this is what my code looks like:
func convertAllMosaicsToArray() {
// retrieve and convert here
Database.database().reference().child("mosiacTitles").observe(.value, with: { (snapshot) in
if let dictionary = snapshot.value as? [Int : AnyObject] {
print(dictionary)
} else {
print("error")
}
})
}

static func load(_ completion: #escaping () -> ()) {
if let user = Auth.auth().currentUser {
let ref = Database.database().reference().child("users").child(user.uid).child("something")
ref.observe(.value, with: { (snapshot) in
if let data = snapshot.value as? [String : AnyObject] {
var arrayNeeded: [Int] = []
if let array = data["key"] as? [Int] {
arrayNeeded = array
}
}
completion()
})
}
}

The problem was using the if let statement to cast it as a [Int : AnyObject], it just needed to be changed to an [String]
Like this:
func retrieveMosaicTitles() {
// retrieve and convert here
Database.database().reference().child("mosaicTitles").observe(.value, with: { (snapshot) in
if let allMosaicTitles = snapshot.value as? [String] {
self.searchResultsVC.listOfMosaics = allMosaicTitles
} else {
print("error")
}
})
}

Related

array return empty when call it out of own method

i am making a url call with alamofire to GET data as below . when i print variables inside the call method its show correctly but when i call that out side the method , like View dIdLoad or some where there no value inside array and print empty [ ] .
class ChartVC: UIViewController {
var _year : [String] = []
var _month : [String] = []
var _price : [String] = []
override func viewDidLoad() {
super.viewDidLoad()
getData()
// show empty array
print(_month)
}
func getData() {
AF.request(DOLLAR_CHART).response { (response) in
guard let data = response.data else { return }
let responseJSON = try? JSONSerialization.jsonObject(with: data, options: [])
if let items = responseJSON as? [[String: Any]] {
var years: [String] = []
var months: [String] = []
var prices: [String] = []
for item in items {
if let year = item["year"] as? String {
years.append(year)
}
if let month = item["month"] as? String {
months.append(month)
}
if let price = item["price"] as? String{
prices.append(price)
}
}
self._year = years
self._month = months
self._price = prices
//print correctly
print(_months)
} else {
print("json is not array dictionary")
}
}
}
You are adding data after the network calls completed. It will print data everytime once your call is completed. At the time of did load the initial data (which is empty intialization in your case) will be printed.
If you want to do any UI updates then do updtae after your call is completed.
This is because the request takes a while to receive the answer, and your print(_month) in the viewDidLoad() method is executed before the answer from the service.
You need to wait for the service to return, parse the response and only then use the data.
A good approach would be this:
self._year = years
self._month = months
self._price = prices
//print correctly
self.updateUI()
func updateUI() {
//Use response
}
EDIT - Full code
class ChartVC: UIViewController {
var _year : [String] = []
var _month : [String] = []
var _price : [String] = []
override func viewDidLoad() {
super.viewDidLoad()
getData()
}
func getData() {
AF.request(DOLLAR_CHART).response { (response) in
guard let data = response.data else { return }
let responseJSON = try? JSONSerialization.jsonObject(with: data, options: [])
if let items = responseJSON as? [[String: Any]] {
var years: [String] = []
var months: [String] = []
var prices: [String] = []
for item in items {
if let year = item["year"] as? String {
years.append(year)
}
if let month = item["month"] as? String {
months.append(month)
}
if let price = item["price"] as? String{
prices.append(price)
}
}
self._year = years
self._month = months
self._price = prices
self.updateUI()
} else {
print("json is not array dictionary")
}
}
}
func updateUI() {
//USE THE RESPONSE AND UPDATE THE UI HERE
}

Implementing comments on feed post in swift using firebase

I am trying to implement a comment section on each feed post in my app using swift and firebase, but am having trouble with the code that will get the comments. In my function it is returning a empty array of messageComments but I do not know what I am doing wrong. If I want my firebase database structure to look like that in the picture how can I implement the code that will download those comments in an array?
func getFeedMessages(handler: #escaping (_ feedMessages:[FeedMessages]) -> ()){
var feedMessagesArray = [FeedMessages]()
var commentArray = [messageComments]()
REF_FEEDMESSAGES.observeSingleEvent(of: .value) { (feedMessagesSnapshot) in
guard let feedMessagesSnapshot = feedMessagesSnapshot.children.allObjects as? [DataSnapshot] else {return}
for messages in feedMessagesSnapshot {
let content = messages.childSnapshot(forPath: "content").value as? String ?? "Joe Flacco is an elite QB"
let icon = messages.childSnapshot(forPath: "icon").value as? String ?? "none"
let color = messages.childSnapshot(forPath: "color").value as? String ?? "bop"
self.REF_FEEDCOMMENTS.observeSingleEvent(of: .value, with: { (feedCommentsSnapshot) in
guard let feedCommentsSnapshot = feedCommentsSnapshot.children.allObjects as? [DataSnapshot] else {return}
for comments in feedCommentsSnapshot {
commentArray.append((comments.childSnapshot(forPath: "comments").value as? messageComments!)!)
}
})
print(" comment: ")
print(commentArray)
let messages = FeedMessages(content: content, color: color, icon: icon, comments: commentArray)
feedMessagesArray.append(messages)
}
handler(feedMessagesArray)
}
}
If you also have the same data structure, there would be no need for another request for the comments since they are nested in the feed messages. This will only require some simple parsing, which can be made easier to read and understand with a few extensions.
extension DataSnapshot {
var string: String? {
return value as? String
}
var childSnapshots: [DataSnapshot] {
return children.allObjects as? [DataSnapshot] ?? []
}
func child(_ path: String) -> DataSnapshot {
return childSnapshot(forPath: path)
}
}
These two extensions take care of the snapshot operations needed to initialize the objects.
extension MessageComments {
convenience init(snapshot: DataSnapshot) {
self.comments = snapshot.childSnapshots.map { $0.string }
}
}
extension FeedMessages {
convenience init(snapshot: DataSnapshot) {
self.color = snapshot.child("color").string ?? "bop",
self.comments = MessageComments(snapshot: snapshot.child("comments"))
self.content = snapshot.child("content").string ?? "Joe Flacco is an elite QB",
self.icon = snapshot.child("icon").string ?? "none",
}
}
Just map the children snapshots to initialize each of them as a FeedMessages object.
func getFeedMessages(handler: #escaping (_ feedMessages: [FeedMessages]) -> ()) {
REF_FEEDMESSAGES.observeSingleEvent(of: .value) {
handler($0.childSnapshots.map { FeedMessages(snapshot: $0) })
}
}

Json data - white console - Xcode 9

I am trying a simple app in which I want to convert some values. It worked until I tried to convert the data in a dictionary, and when I hit run, it builds successfully, but the console does not print anything. Here is the code:
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let url = URL(string: "http://gnb.dev.airtouchmedia.com/rates.json")
let task = URLSession.shared.dataTask(with: url!) { (data, response, error) in
if error != nil
{
print("ERROR")
}
else {
if let content = data {
do {
//Array
let myJson = try JSONSerialization.jsonObject(with:content, options: JSONSerialization.ReadingOptions.mutableContainers) as AnyObject
//print(myJson)
if let rate = myJson["rate"] as? NSDictionary {
if let currency = rate["AUD"] {
print(currency)
}
}
}
catch {
}
}
}
}
task.resume()
}
because you are parsing JSON wrongly
try this
let myJson = try JSONSerialization.jsonObject(with:content, options: JSONSerialization.ReadingOptions.mutableContainers) as? [[String: AnyObject]] else { return }
for rate in myJson
guard let cur = user["from"] as? String,
let curRate = user["rate"] as? Double else { break }
if let cur = "AUD" {
print(curRate)
}
Update:
You are receiving Array of Objects in response,
so first you have to treat it as Array of object,
Then you have to loop through this objects and then inside that loop you have to extract the data you were looking for and play with it.

Read array from firebase once and put it into an array

How to read firebase array and put it into swift array? I'm trying to solve this problem for like 4 hours. What am I doing wrong?
ref.child("names").child("myNames").observe(.value) { (snapshot) in
if let item = snapshot.value as? String {
namesArray.append(item)
}
}
You should parse the snapshot as [String : Any]? and fetch the values in the dictionary.
ref.child("names").child("myNames").observe(.value) { (snapshot) in
if let itemDictionary = snapshot.value as? [String : Any] {
for (key, value) in itemDictionary {
// Another check for String
if let valueString = value as? String {
namesArray.append(valueString)
}
}
}
}
You are trying to unwrap an array of String as a single String, so that is why it's failing. Change to the following:
ref.child("names").child("myNames").observe(.value) { (snapshot) in
if let item = snapshot.value as? [String] {
namesArray = item
}
}

Working With Json in swift 3

I want to get long_name from this JSON file I can just access 'results' with this code:
let url = URL(string: "https://maps.googleapis.com/maps/api/geocode/json?latlng=35.7229513,51.3566039&language=fa&key=AIzaSyBXOPT1jEYizWZHOKLwv4dhacgYTcmn3I4")!
let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
if error != nil {
print(error!)
}
else{
if let urlcontent = data {
do{
let jsonResult = try JSONSerialization.jsonObject(with: urlcontent, options: JSONSerialization.ReadingOptions.mutableContainers) as! [String:Any]
print(jsonResult["results"]!)
if let jsonResult = jsonResult["results"] as? [String: Any] {
if let address_components = jsonResult["address_components"] as? [String: Any] {
print(address_components)
if let long_name = address_components["long_name"] as? [String: Any] {
print(long_name)
}
}
}
}
catch{
print("json failed")
}
}
}
}
task.resume()
But I'm just getting result this is my JSON file:
https://maps.googleapis.com/maps/api/geocode/json?latlng=35.7339859%2C51.3393980&sensor=true_or_false&language=fa
Your result key contains Array as value not Dictionary so simply change [String:Any] to [[String:Any]] and then access address_components from the each dictionary objects of resultsArray, now address_components is also array of dictionary and long_name is inside that dictionary. So try like this.
if let resultsArray = jsonResult["results"] as? [[String: Any]] {
for dic in resultsArray {
if let addressArray = dic["address_components"] as? [[String:Any]] {
for address in addressArray {
if let longName = address["long_name"] as? String {
print(longName)
}
}
}
}
}

Resources