How to update Firebase with struct - ios

I have a struct EventDate and am trying to update a reference in Firebase.
struct EventDate {
var club: String = ""
var date: String = ""
var eventText: String = ""
var free: String = ""
var monthYear: String = ""
}
My update function throws lldb. I guess because the keys are no Strings(?)
func updateEvent(_ backendlessUserObjectID: String, event: EventDate) {
let reference = firebase.child("eventDates").child(backendlessUserObjectID).child(event.date)
reference.setValue(event) { (error, ref) -> Void in
if error != nil {
print("\(error)")
}
} // lldb here
}
If I change the function to the following, everything is fine (because Keys and Values are now Strings?)
func updateEvent(_ backendlessUserObjectID: String, event: EventDate) {
let item: NSMutableDictionary = ["club" : event.club,
"date" : event.date,
"eventText" : event.eventText,
"free" : event.free,
"monthYear" : event.monthYear]
let reference = firebase.child("eventDates").child(backendlessUserObjectID).child(event.date)
reference.setValue(item) { (error, ref) -> Void in
if error != nil {
print("\(error)")
}
}
}
Am I right that I receive lldb because the keys from my models are not Strings? Or what am I missing and how will I be able to save the values into my Firebase using my model without creating the NSMutableDictionary? Help is very appreciated.
PS: print(event.date) = 201610120200000000 -> the desired value for .child

Firebase data exists in a JSON format which can be thought of as key:value pairs. The keys must be strings and the values can be any of the for data types mentioned in Dravidians answer (which is a correct answer and should be accepted). I would like to add some additional comments that may help as well.
There are times when you want to use a structure in code and that can't be written to Firebase directly - you need some way to get the data out of the structure into something Firebase likes - which is a Dictionary.
Heres an example (Swift 3, Firebase 2.x)
struct EventDate {
var club: String = ""
var date: String = ""
var eventText: String = ""
var free: String = ""
var monthYear: String = ""
func getDict() -> [String:String] {
let dict = ["club": self.club,
"date": self.date,
"eventText": self.eventText,
"free": self.free,
"monthYear": self.monthYear
]
return dict
}
}
var event = EventDate()
event.club = "Wimbledon"
event.date = "20161023"
event.eventText = "Special Tennis Event"
event.free = "Free"
event.monthYear = "10/2016"
let ref = self.myRootRef.child(byAppendingPath: "events")!
let eventRef = ref.childByAutoId() //Firebase 2.x
eventRef?.setValue( event.getDict() )
This results in a node being written to Firebase that looks like this
"events" : {
"-KUli8oiM_KKw8GZ0MMm" : {
"club" : "Wimbeldon",
"date" : "20161023",
"eventText" : "Special Tennis Event",
"free" : "Free",
"monthYear" : "10/2016"
}
}

No it has nothing to do with the type of keys that you are trying to save in your Firebase Database its just that struct is a dataModel or to be precise a physically grouped list of variables which you initialise with some custom Data, and you can only save four types of values types in your Firebase Database:-
NSDictionary
NSArray
NSNumber
NSString
Look up the docs :- Read And Write data, Firebase- iOS
So when you cast your values in a NSMutableDictionary, you come clean of struct. And struct and class is not recognisable by the Firebase Database.

Related

App crashes when I am trying to saved data in my model

I am developing an App using Realm. At some point in my app when I try to manipulate my model, my app crashed in an unexpected way. Here is what the stack trace said
Can only add, remove, or create objects in a Realm in a write transaction - call beginWriteTransaction on an RLMRealm instance first
What I am trying to do :
lets break down my problem in parts.following is my model of app
#objcMembers public class ClassGroup : Object , Codable {
dynamic var Id : Int? = ""
dynamic var ClassName : String? = ""
dynamic var TeacherId : Int = 0
dynamic var Teachers : [TeacherMdoel]? = []
}
#objcMembers public class TeacherModel : Object , Codable {
dynamic var Id : String? = ""
dynamic var Name : String? = ""
dynamic var ClassId : Int = 0
dynamic var Students : [StudentClass]? = []
}
#objcMembers public class StudentModel : Object , Codable {
dynamic var Id : String? = ""
dynamic var Name : String? = ""
dynamic var ClassId : Int = 0
dynamic var TeacherId : Int = 0
}
now I am trying to get the list of all classes like this from realm (after saving them to realm )
let mClassLists = mDbHelper.realmObj.objects(ClassGroup.self)
Now here I get exception/error. What I am doing is, I am trying to populate my UITableView with some data that consist of all of the above models. I am fetching data and saving them in my model and trying to supply that list to UITableView but my app crash with the error I mentioned above
let mClassLists = mDbHelper.realmObj.objects(ClassGroup.self)
let classLists = Array (mClassLists)
for classModel in classLists {
let resultPredicateTeachers = NSPredicate(format: "ClassId == %#", classModel.Id)
let mTeachersList = mDbHelper.realmObj.objects(TeacherModel.self).filter(resultPredicateTeachers)
if(mTeachersList.count > 0){
var listTeachers : [TeacherModel] = []
for teacherModel in mTeachersList {
let resultPredicateStudent = NSPredicate(format: "TeacherId == 29")
let mStudentList = mDbHelper.realmObj.objects(StudentModel.self).filter(resultPredicateStudent)
if(mStudentList.count > 0){
let studentsList = Array(mStudentList)
teacherModel.Students = studentsList[0]
}
listTeachers.append(savedDetailItem)
}
classModel.Teachers? = (listTeachers)
listClassModel.append(classModel)
}
}
**In the Above code you can see that I am gathering data on behalf of Ids and saving the resultant arrays in the model. So I am getting error in the following line
**
teacherModel.Students = studentsList[0]
now I really do not understand why it is happening? I am not saving data in realm, I am saving in my model, still I am getting error.
In Realm database, if you want to modify any model (save new data or update), the operation should be performed in a write transaction:
try! realm.write {
realm.add(<your_model_objects>)
}

Check if an element is present in 3D array Swift

I have an array which gets instantiated in viewDidLoad like var bookingsArray : [[String]] = []
I am adding elements to it in this way:
var configuration: [String] = []
configuration.append(textfieldFacility.text!)
configuration.append((pickSlotTF.text?.components(separatedBy: " ")[0])!)
configuration.append((pickSlotTF.text?.components(separatedBy: " ")[1])!)
bookingsArray.append(configuration as [String])
bookingsArray looks like :
[["A", "20-08-2017", "14:00"], ["B", "20-08-2017", "14:00"]]
While adding new elements to bookingsArray, I want to check if the new element is already present in the array. How do I do it in this case of multi-dimensional array?
First of all, if you want unique objects use a Set.
If this is not possible I highly recommend to use a custom struct which can conform to Equatable rather than a nested array , for example
struct Booking : Equatable {
let facilty : String
let date : String
let time : String
static func ==(lhs : Booking, rhs : Booking) -> Bool {
return lhs.facilty == rhs.facilty && lhs.date == rhs.date && lhs.time == rhs.time
}
}
Then declare the array as
var bookingsArray = [Booking]()
and create an object with
let dateArray = pickSlotTF.text!.components(separatedBy: " ")
let configuration = Booking(facility: textfieldFacility.text!,
date: dateArray[0],
time = dateArray[1])
bookingsArray.append(configuration)
The huge benefit is that you can easily check
if bookingsArray.contains(item)
You can simply search for it with contains().
var configuration: [String] = []
configuration.append(textfieldFacility.text!)
configuration.append((pickSlotTF.text?.components(separatedBy: " ")[0])!)
configuration.append((pickSlotTF.text?.components(separatedBy: " ")[1])!)
if !bookingsArray.contains(where: {$0 == configuration}) {
bookingsArray.append(configuration)
}

Filtering Arrays Containing Multiple Data Types in Swift3

I have an array like:-
var arrayData : Array<Dictionary<String, [BottleModel]>> = []
Bottle model :-
class BottleModel: NSObject {
var name : String
var price : Int
var reviews : Int
var category : String
var quantity : String
var id : String
var shopData : ShopModel
}
I want filtered array where price is > 2000
I tried let searchByInts = arrayData.filter({m in m.price < 200})
but getting below error:
Contextual closure
type '(Dictionary) -> Bool' expects 1 argument,
but 0 were used in closure body
How to filter such kind of array based on price
Working code:
let searchByInts = arrayData.filter { $0.values.contains { $0.contains { $0.price > 2000 } } }
By the way please write the following using literals:
var arrayData : [[String : [BottleModel]]] = []
Still no idea if that is what you actually want because your goal is very unclear. You have an array of dictionaries of arrays which actually contain the values you want to filter out. If a BottleModel costs more than 2000 do you want to keep the entire array it is contained in and the dictionary that array is in? You might want to map the entire data into one flat array before or after filtering.
Alternative using flatMap:
let flat = arrayData.flatMap { $0.values.flatMap { $0 } }
let searchByInts2 = flat.filter { $0.price < 200 } // or some other criteria

Cannot add an append an array into a dictionary that has an empty array

I have a Profile Data singleton class as follows.
I am trying to store data into an empty array in a dictionary .
After appending data to the array also the count of the array is 0.
class ProfileData{
static let sharedInstance = ProfileData()
var artistProfileDict = [String : Profile]()
var loggedInUserProfile = Profile(artistName: "John Smith", artistDescription: "Admiral of New England, English soldier, explorer, and author.", totalLikes: "174", totalViews: "200", totalFollowing: "100",totalFollowers:"50",imageUrl:"image_singer", feeds:[] )
private init() {
getProfilesDictionary()
}
func getProfilesDictionary()->[String: Profile]{
artistProfileDict["John Smith"] = loggedInUserProfile
return artistProfileDict
}
func add(array: Feed, artistName: String) {
artistProfileDict[artistName]!.feeds.append(array)
}
}
In another view Controller I am trying to add an array to the empty array in the dictionary as follows
let newFeed = Feed(profilePicture: "image",artistName: "New",
videoUrl: "url",videoTitle:"New", videoViews: "160",likes:
"200",shoutouts: "200",comments: [],votes: "50", dateCreated: Date(),
userActivity :"This user liked your video")
ProfileData.sharedInstance.add(array: newFeed,artistName:"John Smith")
After appending the array to the empty array in the dictionary I still get the count of the array as 0.
I am not able to figure out the problem here. Any help will appreciated . Thank you.
Profile class
struct Profile {
var artistName: String
var artistDescription: String
var totalLikes: String
var totalViews: String
var totalFollowing: String
var totalFollowers: String
var imageUrl: String
var feeds : [Feed]
init(artistName: String,artistDescription:String,totalLikes:String,totalViews:String,totalFollowing:String,totalFollowers:String,imageUrl:String, feeds:[Feed]) {
self.artistName = artistName
self.artistDescription = artistDescription
self.totalLikes = totalLikes
self.totalViews = totalViews
self.totalFollowing = totalFollowing
self.totalFollowers = totalFollowers
self.imageUrl = imageUrl
self.feeds = feeds
}
}
It's working fine
ProfileData.sharedInstance.add(array: newFeed,artistName:"John Smith")
ProfileData.sharedInstance.artistProfileDict["John Smith"]?.feeds.count // 1
Probably you are using wrong class ArtistProfileData instead of ProfileData.

iterating an array to extract a value from firebase database in swift

might sound like a basic question--but I'm not seeing where I am going wrong..
I end up with either of these two scenarios:
I keep getting the error "Could not cast value of type __NSCFNumber to NSSTring". if I use extractedSku = skuList[i]!.value["sku"] as! String
If I remove as! String it saves it, but it isn't saved as a string. How do I get this to be saved as a string?
I have appended data from firebase into an array
skuArray = [AnyObject?]()
in viewDidLoad, I am iterating skuArray to extract the 'sku' and store into a variable.
var skuArray = [AnyObject?]()
var productDetailArray = [AnyObject?]()
data stored in Sku Array is:
[Optional(Snap (aRandomKey) {
active = 1;
sku = 888888;
})]
viewDidLoad:
let skuList = self.skuArray
for var i = 0; i < skuList.count ; ++i{
let extractedSku = skuList[i]!.value["sku"] as! String
// go into database and extract "products" details by sku
self.databaseRef.child("products/\(extractedSku)").observeEventType(.ChildAdded, withBlock: { (snapshot:FIRDataSnapshot) in
self.productDetailArray.append(snapshot)
})
Since the underlying type is NSNumber, use the stringValue property to get a String:
if let extractedSku = (skuList[i]?.value["sku"] as? NSNumber)?.stringValue {
// use extractedSku which is of type String
}

Resources