Swift Query Request crashing when value is null - ios

Query results retrieved
"Adjusted_Lease_Value__c" = "0.0";
"Amount_Financed__c" = "23520.64";
"Assignment_Amount__c" = "19220.21";
"Category__c" = 4;
"Charge_Off_Amount__c" = "0.0";
"Committed_Funds__c" = "19220.21";
"Date_Assigned_Back_to_ACG__c" = "<null>"
How I'm retrieving them:
// Initial Access to Salesforce in order to query data
client.performLogin(accessUsername, password: accessPassword, fail:{ (fail) in
}) { (success) in
self.queryResult = self.client.query(getCasesSQL2)
for o: Any in self.queryResult.records() {
// This line fails
let test = (o as AnyObject).fieldValue("Date_Assigned_Back_to_ACG__c") as! String
// This works no problem
let AmountFinanced = ((o as AnyObject).fieldValue("Amount_Financed__c") as! String
}
When the query result is "null" it crashes the app. What should I do?

If it may nil then do not use forced conversion.
self.queryResult = self.client.query(getCasesSQL2)
for o: Any in self.queryResult.records() {
let test = (o as AnyObject).fieldValue("Date_Assigned_Back_to_ACG__c") as? String
let amountFinanced = ((o as AnyObject).fieldValue("Amount_Financed__c") as? String
}

Related

Traverse nsdictionary in swift

I am new to swift.
I have my dictionary as
monthData =
{
"2018-08-10" = {
accuracy = 71;
attempted = 7;
correct = 5;
reward = Bronze;
};
"2018-08-12" = {
accuracy = 13;
attempted = 15;
correct = 2;
reward = "";
};
"2018-08-13" = {
accuracy = 33;
attempted = 15;
correct = 5;
reward = "";
};
"2018-08-14" = {
accuracy = 100;
attempted = 15;
correct = 15;
reward = Gold;
};
"2018-08-16" = {
accuracy = 73;
attempted = 15;
correct = 11;
reward = Silver;
};
"2018-08-21" = {
accuracy = 26;
attempted = 15;
correct = 4;
reward = "";
};
"2018-08-23" = {
accuracy = 46;
attempted = 15;
correct = 7;
reward = "";
};
}
I want to get all the dates for which reward is Gold
Can anyone please help me do that?
What I have tried 'till now is:
for (key,value) in monthData{
let temp = monthData.value(forKey: key as! String) as! NSDictionary
for (key1,value1) in temp{
if((value1 as! String) == "Gold"){
print("keyFINAL \(key)")
}
}
but it outputs the error Could not cast value of type '__NSCFNumber' to 'NSString'
The error occurs because when you are iterating the dictionary you force cast the Int values to String which is not possible
The (highly) recommended Swift way is to use the filter function. This is much more efficient than a loop.
In the closure $0.1 represents the value of the current dictionary ($0.0 would be the key). The result is an array of the date strings.
let data : [String:Any] = ["monthData" : ["2018-08-10": ["accuracy" : 71, "attempted" ... ]]]
if let monthData = data["monthData"] as? [String:[String:Any]] {
let goldData = monthData.filter { $0.1["reward"] as? String == "Gold" }
let allDates = Array(goldData.keys)
print(allDates)
}
The code safely unwraps all optionals.
However if there is only one Gold entry the first function is still more efficient than filter
if let monthData = data["monthData"] as? [String:[String : Any]] {
if let goldData = monthData.first( where: {$0.1["reward"] as? String == "Gold" }) {
let goldDate = goldData.key
print(goldDate)
}
}
In Swift avoid the ObjC runtime (value(forKey:)) and Foundation collection types (NSDictionary) as much as possible.
From the first for in loop, you are getting the NSDictionary in temp variable
"2018-08-16" = {
accuracy = 73;
attempted = 15;
correct = 11;
reward = Silver;
};
So, you should directly check .value(forKey:) on temp and get the value for reward.
You should try it like this
for (key,value) in monthData {
let temp = monthData.value(forKey: key as! String) as! NSDictionary
if(((temp.value(forKey: "reward")) as! String) == "Gold"){
print("keyFINAL \(key)")
}
}
Try and share results
EDIT
Please checkout the answer from vadian for in-depth explanation and pure swift approach to achieve the same.
Thanks

am trying to print("_id") data which am getting from server

For the following swift code
self.cardDataArray = response.value(forKey: "card_list") as? NSArray
print(self.cardDataArray!)
i got this output from server(API)
(
{
"__v" = 0;
"_id" = 5978b5dadc336d0788a81c58;
"stu_number" = 1234567812345678;
"stu_status" = 1;
"created_at" = "2017-07-26T15:31:38.874Z";
"stu_id" = 5978b41ddc336d0788a81c57;
"stu_number" = 1234;
"default_status" = 0;
"default_type" = 3;
}
)
am trying to print "_id" from above code
but am getting error
Could not cast value of type '__NSSingleObjectArrayI' (0x1a9ae6ca0) to 'NSString'
here is the code which i tried to print
let studentID = self.cardDataArray?.value(forKey: "_id") as! NSString
print(studentID)
Your cardDataArray is a Dictionaries Array so you must first take this dictionary and access to the key you need in this case "_id", try with this code
if let studentDict = self.cardDataArray?[0] as? NSDictionary
{
print(studentDict.object(forKey: "_id") as? NSString)
}
Updated
for dictObj in self.cardDataArray {
print(dictObj.object(forKey: "_id") as? NSString)
}
Hope this helps

Compare if let in swift?

I used this code
if let breedVaccRecorddStr = self.petInfoDict.objectForKey("breedvaccinationrecord") {
}else{
ALToastView.toastInView(UIApplication.sharedApplication().keyWindow, withText: "No Data Found")
}
This is my response
{
breed = dabour;
breedvaccinationrecord = "";
"city_registration" = 123146515;
"date_of_birth" = "12-10-2014";
"emergency_contacts" = 1245749876;
gender = male;
"owner_name" = Environmental;
"pt_id" = 4150;
"pt_images" = "";
"pt_name" = demo123;
ptinfo = "http://www.petcsi.com/wp-content/uploads/2015/12/jacky42.jpg";
"prop_name" = "Bella Vida Estates";
"qr_tag" = 5215653454;
species = test;
"vaccination_records" = test123;
vaccinationrecord = "";
"vet_info" = "";
},
Constant can't be nil so it execute if block. but i am expecting output "No Data Found". their may be image url in that key how to check this?
Your question is not very clear, but I'm guessing that your problem is breedvaccinationrecord contains an empty string, not nil. The if let construct by itself only tests for nil, which is why it's not working for you. However, you can also use a where clause:
let value = self.petInfoDict.objectForKey("breedvaccinationrecord")
if let breedVaccRecorddStr = value where value != "" {
// do your stuff
} else {
ALToastView.toastInView(UIApplication.sharedApplication().keyWindow, withText: "No Data Found")
}
This will execute the else if breedvaccinationrecord is nil or an empty string.
You should write another if let statement for nil value you expected. Such as:
if let imageString = self.petInfoDict.objectForKey("ptInfo") as String {
//Do something with the string
}
else {
}

Unable to get PFUser field

I want to get the xp of the current user and display it in a label. The xp field of the user is equal to 252 but it is displaying 0. I can get other fields like email, username and password but can't get the value for the xp field. Code:
xpRequiredLabel.text = "\(PFUser.currentUser()!["XP"])/300 XP"
What am I doing wrong ?
This expression PFUser.currentUser()!["XP"] returns AnyObject?. You need to unwrap this optional and cast it to string. Try this:
let userXP = PFUser.currentUser()!["XP"] as! String
xpRequiredLabel.text = "\(userXP)/300 XP"
Or this (less error-prone):
if let userXP = PFUser.currentUser()?["XP"] as? String {
xpRequiredLabel.text = "\(userXP)/300 XP"
}
Update
It turns out that you have to fetch the object from the server before accessing new properties. So, your code should look like:
let user = PFUser.currentUser()!
user.fetch()
let userXP = ["XP"] as! Int // If you have "Number" as your column datatype
xpRequiredLabel.text = "\(userXP)/300 XP"
Note that fetch() will block the UI. You can also make this code async:
if let user = User.currentUser() {
user.fetchInBackgroundWithBlock({ (result, error) -> Void in
if let u = result as? PFUser {
if let userXP = u["XP"] as? Int {
self.xpRequiredLabel.text = "\(userXP)/300 XP"
}
}
})
}
those are Int values
252 / 300 = 0 when ints invovled
you can do something like
xpRequiredLabel.text = "Float((PFUser.currentUser()!["XP"]))/300.0 XP"

NSDictionary annidate in swift

I have this json result.
I would take the field "alert".
I try this:
var alert: NSString = jsonResult["features"]["properties"]["alert"]
but this is the error: does not have a member named 'subscript'.
I can not how to access a field in a nested dictionary
{
features = (
{
geometry = {
coordinates = (
"-97.95359999999999",
"37.2382",
5
);
type = Point;
};
id = usb000si7g;
properties = {
alert = green;
cdi = "5.8";
code = b000si7g;
detail = "http://earthquake.usgs.gov/earthquakes/feed/v1.0/detail/usb000si7g.geojson";
dmin = "0.017";
felt = 1258;
gap = 38;
ids = ",usb000si7g,";
mag = "4.3";
magType = mwr;
mmi = "4.94";
net = us;
nst = "<null>";
place = "8km SE of Harper, Kansas";
rms = "0.51";
sig = 864;
sources = ",us,";
status = reviewed;
time = 1412272884590;
title = "M 4.3 - 8km SE of Harper, Kansas";
tsunami = "<null>";
type = earthquake;
types = ",cap,dyfi,general-link,geoserve,losspager,moment-tensor,nearby-cities,origin,phase-data,shakemap,tectonic-summary,";
tz = "-300";
updated = 1412614943519;
url = "http://earthquake.usgs.gov/earthquakes/eventpage/usb000si7g";
};
type = Feature;
}
);
metadata = {
api = "1.0.13";
count = 1;
generated = 1412617232000;
status = 200;
title = "USGS Significant Earthquakes, Past Week";
url = "http://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/significant_week.geojson";
};
type = FeatureCollection;
}
I don't know what to do. swift is changed every beta.
As #Kirsteins said is his answer, you have to do a lot of unwrapping, and it's recommended to use a JSON library.
If you still want to stick with hand made extraction, then I suggest you to made it programmatically, such as adding an extension to NSDictionary as follows:
extension NSDictionary {
func objectForTreeKeys<T>(keys:[String]) -> T? {
var dict: NSDictionary? = self
var retValue: T?
for key in keys {
var value: AnyObject? = dict?.objectForKey(key)
if let unwrapped = value as? NSDictionary {
dict = unwrapped
} else if let unwrapped = value as? T {
retValue = unwrapped
break
} else {
retValue = nil
break
}
}
return retValue
}
}
You pass an array of keys to the function, and it traverses all nested dictionaries until:
a value of type T is encountered
a value having type different than NSDictionary and T is found
a nil value is found
In the first case, it returns the value of T type - in the other cases it returns nil.
You can use it as follows:
let ret: String? = jsonResult.objectForTreeKeys(["features", "properties", "alert"])
As you can see, it's a generic method, and the return type is inferred from the type of the variable the result is assigned to - so it's necessary to explicitly define its type, which must be optional (String? in this specific case).

Resources