Downcast from Any to Specific type - ios

I have firestore DB "sales", which has one column called saleapproveddate. There are 2 levels of people, one who logs sale and other approves the sale logs. While logging sale, I save the saleapproveddate as NSNull() (which saves as nil in firestore DB field). Approver can update the saleapproveddate as TimeStamp, but if the approver never approves the sale log, it remains as nil in firestore DB field. So it can have either nil or TimeStamp type.
I have model Sales
class Sale {
var saleapprovedate : Any?
}
When I load the data from firestore, I tried to downcast the saleapprovedate as Any
let approvedDate = document[SaleProperties.paidDate.rawValue] as Any
But the real challenge is, saleapprovedate can have either nil or Timestamp. How do I check for type condition, convert to specific type and display in label?
Below is what I tried:
While loading data:
sale.saleapprovedate = document[SaleProperties.saleapprovedate.rawValue] as Any
while displaying data:
let saleItem = sales[indexPath.row]
let paidDate = saleItem.saleapprovedate
if paidDate == nil {
cell.paidDateLabelContainer.text = "Yet to pay"
cell.paidStatusImageView.isHidden = true
}
else {
let paidDateTimeStamp = saleItem.saleapprovedate as! Timestamp
let convertedPaidDate = self.convertTimestampToDate(timeStamp: paidDateTimeStamp)
cell.paidDateLabelContainer.text = convertDateToString(date: convertedPaidDate)
cell.paidStatusImageView.isHidden = false
}
But the above code is not updating the cell label properly. I have two data, one has saleapprovedate as Timestamp and other as nil. Both the cell label is displaying as "Yet to pay". What is wrong?

Modal :
var incentivepaiddate : Any?
Array :
var sales : [Sale] = [Sale]()
Loading data from firestore :
for document in querySnapshot!.documents {
let sale = Sale()
sale.incentivepaiddate = document[SaleProperties.incentivepaiddate.rawValue]
self.sales.append(sale)
}
Checking for nil, downcasting to a specific type and display data in cell
let saleItem = sales[indexPath.row]
let paidDate = saleItem.incentivepaiddate
if let paid = paidDate {
let paidDateTimeStamp = paid as? Timestamp
let convertedPaidDate = self.convertTimestampToDate(timeStamp: paidDateTimeStamp!)
cell.paidDateLabelContainer.text = convertDateToString(date: convertedPaidDate)
}
else {
cell.paidDateLabelContainer.text = "Yet to pay"
cell.paidStatusImageView.isHidden = true
}
Hope this helps someone!

Related

Loop in different type of array to find matched one

I'm trying to add a favorite button to my application using CoreData.
I have tableView and added favorite button inside of it to save the label when I press that specific row. I saved it successfully. But I want to populate the CoreData just once for that specific row.
var checkFav = [Fav]()
I created an array with Type Fav which is name of my class for CoreData to populate items I have to check they appear just once.
let result = try context.fetch(Fav.fetchRequest())
checkFav = result as! [Fav]
if checkFav.isEmpty{
let fav = Fav(context: context)
fav.name = name
appDelegate.saveContext()
}
Above you see i populated the array.
do{
let result = try context.fetch(Fav.fetchRequest())
checkFav = result as! [Fav]
if checkFav.isEmpty{
let fav = Fav(context: context)
fav.name = name
appDelegate.saveContext()
}
else{
let checkName = array[rowSelected]
for value in checkFav{
if value.name == checkName{
print("You already have this name ")
}
else {
let fav = Fav(context: context)
fav.name = name
appDelegate.saveContext()
}
}
}
} catch{
print("Error")
}
Let's says I have two name "john","martha" in CoreData if I press to button of "martha" it shouldn't add again. But because of my loop when it sees "john" in the array it thinks this name isn't matching so it's saving "martha" (same name) to CoreData.
How can I check my checkFav array which contains the upcoming name if it contains don't save it again. But if not, add to CoreData. I'm really confused.
Your way to check for an empty entity cannot work if you want to save multiple records.
Add a predicate to the fetch request and a result limit of 1 to check for the specific name.
This method takes the name as parameter and adds a record if the name does not exist. It returns true if an entry is added otherwise false. Further it passes a potential error.
func addFavorite(for name : String) throws -> Bool {
let request : NSFetchRequest<Fav> = Fav.fetchRequest()
request.predicate = NSPredicate(format: "name = %#", name)
request.resultsLimit = 1
if let _ = try context.fetch(request).first {
return false // record exists
} else {
let fav = Fav(context: context)
fav.name = name
appDelegate.saveContext()
return true // record added
}
}

Save json dictionary to core data Swift 3

I am able to get the last guest dictionary value in the json array saved into core data as a dictionary using the transformable key value however the other guest dictionary values are not saving. Guest is also it's on entity for now but I was hoping to save the guest as a dictionary since this task doesn't require complex relationships. I'm sure I'm looking through the json, the value type for reservation.guest = [AnyHashable: Any]?Any suggestions would be helpful here is my json response https://pastebin.com/J28myW66, thanks
Note: using Alamofire for the HTTP Request. Also haven't included my entire class here as this is the main part of it. Reservation and Guest are both NSManagedObject classes
let managedObjectContext = CoreDataManager.shared.persistentContainer.viewContext
let reservationEntityDescription = NSEntityDescription.entity(forEntityName: "Reservation", in: managedObjectContext)
let guestEntityDescription = NSEntityDescription.entity(forEntityName: "Guest", in: managedObjectContext)
let reservation = Reservation(entity: reservationEntityDescription!, insertInto: managedObjectContext)
let guest = Guest(entity: guestEntityDescription!, insertInto: managedObjectContext)
let url = "\(serverEndpoint)\(path)"
manager?.request(
url
).responseJSON { responseData in
if(responseData.result.error != nil) {
print(responseData.response)
}
else if responseData.result.value != nil{
let json = JSON(responseData.result.value!)
let content = json["data"]
var reservationArray: [String] = []
if let dates = content.array {
for item in dates {
if let str = item["date_time"].string {
reservationArray.append(str)
print(reservationArray)
}
}
}
for (key,obj) in content {
let guestData = obj["guest"]
let guestDict = guestData.dictionaryObject!
reservation.guest = guestDict
reservation.id = obj["id"].stringValue
reservation.dateTime = obj["date_time"].date
reservation.startTime = obj["start_time"].time
reservation.numOfPeople = obj["number_of_people"].intValue as NSNumber?
reservation.status = obj["status"].stringValue
reservation.tables = obj["tables"].arrayObject as! [NSString]?
reservation.reservationCollections = reservationArray as [NSString]?
guest.id = guestData["id"].stringValue
guest.email = guestData["email"].stringValue
guest.name = guestData["full_name"].stringValue
guest.phone = guestData["phone"].stringValue
guest.notes = guestData["notes"].stringValue
}
print("Reservation to be saved\(reservation)")
print("Guest to be saved: \(guest)")
}
}
do {
try reservation.managedObjectContext?.save()
} catch let error as NSError {
fatalError(error.localizedDescription)
}
do {
try guest.managedObjectContext?.save()
} catch let error as NSError {
fatalError(error.localizedDescription)
}
When your code starts, you create one instance of Guest and one instance of Reservation:
let reservation = Reservation(entity: reservationEntityDescription!, insertInto: managedObjectContext)
let guest = Guest(entity: guestEntityDescription!, insertInto: managedObjectContext)
After that you never create any other instances. In your loop you assign values to this instance:
reservation.guest = guestDict
reservation.id = obj["id"].stringValue
...
guest.id = guestData["id"].stringValue
guest.email = guestData["email"].stringValue
...
But since there's only one instance, only the last pass through the loop gets saved. The first time through the loop you assign values to guest and reservation. Every other time, you overwrite the previous values with new ones.
If you want to save a new instance for every pass through the loop, you need to create new instances every time. Move the let guest = ... and let reservation = ... lines inside the loop.
Firstly you need to make design flow bit generic i.e The HTTP request/response, DataBase Part, Model Part and UI part.
Now create a generic model class for your response,
so that the values will bind in single object.
In you core data sub class your table i.e custom NSManagedObject Class.
First convert the dictionary objects [objects in content.array] into respective model class objects.
In that SBPlayer is a model class
Favourite+CoreDataProperties.swift & Favourite+CoreDataClass.swift are custom NSManagedObject class (auto-generated).
Now with every object, you have mapping respective properties in database table and in custom NSManagedObject class.
Map the values and Save it DataBase.
For example: https://github.com/Abhishek9634/ScoreBoard/blob/master/ScoreBoard/ScoreBoard/SBDBManager.swift
Reference : https://github.com/Abhishek9634/ScoreBoard

How to handle Empty PFFile objects (Parse backend, Swift)

I have a list of users stored on Parse (backend), with a column called "profile_picture" that stores the user's profile picture. However, there are certain users without a profile picture, thus their profile_picture column is "undefined" (has no value).
I am using a searchbar to query through all the users and update the tableview with the user's profile pic and username. I do this by appending the username to var searchResults = String , and the profile pic to var searchImages = PFFile after the query like so:
let query = PFQuery.orQuery(withSubqueries: [usernameQuery!,fbUsername!, firstnameQuery!, lastnameQuery!]);
searchActive = true;
query.findObjectsInBackground { (objects, error) in
if error != nil {
print("There was an error getting userlist");
}
else {
if let users = objects {
self.searchResults.removeAll(keepingCapacity: false);
for object in users {
if let user = object.object(forKey: "username") as? String {
self.searchResults.append(user);
}
if let picture = object.object(forKey: "profile_picture") as? PFFile {
self.searchImages.append(picture);
}
self.searchTableView.reloadData();
}
The problem is that when the "profile_picture" column is empty, it does not append anything, which then means that the searchResults array (containing usernames) and the searchImages array (containing the PFFiles) have different sizes, which results in uncoordinated assignments of values. They are supposed to parallel arrays. And I'm using values in these arrays to assign values in a table cell.
Hope you guys understand my problem! Thanks in advance
So your username field is definitely not empty. I think you can add an else after you check whether profile_picture is nil or not. Like:
if let picture = object.object(forKey: "profile_picture") as? PFFile {
self.searchImages.append(picture);
} else {
self.searchImages.append(UIImage(named:"placeholder"))
}

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
}

Adding Relational Data to a Class From User Class - Parse & Swift

I have to classes in parse, one is showing the users and the other is showing tweets. Both of the classes has a username column. However, I need to add a relational data to the tweets class that will include the info of the user class object for each user. I tried lots of codes but I could not make it. The views of my two classes are attached. How would be the swift code that when someone enters a new tweet a relational input will also be created in the tweet class. My current tweet code is as below:
var tweetObj = PFObject(className: "tweets")
tweetObj["userName"] = PFUser.currentUser()!.username
tweetObj["profileName"] = PFUser.currentUser()!.valueForKey("profileName") as! String
tweetObj["photo"] = PFUser.currentUser()!.valueForKey("photo") as! PFFile
tweetObj["tweet"] = theTweet
tweetObj["tweetType"] = 1
if hasImage == true {
tweetObj["hasImage"] = "yes"
let imageData = UIImagePNGRepresentation(self.tweetImg.image)
let imageFile = PFFile(name: "tweetPhoto.png", data: imageData)
tweetObj["tweetImage"] = imageFile
} else {
tweetObj["hasImage"] = "no"
}
tweetObj.save()
println("tweet!")
self.dismissViewControllerAnimated(true, completion: nil)
}
http://i.imgur.com/blszoqn.png
http://i.imgur.com/fK4ghlq.png

Resources