Firebase array became nil after loop in Swift - arrays

I'm trying to append element to array but it returns empty array.
What I'm trying to do is put elements that match up with tags user selected.
To achieve that, first I created model.
//Model
import UIKit
import Firebase
struct Team {
var key: String
var teamName: String
var league: String
var lat: Double
var lng: Double
init(snapshot: DataSnapshot) {
self.key = snapshot.key
self.teamName = (snapshot.value as! NSDictionary)["teamName"] as? String
self.league = (snapshot.value as! NSDictionary)["league"] as? String ?? ""
self.lat = (snapshot.value as! NSDictionary)["lat"] as? Double ?? 0
self.lng = (snapshot.value as! NSDictionary)["lng"] as? Double ?? 0
}
}
firebase structure looks like this.
{
"tags": {
"NewYork": {
uid1: 1
uid2: 1
uid3: 1
},
"baseball": {
uid1: 1
}
}
}
First, I fetched uids that match up with the tags. Then retrieve team's info based on uids that matched up with. If the same uid comes in like uid1 above, I want Xcode to print something. To do that I implemented like so(is there a better way?) but it's never been executed because results.count is always 0 even if after appended. However right after append method(I commented //here) it returns team's info properly.
func filterTeam(filterTag: FilteredTags) {
let tag = filterTag.selectedTag.components(separatedBy: "/") //this returns "NewYork" and "baseball"
var results = [Team]()
tag.forEach { (key) in
ref.child("tags").child(key).observe(.value, with: { (snapshot) in
guard let dictionary = snapshot.value as? [String:Any] else { return }
dictionary.forEach({ (uid,_) in
if results.count == 0 {
ref.child("teams").child(uid).observe(.value, with: { (snapshots) in
let team = Team(snapshot: snapshots)
results.append(team)
//here
print(results)
}, withCancel: nil)
} else {
for result in results {
if result.key == uid {
print("same uid!!")
} else {
ref.child("teams").child(uid).observe(.value, with: { (snapshots) in
let team = Team(snapshot: snapshots)
results.append(team)
}, withCancel: nil)
}
}
}
})
}, withCancel: nil)
}
}//func
How can I append properly and achieve what I want to do.
Thank you in advance!

Related

Child Updated crashing table (indexPath is out of range error that crashes my app Error)

I am having a hard time updating an array in my app that controls a table. I want to be able to change a child node in Firebase Database and have it update on my users' end without me having to code and send an update. I need to be able to change their tag and have it update the table without the index being out of range.
Here is my Class Struct for the information for the users:
import UIKit
class User: NSObject {
var Name: String?
var Email: String?
var UID: String?
var Tag: String?
}
In my controller I have the following code to initialize the table with the info from Firebase:
func CreateDataArray() {
Database.database().reference().child("Users").observe(.childAdded, with: { (snapshot) in
if let dictionary = snapshot.value as? [String: AnyObject] {
let user = User()
//self.setValuesForKeys(dictionary)
user.Name = dictionary["Name"] as? String
user.Email = dictionary["Email"] as? String
user.UID = dictionary["UID"] as? String
user.Tag = dictionary["Tag"] as? String
if user.Tag == "Macro" {
self.macroUsersArray.append(user)
} else if user.Tag == "Micro" {
self.microUsersArray.append(user)
}
self.users.append(user)
self.userName.append(user.Name!)
self.filteredNames.append(user.Name!)
print(dictionary)
print(self.macroUsersArray)
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
}, withCancel: nil)
}
I then have a function that listens for any changes from my Firebase and updates the arrays:
func updateDataArray() {
Database.database().reference().child("Users").observe(.childChanged, with: { (snapshot) in
if let dictionary = snapshot.value as? [String: AnyObject] {
let user = User()
//self.setValuesForKeys(dictionary)
user.Name = dictionary["Name"] as? String
user.Email = dictionary["Email"] as? String
user.UID = dictionary["UID"] as? String
user.Tag = dictionary["Tag"] as? String
if user.Tag == "Macro" {
self.microUsersArray.remove(at: 2)
} else if user.Tag == "Micro" {
self.macroUsersArray.remove(at: 2)
}
self.users.append(user)
self.userName.append(user.Name!)
self.filteredNames.append(user.Name!)
print(dictionary)
print(self.macroUsersArray)
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
}, withCancel: nil)
}
I want to get the user that originally had the tag "macro" that got switch to "micro" to be removed from the macro list and show up in the micro list. I am not able to get the arrays to append and keep getting the indexPath is out of range error that crashes my app. I really need help and have been struggling with this the last few weeks.
Edit: I have decided to use observe.value so that when I make changes it reads it. Here is my code for creating the users' info:
func CreateDataArray() {
Database.database().reference().child("Users").observe(.value, with: { (snapshot) in
if let dictionary = snapshot.value as? [String: AnyObject] {
let user = User()
//self.setValuesForKeys(dictionary)
user.Name = dictionary["Name"] as? String
user.Email = dictionary["Email"] as? String
user.Tag = dictionary["Tag"] as? String
if user.Tag == "Macro" {
self.macroUsersArray.append(user)
} else if user.Tag == "Micro" {
self.microUsersArray.append(user)
}
self.users.append(user)
self.userName.append(user.Name!)
self.filteredNames.append(user.Name!)
print(dictionary)
print(self.macroUsersArray)
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
}, withCancel: nil)
}
However, I am able to pull all the data into a snapshot but it is returning nil when I try to append. I am getting an error of nil on any line of code with "append(User.Name!)
I would love to figure out how to stop this nil and allow my observer to keep listening for changes in my database.
EDIT 2:
Here are my variables:
var allUsersArray = [User]()
var macroUsersArray = [User]()
var microUsersArray = [User]()
Here is my ViewDidLoad:
override func viewDidLoad() {
super.viewDidLoad()
updateDataArray()
}
Here is my updateDataArray code:
func updateDataArray() {
Database.database().reference().child("Users").observe(.childAdded, with: { (snapshot) in
if let dictionary = snapshot.value as? [String: AnyObject] {
let user = User()
//self.setValuesForKeys(dictionary)
user.Name = dictionary["Name"] as? String
user.Email = dictionary["Email"] as? String
user.UID = dictionary["UID"] as? String
user.Tag = dictionary["Tag"] as? String
self.allUsersArray.append(user)
self.users.append(user)
self.userName.append(user.Name!)
self.filteredNames.append(user.Name!)
self.macroUsersArray = self.allUsersArray.filter { $0.Tag == "Macro" }
self.microUsersArray = self.allUsersArray.filter { $0.Tag == "Micro" }
self.observeChangeInUserProperty()
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
}, withCancel: nil)
}
Here is the observeChangeInUserProperty() function:
func observeChangeInUserProperty() {
let ref = Database.database().reference().child("Users").child("Talent")
ref.observe(.childChanged, with: { snapshot in
let key = snapshot.key
let tag = snapshot.childSnapshot(forPath: "Tag").value as! String // ! = never optional
//get the user from the allUsersArray by its key
if let user = self.allUsersArray.first(where: { $0.Tag == key }) {
if user.Tag != tag { //if the tag changed, handle it
user.Tag = tag //update the allUsersArray
if tag == "Macro" { //if the new tag is Macro remove the user from the Micro array
if let userIndex = self.microUsersArray.firstIndex(where: { $0.Tag == key }) {
self.microUsersArray.remove(at: userIndex)
self.macroUsersArray.append(user) //add user to macro array
}
} else { //new type is micro so remove from macro array
if let userIndex = self.macroUsersArray.firstIndex(where: { $0.Tag == key }) {
self.macroUsersArray.remove(at: userIndex)
self.microUsersArray.append(user)
}
}
//reload the tableviews to reflect the changes
self.microTableView.reloadData()
self.tableView.reloadData()
}
}
})
}
I am getting empty arrays for Macro and Micro. I don't know what I am doing wrong.
EDIT 3:
Here is my new user struct with initialization from Firebase:
import UIKit
import Firebase
class User: NSObject {
var Name: String?
var Email: String?
var UID: String?
var Tag: String?
init?(from snapshot: DataSnapshot) {
let dictionary = snapshot.value as? [String: Any]
self.Name = dictionary!["Name"] as? String
self.Email = dictionary!["Email"] as? String
self.UID = dictionary!["UID"] as? String
self.Tag = dictionary!["Tag"] as? String
}
}
I am now able to append the arrays but they are not populating my tables. I can also change the user's tag in Firebase without the app crashing but it doesn't observe the changed Tag and move the user to the other array. So I need help with those two things.
This answer is going to require a little set up and restatement of the goal
The goal is to have two arrays, used as dataSources for two
tableViews. One array contains user type: macro and the other array
contains user type: micro.
If a user type is changed from macro to micro (and vice-versa) the OP
wants to remove the user from one table and add it to the other.
the conceptual answer is: add an observer to the users node in Firebase and when a change occurs to a user, see if it's the type property, and if so remove from one table and add it to another.
There are lots of solutions but let me present this very long-winded answer which could be reduced in both code and by property observers.
Start with three arrays, one to hold all users and the others to hold macro and micro users. Assume the UserClass has a String type property of either macro or micro
var allUsersArray = [UserClass]()
var macroArray = [UserClass]()
var microArray = [UserClass]()
Read in all users and then from that, divide the users into their respective type
...read firebase single event of .value, with: { snapshot in
and populate allUsersArray from the snapshot..
self.macroArray = self.allUsersArray.filter { $0.type == "macro" }
self.microArray = self.allUsersArray.filter { $0.type == "micro" }
self.observeChangeInUserProperty()
}
The below code adds an observer to the users array which will notify the app when any property of a user changes, and presents that user node in the snapshot.
func observeChangeInUserProperty() {
let ref = self.ref.child("users")
ref.observe(.childChanged, with: { snapshot in
let key = snapshot.key
let type = snapshot.childSnapshot(forPath: "type").value as! String // ! = never optional
//get the user from the allUsersArray by its key
if let user = self.allUsersArray.first(where: { $0.key == key }) {
if user.type != type { //if the type changed, handle it
user.type = type //update the allUsersArray
if type == "macro" { //if the new type is macro remove the user from the micro array
if let userIndex = self.microArray.firstIndex(where: { $0.key == key }) {
self.microArray.remove(at: userIndex)
self.macroArray.append(user) //add user to macro array
}
} else { //new type is micro so remove from macro array
if let userIndex = self.macroArray.firstIndex(where: { $0.key == key }) {
self.macroArray.remove(at: userIndex)
self.microArray.append(user)
}
}
//reload the tableviews to reflect the changes
self.microTable.reloadData()
self.mactoTable.reloadData()
}
}
})
}
As mentioned this is a lot of extraneous code and could be condensed with property observers or leveraging a single array for both tables or a number of other solutions.
Edit
In case you want to know how to populate the all users array from Firebase, you need to have a User class that is init'ed from a snapshot and here's the code
func loadAllUsersAndPopulateArray() {
let ref = self.ref.child("users")
ref.observeSingleEvent(of: .value, with: { snapshot in
let allUsersSnapshot = snapshot.children.allObjects as! [DataSnapshot]
for userSnap in allUsersSnapshot {
let user = UserClass(withSnap: userSnap)
self.allUsersArray.append(user)
}
})
}

How can I remove whole dictionary in nested array at specific index after filter some specific value

I have API response with nested array . But I can't understand how can I remove whole Dict by filtering the value .
This is the response screenshot
https://imgur.com/XIDyfYX
here is the json Resonse :- https://del.dog/lofavofogo.json
I have tried this but I don't know how to get filter nested value and remove whole dict at specific index
How to remove pairs from dictionary at specific index - Swift?
I want to remove the dict where section name are "NA"
Here is the code :-
Model Class For API Response :-
class filterclass: NSObject {
var classesID : String?
var classname : String?
var section = [filterSections]()
init(json: [String: Any]) {
if let classname = json["class"] as? String {
self.classname = classname
}
if let classesID = json["classesID"] as? String {
self.classesID = classesID
}
print("classname",classname)
if let evUserGoing = json["classsection"] as? [[String: Any]] {
if self.section.count > 0
{
self.section.removeAll()
}
for evUser in evUserGoing {
// print("evUser",evUser)
let userGoing = filterSections(json: evUser)
self.section.append(userGoing)
}
for sec in section {
let section = sec.secctionname
let setionID = sec.sectionID
}
}
}
}
class filterSections: NSObject {
var sectionID : String?
var secctionname : String?
var isSelctedSection : Bool = false
init(json: [String: Any]) {
if let sectionID = json["sectionID"] as? String {
self.sectionID = sectionID
}
if let secctionname = json["section"] as? String {
self.secctionname = secctionname
}
print("sectioname",secctionname)
}
}
API POST Method TO hit API :-
func getClassSectionAPI() {
if ReusableClass.sharedInstance.isNetworkAvailable() == true
{
ReusableClass.sharedInstance.showActivityIndicator()
let UUid = LoginUserInfo.sharedInstance.uuid!
let dictionary = ["uuid":UUid,"device_id":devicetoken,"school_id":LoginUserInfo.sharedInstance.schoolId!, "user_type":LoginUserInfo.sharedInstance.usertype!]
print(dictionary)
let encoder = JSONEncoder()
if let jsonData = try? encoder.encode(dictionary) {
if let jsonString = String(data: jsonData, encoding: .utf8) {
// print(jsonString)
let cipher:String = CryptoHelper.encrypt(input:jsonString)!;
let NewEncryption = "data=\(cipher)"
print(NewEncryption)
let hmac_md5 = cipher.hmac(algorithm: .sha512, key: kHMACKey)
print("hmac",hmac_md5)
UserDefaults.standard.set(hmac_md5, forKey: Headerkey)
Singleton.sharedInstance.getWebservicesverify(params: NewEncryption, Methodname: KFilterClassSection, data: Stringnil)
{ (result) in
DispatchQueue.main.async {
ReusableClass.sharedInstance.hideActivityIndicator()
}
if result != nil
{
do {
let jsonData = try JSONSerialization.data(withJSONObject: result)
if let json = String(data: jsonData, encoding: .utf8) {
let Dict = function.convertToDictionary(text: json)! as NSDictionary
guard let data = Dict[KData] as? String
else
{
return
}
self.baseDict = data
}
}
catch {
}
guard let output = CryptoHelper.decrypt(input:self.baseDict)
else
{
return
}
print(output)
let mainDict = function.convertToDictionary(text: output)! as NSDictionary
let status = mainDict[KStatus] as! NSInteger
if(status == 1)
{
DispatchQueue.main.async {
print("Main dict",mainDict)
guard let messageArray = mainDict["data"] as? [[String: Any]] else{
return
}
if self.arrayClasSection.count > 0
{
self.arrayClasSection.removeAll()
}
print("Main dict",messageArray)
for arr in messageArray {
let obj = filterclass.init(json: arr)
if let index = self.arryFilterTemperary.index(where: { $0.classname == obj.classname }) {
// let filtered = self.arryFilterTemperary.filter { $0.classname == "NA" }
obj.section = self.arryFilterTemperary[index].section
self.arrayClasSection.append(obj)
for sec in self.arryFilterTemperary[index].section {
let section = sec.sectionID
let sectionName = sec.secctionname
self.NASection = sec.secctionname!
print(self.NASection)
self.selectedNASectionID = sec.sectionID!
// let test = self.arryFilterTemperary[index].section.filter { !$0.value.contains("") }
// print(test)
}
}
else
{
self.arrayClasSection.append(obj)
}
}
ReusableClass.sharedInstance.hideActivityIndicator()
self.tableFilter.reloadData()
}
}
I want to append the data to array but before appending I want to
filter that "NA" value dict from the array
Since this is your first question I go to some greater length in answering it than usual. Playgrounds are an exceptional way to demonstrate your problem, so you should always try to compose your questions in a form of one. I will post my answer directly from the Playground I have done.
With that out of the way lets get to the question. Your main problem seems to be that you tried an ill fated JSONSerialization "shortcutt" route. This looks cheap from the outside, but working with the unavoidable optionality of a [String:Any] comes at a high cost in a language like Swift. The way to go is the brilliant Codable protocol, at least in my opinion. Once you define your data structure properly Xcode has so much more possibilities to guide you through the APIs that writing your filter code becomes a piece of cake.
Enough of the ranting, let's get to the pizza.
import UIKit
let dataStr = """
{
"status":1,
"message":"Class and sections list",
"data":[
{
"classsection":[
{
"section":"A",
"sectionID":"1",
"classesID":"1"
},
{
"section":"B",
"sectionID":"3",
"classesID":"1"
}
],
"class":"First",
"classesID":"1"
},
{
"classsection":[
{
"section":"A",
"sectionID":"2",
"classesID":"2"
},
{
"section":"B",
"sectionID":"7",
"classesID":"2"
}
],
"class":"Second",
"classesID":"2"
},
{
"classsection":[
{
"section":"A",
"sectionID":"20",
"classesID":"15"
}
],
"class":"Third",
"classesID":"15"
},
{
"classsection":[
{
"section":"NA",
"sectionID":"33",
"classesID":"22"
}
],
"class":"Pre Nursery",
"classesID":"22"
},
{
"classsection":[
{
"section":"NA",
"sectionID":"34",
"classesID":"23"
},
{
"section":"A",
"sectionID":"35",
"classesID":"23"
},
{
"section":"B",
"sectionID":"36",
"classesID":"23"
},
{
"section":"C",
"sectionID":"37",
"classesID":"23"
}
],
"class":"Fourth four",
"classesID":"23"
},
{
"classsection":[
{
"section":"NA",
"sectionID":"38",
"classesID":"24"
}
],
"class":"Fifth",
"classesID":"24"
},
{
"classsection":[
{
"section":"NA",
"sectionID":"39",
"classesID":"25"
}
],
"class":"sixth 6th",
"classesID":"25"
}
]
}
"""
struct Section: Codable {
let section, sectionId, classesId: String
enum CodingKeys: String, CodingKey {
case sectionId = "sectionID"
case classesId = "classesID"
case section
}
}
struct Class1: Codable {
let classsection: [Section]
let clazz, classesId: String
private enum CodingKeys: String, CodingKey {
case classsection
case clazz = "class"
case classesId = "classesID"
}
}
struct Response: Codable {
let status: Int
let message: String
let data: [Class1]
func filterSections(notMatching filterVal: String) -> Response {
let filteredData = data.map { (clazz) -> Class1 in
let filteredSections = clazz.classsection.filter { (sect) -> Bool in
sect.section != filterVal
}
return Class1(classsection: filteredSections, clazz: clazz.clazz, classesId: clazz.classesId)
}
return Response(status: status, message: message, data: filteredData)
}
}
let jsonData = dataStr.data(using:.utf8)!
do {
let res = try JSONDecoder().decode(Response.self, from: jsonData)
let filteredResponse = res.filterSections(notMatching: "NA")
let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted
print(String(data:try encoder.encode(filteredResponse), encoding: .utf8)!)
} catch {
print(error)
}
As you can see your data structure is easily defined and the filtering code is really easy to understand once you wrap your head around the lambdas (which you should). The playground will output nicely formatted JSON as an answer, this way it is easy to check that your code does the right thing without all the messy parts of asynchronous communication (which are still nicely done in Swift).
Here's my last tipp of the day: Always try to isolate your problem as much as possible if you post a question on StackOverflow. I think your question carried too much legacy, you should whittle it down for the next one. This will improve your chances for a quick answer.

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) })
}
}

Swift - json nested array not returning value

I am trying to grab the array from "imports" from the JSON file but the array is returning encoded.
[ServerName.JSONNodeValue, ServerName.JSONNodeValue, ServerName.JSONNodeValue, ServerName.JSONNodeValue, ServerName.JSONNodeValue, ServerName.JSONNodeValue]
I know the data can be seen as if I print the value of the data in the JSONNode file, it comes up as
https://servername.com/storage/sessions/00167/imports
(
"movie1.mov",
"movie3.mov",
"movie2.mov",
"._movie1.mov",
"._movie2.mov",
"._movie3.mov"
)
This isn't my code and the reason why I am struggling as I am still pretty new at swift.
My JSON file looks similar to this.
{
"id": 135
"name": Test
"angles" [
{
"id": 35,
"name": "test",
"mp4": "http:/0.0.0:3000/storage/seesion/00138/url.mp4"
}
]
"imports" [
movie1.mp4,
movie2.mp4,
movie3.mp4
]
}
Swift Code - Session File
struct Session {
var id: Int
var name: String
var angles: [Angle] = []
var imports: [Any]
extension Session {
init(fromDict dict: [String: AnyObject]){
let node = JSONNodeValue(dict)
let sessionId = node["id"].int ?? 0
self.id = sessionId
self.name = node["name"].string ?? "???"
print(name)
self.imports = node["imports"].arrayOrEmpty
self.angles = node["angles"].arrayOrEmpty.map { angleDict in
Angle(fromDict: angleDict.object!)
}
JSONnode file that handles the JSON
protocol JSONNode {
subscript(key: String) -> JSONNode { get }
var int: Int? { get }
var double: Double? { get }
var string: String? { get }
var bool: Bool? { get }
var date: Date? { get }
var array: [JSONNode]? { get }
var arrayOrEmpty: [JSONNode] { get }
var object: [String: Any]? { get }
var objectOrEmpty: [String: Any] { get }
}
class JSONNodeValue : JSONNode {
static func parse (_ data: Data) -> JSONNode {
if let root = try? JSONSerialization.jsonObject(with: data) {
return JSONNodeValue(root)
} else {
return JSONNodeNone.instance
}
}
var value: Any
init(_ value: Any) {
self.value = value
print(value) // SHOWS THE DATA I NEED
}
subscript(key: String) -> JSONNode {
if let object = value as? [String: Any], let subvalue = object[key] {
return JSONNodeValue(subvalue)
} else {
return JSONNodeNone.instance
}
}
var int: Int? {
return value as? Int
}
var double: Double? {
return value as? Double
}
var string: String? {
return value as? String
}
var bool: Bool? {
return value as? Bool
}
var date: Date? {
if let formatted = string {
return Date.fromIso8601(formatted)
} else {
return nil
}
}
var array: [JSONNode]? {
if let array = value as? [Any] {
return array.map { JSONNodeValue($0) }
} else {
return nil
}
}
var arrayOrEmpty: [JSONNode] {
return array ?? []
}
var object: [String: Any]? {
return value as? [String: Any]
}
var objectOrEmpty: [String : Any] {
return object ?? [:]
}
}
Could someone point me in the right direction or to other answered questions that could help me solve this? Thanks
The struct looks good, but remove the = [] after [Angle], but you should use Codable protocol to parse the JSON like so:
struct Session: Codable {
var id: Int
var name: String
var angles: [Angle]
var imports_dir_contents: [Any]
then create another struct to get the Angle
struct Angle: Codable
let id: Int
let name: String
let mp4: String
Then you want to parse using the Codable protocol method by passing in the data retrieved from the networking call.
do {
let newJSONDecoder = JSONDecoder()
let session = try newJSONDecoder.decode(Session.self, from:data)
let anglesArray = session.angles // or use whatever array property you want
} catch {
print("error while parsing:\(error)")
}
I solved what I was trying to achieve by adding a new a variable in the JSNODE file which then gave me ["movie1.mov", "movie3.mov", "movie2.mov", "._movie1.mov", "._movie2.mov", "._movie3.mov"]
var arrayList: [String]? {
return value as? [String]
}
Thanks for the help though.

Creating an array out of Firebase Dictionary

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")
}
})
}

Resources