I've been trying to retrieve some data from firebase and store it in arrays. But I've got a problem when I try to append the data.
I can store the data into arrays only in the closure and outside of the closure, i all the sudden lose all the values inside of the arrays. Why does this happen? Please help me to find what I'm missing...
var names = [String]()
var txts = [String]()
var imgUrls = [String]()
Database.database().reference().child("Posts").child("dummy").observe(.value) { (snapshot) in
guard let snapshots = snapshot.children.allObjects as? [DataSnapshot] else {
return
}
for snap in snapshots {
let autoId = snap.key as String
Database.database().reference().child("Posts").child("dummy").child(autoId).observe(.value, with: { (snapshot) in
guard let data = snapshot.value as? [String: Any] else {return}
//name
guard let name = data["name"] as? String else {return}
self.names.append(name)
//image
guard let imgUrl = data["image"] as? String else {return}
self.imgUrls.append(imgUrl)
//txt
guard let txt = data["text"] as? String else {return}
self.txts.append(txt)
print(self.names) //this returns all data from firebase
print(self.imgUrls) //this returns all data from firebase
print(self.txts) //this returns all data from firebase
}
print(self.names) //this returns empty array
print(self.imgUrls) //this returns empty array
print(self.txts) //this returns empty array
}
Could it be because you are assigning the data inside a closure which could happen in a later time. So basically the last print statement occurs before the closure statements.
I will recommend you use didSet to understand the sequence. For example:
var names: [String] = [String]() {
didSet {
print(names) // this is print each time the value is set
}
}
var txts: [String] = [String]() {
didSet {
print(txts)
}
}
var imgUrls: [String] = [String]() {
didSet {
print(imgUrls)
}
}
Database.database().reference().child("Posts").child("dummy").observe(.value) { (snapshot) in
guard let snapshots = snapshot.children.allObjects as? [DataSnapshot] else { return }
for snap in snapshots {
let autoId = snap.key as String
Database.database().reference().child("Posts").child("dummy").child(autoId).observe(.value, with: { (snapshot) in
guard let data = snapshot.value as? [String: Any] else {return}
//name
guard let name = data["name"] as? String else {return}
self.names.append(name)
//image
guard let imgUrl = data["image"] as? String else {return}
self.imgUrls.append(imgUrl)
//txt
guard let txt = data["text"] as? String else {return}
self.txts.append(txt)
}
}
Related
public func getAllItems(completion: #escaping (Result<[Item], Error>) -> Void)
{
database.child("Items").observe(.value, with: {snapshot in
guard (snapshot.value as? [[String: Any]]) == nil else{
completion(.failure(DatabaseError.failedToFetch))
return
}
var newUrlArray: [Item] = []
var newItemArray: [Item] = []
for child in snapshot.children{
if let childSnapshots = child as? DataSnapshot,
let dict = childSnapshots.value as? [String:Any],
let title = dict["title"] as? String,
let content = dict["content"] as? String,
let itemId = dict["itemid"] as? String,
let price = dict["price"] as? Int{
let item = Item(title: title, content: content, itemId: itemId, price: price, urs: newUrlArray)
newItemArray.append(item)
}
}
completion(.success(newDataArray))
})
}
My question is how can I get urls that shown in picture as an array or is it possible.
You need to go one level deeper into your JSON/Snapshot hierarchy to get the URLs.
If I remove the non-URL code for a moment for readability, it'd be something like:
for child in snapshot.children{
if let childSnapshots = child as? DataSnapshot,
let dict = childSnapshots.value as? [String:Any],
let urls = childSnapshots.childSnapshot(atPath: "urls").value as? [String:Any],
...
}
}
So urls above is another dictionary, where you can loop over its keys to get the URL values.
My code below is trying to take core data from a NSManagedObject append it to an array. The core data element is saved as a string. My code is not compelling. Ideally the code should be able to append code into the array then the array is filled, find the sum of the numbers added together and print them into the viewDidLoad() func.
var itemName : [NSManagedObject] = []
func performAction() {
let appD = UIApplication.shared.delegate as! AppDelegate
let context = appD.persistentContainer.viewContext
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "Data")
request.returnsObjectsAsFaults = false
do {
let result = try context.fetch(request)
var retrievedData = [Double]()
for data in result as! [NSManagedObject] {
if let value = data.value(forKey: "ee") as? Double {
retrievedData.append(value)
}
}
let arraySum = retrievedData.reduce(0, +)
print(arraySum)
} catch {
print("Failed")
}
}
I reviewed your code when you will need to change small thing over there. Replace performAction function as per my updated answer.
func performAction() {
let appD = UIApplication.shared.delegate as! AppDelegate
let context = appD.persistentContainer.viewContext
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "Data")
request.returnsObjectsAsFaults = false
do {
let result = try context.fetch(request)
var retrievedData = [Double]()
for data in result as! [NSManagedObject] {
if let value = data.value(forKey: "ee") as? String {
retrievedData.append(Double(value) ?? 0)
}
}
let arraySum = retrievedData.reduce(0, +)
print(arraySum)
} catch {
print("Failed")
}
}
I want to retrieve all the values of 'itemname' from Firebase and put them in my array generatedObjects. Now it seems like i get the parent, and also the key and value of its children, when i only want all values of 'itemname' ('Toiletry bag', 'Toothbrush' etc.). Not sure where to go from here, appreciate any help:
My code:
self.ref.child("lists").child("-LOXr5PoUvBn_tGNhql-").child(whatList!).observeSingleEvent(of: .value, with: { (snapshot) in
let children = snapshot.children
while let rest = children.nextObject() as? DataSnapshot{
print(rest.value)
//self.generatedObjects.append(rest.value as! [String: AnyObject])
}
},withCancel: nil)
Try this
func getData() {
ref.child("lists").child("-LOXr5PoUvBn_tGNhql-").child("mylist").observe(.childAdded) { (snapshot) in
let result = snapshot.value as? [String: Any]
let item = result!["itemname"]
//append item to your array
...
}
}
func fetchdata(toId: String)
{
Database.database().reference().child("Users").child(toId).observeSingleEvent(of: .value) { (snapshot) in
guard let dictionary = snapshot.value as? [String:Any] else {return}
let itemname = dictionary["itemname"] as! String
print(itemname)
}
}
does it helpfull!!
Data:
tried get data from JSON
has code with Swift run on Playground
var roadWayStatusArray = [AnyObject]()
let url = URL(string: "http://od.moi.gov.tw/data/api/pbs")
let data = try? Data(contentsOf: url!)
let json = try? JSONSerialization.jsonObject(with: data!, options: .mutableContainers)
if let results = json as? [String : AnyObject] {
if let result = results["result"] as? [[String : AnyObject]] {
for data in result {
let happendate = data["happendate"] as? String
roadWayStatusArray.append(data as AnyObject!)
}
}
}
I has tried using roadWayStatusArray.sort(by: >) but Xcode report me Ambiguous reference member '>'
How to create sort by hapendate or happentime
Your roadWayStatusArray is an array of AnyObject. There is no > operator defined for AnyObject.
The objects in roadWayStatusArray are actually dictionaries that look like this:
{
UID = "10602090007-0";
areaNm = "\U4e2d\U5c71\U9ad8\U901f\U516c\U8def-\U570b\U9053\Uff11\U865f";
comment = "\U5317\U4e0a.\U4e2d\U58e2\U670d\U52d9\U5340 \U51fa\U53e3\U531d\U9053\U4e2d \U53f3\U5074 \U5c0f\U5ba2\U8eca\U505c\U653e\Uff0c\U99d5\U99db\U7591\U4f3c\U7761\U8457\U4e86";
direction = "\U5317\U4e0a";
happendate = "2017-02-09";
happentime = "01:08:00.0000000";
modDttm = "2017-02-09 01:15:43.603";
region = N;
road = "";
roadtype = "\U5176\U4ed6";
srcdetail = "\U71b1\U5fc3\U807d\U773e";
x1 = "121.73558";
y1 = "25.12263";
}
You need to call sort(by:) with a closure that determines the sort order. For example, if you want to sort by happendate and then happentime:
roadWayStatusArray.sort(by: { (lhsAny, rhsAny) -> Bool in
let lhs = lhsAny as? [String: AnyObject]
let rhs = lhsAny as? [String: AnyObject]
let lhsKey = (lhs?["happendate"] as? String ?? "", lhs?["happentime"] as? String ?? "")
let rhsKey = (rhs?["happendate"] as? String ?? "", rhs?["happentime"] as? String ?? "")
return lhsKey < rhsKey
})
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)
}
}
}
}
}