checking undefined value before retrieving from parse
I am making a simple app, and implementing the userInformation part. The user can edit his info, but I have trouble that if user doesn't put any info, it will crash when I try to retrieve data from an undefined column.
This is my code to retrieve the user data. If there is data to parse it won't crash, otherwise it will.
var query = PFQuery(className: "Note")
query.getObjectInBackgroundWithId("kg8KhAWCms", block: {
(obj, error)in
if let score = obj! as? PFObject {
print(score.objectForKey("title"))
var nickname = (score.objectForKey("title")) as! String
self.nickNameLabel.text = nickname
} else {
print(error)
}
})
I tried this code as well, but it has error which is binary operator '!=' cannot be applied to operands of type 'String' and 'NiLiteralConvertible'
var query = PFQuery(className: "Note")
query.getObjectInBackgroundWithId("kg8KhAWCms", block: {
(obj, error)in
if let obj = obj! as? PFObject {
print(obj.objectForKey("title"))
var nickname = (obj.objectForKey("title")) as! String
if (nickname != nil) {
self.nickNameLabel.text = nickname
}else{
self.nickNameLabel.text = "you don't have a nick name"
}
} else {
print(error)
}
})
So I am asking how can I handle retrieving undefined value before crash? (please write full code for me)
Is there a way I can check undefined value or specific value in column before I retrieve it?
///like this
if (value in parse == "ABC") {
print("yes")
}
Related
I'm writing a program where I reference a database where authenticated users each have a document whose ID corresponds to their User ID. Given the user's ID, I am trying to determine their name; I have managed to read all of the user's data and it is in my data model of class Users:
class Users {
var id: String
var name: String
var surname: String // ...
}
In my ViewModel, I have
#Published var specificUser = User(id: "", name: "", surname: "", email: "", profficiency: 0, lists: [[]])
which is an initialized user.
In that same ViewModel, I have a function that fetches the User Data from the database, which appears to work. It should then store the new user data in the specificUserData variable.
func getData() {
let db = Firestore.firestore()
guard let uid = auth.currentUser?.uid else { return }
db.collection("Users").getDocuments { result, error in
if error == nil {
print("Current User's ID found: \(uid)")
if let result = result {
// iterate through documents until correct ID is found
for d in result.documents {
if d.documentID == uid {
print("Document ID found: \(d.documentID)")
self.specificUser = User(
id: d.documentID,
name: d["name"] as? String ?? "",
// ...
)
print(self.specificUser)
print(self.specificUser.name) // This works; my compiler spits out the correct name from the database, so clearly the specificUser variable has been changed.
}
}
}
} else {
// Handle Error
print("Error while fetching user's specific data")
}
}
}
Here's how I initialized the getData() function:
init() {
model.getData()
print("Data Retrieval Complete")
print("User's Name: \(model.specificUser.name)")
}
I am trying to reference my ViewModel like this:
#ObservedObject var model = ViewModel()
Now here's the problem: when I try to reference the User's name from the view model in my struct with
model.specificUser.name
It gives me the default name, even though I have initialized the getData() function already. Checking my compiler log and adding a bunch of print statements, it appears that the initialization is in fact working, but it is printing data retrieval complete before it is printing the albeit correct name.
Any thoughts? It seems that the initializer function is taking the initialized value from my ViewModel rather than the correct value it should be computing.
try this
func getData(_ completion: #escaping (Bool, User?) -> ()) {
let db = Firestore.firestore()
guard let uid = auth.currentUser?.uid else { return }
db.collection("Users").getDocuments { result, error in
if error == nil {
print("Current User's ID found: \(uid)")
if let result = result {
// iterate through documents until correct ID is found
for d in result.documents {
if d.documentID == uid {
print("Document ID found: \(d.documentID)")
let user = User(
id: d.documentID,
name: d["name"] as? String ?? "",
// ...
)
completion(true, user)
print(self.specificUser)
print(self.specificUser.name) // This works; my compiler spits out the correct name from the database, so clearly the specificUser variable has been changed.
}
}
}
} else {
// Handle Error
completion(false, nil)
print("Error while fetching user's specific data")
}
}
}
init() {
model.getData() { res, user in
if res {
self.specificUser = user!
}
print("Data Retrieval Complete")
print("User's Name: \(model.specificUser.name)")
}
}
This question already has answers here:
Can't assign a value to variable inside of closure Swift [duplicate]
(1 answer)
Assign value of a Firestore document to a variable
(1 answer)
Need to obtain shopping cart sum after series of getDocument price lookups
(1 answer)
Firebase datadescription returns empty array
(1 answer)
Closed 2 years ago.
So I am trying to fetch data from Firebase Firestore and put it into a local variable inside my function. Inside the function I created a variable for a name which is supposed to contain the value of the name of the user fetched from Firebase. The problem is that the variable name which is given the value of nameData (name from the database) is in reality never mutated. How should I do to get the name from the database and put it inside a variable?
public func fetchName(email: String) -> String {
var name: String = "FIRST VALUE"
database.collection(workerCollection).document(email).getDocument() {(querySnapshot, error) in
if let error = error {
print("Error getting documents: \(error)")
} else {
//get info about user
if (querySnapshot != nil && querySnapshot!.exists){
let documentData = querySnapshot!.data()!
if let nameData = (documentData["Name"] as! String?){
name = nameData
}
print(name)
}
}
}
return name
}
Add a completion handler in your function to get the name. Modify your function like this!
public func fetchName(email: String, Completion:#escaping((String)->()) {
database.collection(workerCollection).document(email).getDocument() {(querySnapshot, error) in
if let error = error {
print("Error getting documents: \(error)")
} else {
//get info about user
if (querySnapshot != nil && querySnapshot!.exists){
let documentData = querySnapshot!.data()!
if let nameData = (documentData["Name"] as! String?){
Completion(nameData)
}
}
}
}
}
And then call that function in viewDidLoad or where ever you like.
fetchName(email: "a#b.com") { (name) in
print(name)
}
Try this:
public func fetchName(email: String) -> String? {
var name: String?
name = database.collection(workerCollection).whereField("emailField", isEqualTo: email)
dispatchQueue.main.async {
return name
}
}
Code
let number=UserDefaults.standard.object(forKey: "phone")
let s=PFQuery(className: "Customer")
s.whereKey("phonenumber", equalTo:number!)
s.getFirstObjectInBackground(block: { (gameScore: PFObject?, error: Error?) in
if let error = error {
//The query returned an error
print(error.localizedDescription)
} else {
//The object has been retrieved
print(gameScore?.objectId)
}
})
I need to fetch object id in a row where it matches my phone number, How do I do that?
I made mistake while calling the query , query needs only Int but iam sending Any data type
let number=UserDefaults.standard.object(forKey: "phone") as? String
let Stringtonumber=Int(number!)
let s=PFQuery(className: "Customer")
s.whereKey("phonenumber", equalTo:Stringtonumber)
s.getFirstObjectInBackground(block: { (gameScore: PFObject?, error: Error?) in
if let error = error {
//The query returned an error
print(error.localizedDescription)
} else {
//The object has been retrieved
print(gameScore?.objectId)
}
})
I have the following data model
#objc dynamic var uid = UUID().uuidString;
#objc dynamic var completed: Bool = false;
#objc dynamic var dateCompleted: Date?;
When I create a new object it has nil for the dateCompleted, then when the user completes the task I try to update the object with primaryKey (uid) like so
let query = realm.objects(Tasks.self).filter("uid = %#", id).first!;
if query.completed == false {
var date = Date();
} else {
var date: Date = nil
}
let wayUpdate = ["uid": id, "completed": !query.completed, "dateCompleted": date] as [String : Any]
do {
try realm.write {
realm.create(WaysData.self, value: wayUpdate, update: true)
}
} catch {
print("Error adding update to experience! \(error)");
}
I get the following error Cannot convert value of type 'String' to specified type 'Date' in the else block.
My question is - is there a way to clear the date when updating completion to false, or should I just leave dateCompleted as Date() each time the user completes/uncompletes/completes the task and just do a check on the completed: Bool value whenever I want to update the completion button's label to "Complete" or "Revive"?
If you simply want to update a single property of your Object subclass instance, don't call create, simply modify that single property in a write transaction.
do {
try realm.write {
query.dateCompleted = query.completed ? nil : Date()
}
} catch {
print("Error adding update to experience! \(error)")
}
You should also use the primary key to retrieve the object, don't filter the query.
let query = realm.object(ofType: Tasks.self,forPrimaryKey: id)
Unrelated to your issue, but you shouldn't use ; at the end of your lines in Swift, this is not Objective-C.
I have an array of AnyObject objects in Swift. Each object has attributes of a restaurant, such as name, type, loc, etc. How can I filter the array if I want to keep all objects in the array that contain type: "Sushi".
Sample array of [AnyObject] with 2 objects. The filter should keep the first object (type: sushi):
[<Restaurant: 0x7ff302c8a4e0, objectId: LA74J92QDA, localId: (null)> {
City = "New York";
Country = "United States";
Name = Sumo Japan;
Type = Sushi, Japanese, Asian;
}, <Restaurant: 0x7ff302daa790, objectId: 0aKFrpKN46, localId: (null)> {
City = "New York";
Country = "United States";
Name = Little Italy;
Type = Italian, Pizza;
}]
Current Code (but I'm not sure if the filter can search through an array of [AnyObject]) :
var query = PFQuery(className:"Restaurant")
query.whereKey("RestaurantLoc", nearGeoPoint:userGeoPoint, withinMiles:50)
query.limit = 2
query.findObjectsInBackgroundWithBlock {
(objects: [AnyObject]!, error: NSError!) -> Void in
if objects != nil {
println("list of objects of nearby")
println(objects)
let searchString = "Sushi"
let predicate = NSPredicate(format: "Type CONTAINS[cd] %#", searchString);
//Line below gives error: '[AnyObject]' does not have a member named 'filteredArrayUsingPredicate'
//let filteredArray = objects.filteredArrayUsingPredicate(predicate!)
Your array, objects, is an array of PFObject objects. Thus, to filter the array, you might do something like:
let filteredArray = objects.filter() {
if let type = ($0 as PFObject)["Type"] as String {
return type.rangeOfString("Sushi") != nil
} else {
return false
}
}
My original answer, based upon an assumption that we were dealing with custom Restaurant objects, is below:
You can use the filter method.
Let's assume Restaurant was defined as follows:
class Restaurant {
var city: String
var name: String
var country: String
var type: [String]!
init (city: String, name: String, country: String, type: [String]!) {
...
}
}
So, assuming that type is an array of strings, you'd do something like:
let filteredArray = objects.filter() {contains(($0 as Restaurant).type, "Sushi")}
If your array of types could be nil, you'd do a conditional unwrapping of it:
let filteredArray = objects.filter() {
if let type = ($0 as Restaurant).type as [String]! {
return contains(type, "Sushi")
} else {
return false
}
}
The particulars will vary a little depending upon your declaration of Restaurant, which you haven't shared with us, but hopefully this illustrates the idea.
Swift 3 Solution
Use the filter method on an array.
let restaurants: [Restaurants] = [...]
restaurants.filter({(restaurant) in
return Bool(restaurant.type == "sushi")
})
or return Bool(restaurant.type.contains("sushi")) if type is an array.
Ok, if the array objects contains only Restaurant(s) the following code does work.
Lets say Restaurant is something like this:
enum RestaurantType {
case Sushi, Japanese, Asian
}
class Restaurant {
var type = [RestaurantType]()
// more properties here...
}
First of all lets define an array of Restaurant(s).
var restaurants = objects as [Restaurant]
Then we can filter it:
var sushiRestaurants = restaurants.filter { (restaurant : Restaurant) -> Bool in
return contains(restaurant.type, .Sushi)
}
Update:
Now I am assuming objects is an array of PFObject(s)
Just ignore my previous code and try this:
var restaurants = objects as [PFObject]
var sushiRestaurants = restaurants.filter { (restaurant : PFObject) -> Bool in
return contains(restaurant["Type"], "Sushi")
}
Maybe it will crash again, the problem is that I don't know the type of Restaurant.Type. I'm trying. Maybe the next error message will provide more useful info.
Modification of Rob's answer as Swift 2.0, In swift 2.0 using Rob's code gives error as follows -
initializer for conditional binding must have optional type, not 'string'
However it can be solved by using guard statement instead of if-let as below -
let filteredArray = objects.filter() {
guard let type = ($0 as PFObject)["Type"] as String else {
return false
}
return type.rangeOfString("Sushi") != nil
}
I have a solution as given below.
func filterByCuisineType(list: [Restaurant]) -> [Restaurant]{
if self.cuisineTypes.count == 0 {
return list
}
let array: [Restaurant] = list.filter { (restaurant) -> Bool in
for cuisineName in self.cuisineTypes{
let isContained: Bool = restaurant.cuisineType.contains(cuisineName)
if isContained {
return true
}
}
return false
}
return array
}