Code Crashes when loading an empty attribute from Cloudkit - using Swift - ios

I am trying to get access to a record value in CloudKit, here MyPin, it has a title & subtitle attribute/field value.
However it may happen that sometimes the record value is empty(here subtitle), and it crashes at the line when I call:
var tempS: String = Annot["Subtitle"] as! String
because Annot["Subtitle"] doesn exist ...
When I do
println(Annot["Subtitle"])
it returns nil
but if I do :
if (Annot["Subtitle"] == nil) {
println("just got a nil value")
}
I never enter the if statement:
Can someone help me how to identify if the record has an empty value?
Here is my line of codes:
let container = CKContainer.defaultContainer()
let publicData = container.publicCloudDatabase
let query = CKQuery(recordType: "MyPin", predicate: NSPredicate(format: "TRUEPREDICATE", argumentArray: nil))
publicData.performQuery(query, inZoneWithID: nil) { results, error in
if error == nil { // There is no error
for Annot in results {
var tempS: String = Annot["Subtitle"] as! String
}}

when you get Annot["Subtitle"] it will give you a CKRecordValue? return which has a base class of NSObjectProtocol. So in your case the field does exist but it's not a String so casting it using as! String will crash your app. Since the field exists the CKRecordValue will not be nil. However the content of that field is nil. When you print the field, it will output the .description of that field. In your case that is nil. Could you try this code instead:
if let f = Annot["Subtitle"] {
print("f = \(f) of type \(f.dynamicType)")
}
then set a breakpoint on the print line and when it stops try the following three statements in your output window:
po Annot
po f
p f
After the po Annot you should see what's in that record. Including your subtitle field. The po f is not so interesting. It will just output a memory address. The p f however will show you the actual type. If it's a string you should see something like: (__NSCFConstantString *) $R3 = 0xafdd21e0
P.S. Maybe you should call it record instead of Annot. It's a local variable so it should start with a lower case character. And it's still a record and not an Annot.

I think you are doing the right thing, but you don't see the println as it is executed in another thread (the completion part is executed asynchronously).
Try this:
if (Annot["Subtitle"] == nil) {
dispatch_async(dispatch_get_main_queue()) {
println("just got a nil value")
}
}
and see if it works!
The way I get values from cloudkit is this way. This both take care of the nil values and all other eventualities. Just note I have implemented a delegate to get my results back to the calling object asynchronously
privateDB.performQuery(query, inZoneWithID: nil) { (result, error) -> Void in
if error == nil{
for record in result{
let rec = record as! CKRecord
if let xxxVar = rec.valueForKey("fieldName") as? String{
myArray.append( xxxVar! ) //append unwrapped xxxVar to some result or whatever
}else{
//handle nil value
}
}
dispatch_async(dispatch_get_main_queue()) {
//do something with you data
self.delegate?.myResultCallBack(myArray)
return
}
}else{
dispatch_async(dispatch_get_main_queue()) {
self.delegate?.myErrorCallBack(error)
return
}
}
}
Beware, there are some changes in Swift2

Related

Ambiguous reference to member '==' with realm filter

do {
let result = try Realm().objects(Pros.self)
print(result)
let filterResult = result.filter({ $0.category.filter({$0.type_cat == ""})})
print(filterResult)
}
catch {
print(error)
}
and its give me error as "Ambiguous reference to member '=='"
so what i missing to add
I found solution and its work perfectly for me
do {
let result = try Realm().objects(Pros.self)
print(result)
let predicate = NSPredicate(format: "SELF.type == %# AND SELF.status == 'valide' AND ANY category.type_sector = %# AND SELF.status == 'valide'", arrType[(selectedFromType?.row)!], arrTypeSector[(selectedFromSector?.row)!])
let arrFiltered = result.filter(predicate)
print(arrFiltered)
}
catch
{
print(error)
}
Based on Realm docs, filtering chapter, try to change your request like this:
let type = ""
let result = try Realm().objects(Pros.self).filter("category.type_cat == %#",type)
Realm().objects(Pros.self) will return Result<Pros> which kind of Realm Data. Your filter function syntax is a function of Swift, doesn't of Realm. You should convert Result<Pros> to [Pros] before using filter like this:
let result = Array(try Realm().objects(Pros.self))
let filterResult = result.filter({ $0.category.filter({$0.type_cat == ""})})
Or you can using filter function build in Realm. Please check realm.io docs.

If let condition true when value is missing in optional type, swift

I have parser in Objc, parser returns NSDictionary. I am using this parser in swift class. But when some value is missing on that dictionary, it shows nil value. e.g. ->
wirlessData = {
"anon" = {
};
"channel" = {
"text" = 1;
};
}
I am checking through
if let wepauthValue = wirlessData["wepauth"] {
if let value = wepauthValue["text"] {
print("\(value)") // nil
}
}
I don't how it satisfy the if let condition. Any one faced this types of problem can help me out.
Thanks,
vikash
You don't need any special code to do this, because it is what a dictionary already does. When you fetch dict[key] you know whether the dictionary contains the key, because the Optional that you get back is not nil (and it contains the value).
So, if you just want to answer the question whether the dictionary contains the key, ask:
let keyExists = dict[key] != nil
If you want the value and you know the dictionary contains the key, say:
let val = dict[key]!
But if, as usually happens, you don't know it contains the key - you want to fetch it and use it, but only if it exists - then use something like if let:
if let val = dict[key] {
// now val is not nil and the Optional has been unwrapped, so use it
}
I have tested it and found that value is still optional.Take a look at screenshot below to understand it better.
"anon" would be an empty dictionary. An empty dictionary is not nil, it is a dictionary. Just an empty one. A JSON parser will never, ever give nil values unless you ask for a key that is not in a dictionary. For example wirlessData ["nonexistingkey"] would give you nil.
If you be more type-strong about it with the if..let's then:
if let anonValue = wirlessData["anon"] {
if let value = anonValue["text"] as? String {
// This won't execute if value isn't converted from `anonvalue["text"]` to String specifically. This includes null been a false match too
print("\(value)") // nil
}else{
print("Value did't match string at all")
}
}
or even more specifically in your case:
if let anonValue = wirlessData["anon"] {
if let value = anonValue["text"] as? Int {
// This won't execute if value isn't converted from `anonvalue["text"]` to String specifically. This includes null been a false match too
print("\(value)") // nil
}else{
print("Value did't match int at all")
}
}
The value your parser is returning not nil, its empty so you need to check on count if inner data type is dictionary or array, I have past 1 sample here
Please use below code and correct your logic accordingly to get it work properly
let wirlessData:[String:AnyObject] = [
"anon" : [],
"channel" : [
"text" : 1
]
]
if wirlessData["anon"]?.count > 0 {
if let value = wirlessData["anon"]!["text"] {
print("\(value)") // nil
}
}
Try this below code using type check operator (is) -
if wirlessData["anon"] is [String:AnyObject]
{
let anon = wirlessData["anon"]!
print(anon)
if anon["random"] is String {
let stringValue = anon["random"]!
print("\(stringValue)")
}
else if anon["random"] is Int
{
let intValue = anon["random"]!
print("\(intValue)") // nil
}
else
{
print(" may be value did't match string & Int or nil ")
}
}

Swift Parse - Method doesn't stop executing

I have the following code which basically would query Parse class and return a result set. After returning the results, I would pass that array to a function to check if some elements are set or not.
I used print statements all over the code to try and debug, and found that query executes and within the
if error == nil
I am getting the results array to be empty. Hence when I pass that to my function below, it never gets out of it:
func emailOrUsernameIsTaken(results: [PFObject])->Int
{
/*Check if username is taken or if email is taken*/
var preferenceTaken: Int = 0
if(results[0]["email"] as! String != "" && results[0]["email"] as! String == self.userObject.email!)
{
preferenceTaken = 1
}else if(results[0]["appUsername"] as! String != "" && results[0]["appUsername"] as! String == self.userObject.username!){
preferenceTaken = 2
}
return preferenceTaken
}
and this is the code where the query is taking place:
let query = PFQuery.orQueryWithSubqueries([usernameInputCheck, emailInputCheck])
query.findObjectsInBackgroundWithBlock {
(results: [PFObject]?, error: NSError?) -> Void in
if error == nil {
print("Before")
let checkResult = self.emailOrUsernameIsTaken(results!)
print(results)
print("After")
}
}
as an output from print statements above, I get in console:
Before
Optional([])
After
Can someone help me to find out the issue. I am surprised why this is not working.
If results is empty, results[0]["email"] as! String should crash because you are force unwrapping a nil optional value. So the story you are telling is not consistent.
If the actual problem is the empty results - you would have to provide details about your queries and why you expect there to be a populated result.

How to stop unwrapping nil values from Parse Array?

I'm having trouble getting my information back from a saved array in Parse. I'm saving the information like this.....
videoARY = [videoId, vidTitleText, vidDescription, vidIMG]
let videoSave = PFObject(className:"UserVideos")
videoSave["userObjectId"] = PFUser.currentUser()!.objectId
videoSave["vid\(saveValueLBL.text!)user"] = PFUser.currentUser()!.username
videoSave["vid\(saveValueLBL.text!)"] = videoARY
videoSave.saveInBackgroundWithBlock { (success, error ) -> Void in
if success == true
{
print("Success")
}
}
In a different viewcontroller I'm initializing an array like this....
var vid1array = [String]!()
and retrieving this way.......
let query = PFQuery(className: "UserVideos")
query.whereKey("userObjectId", equalTo: PFUser.currentUser()!.objectId!)
query.findObjectsInBackgroundWithBlock { (vid:Array?, error:NSError?) -> Void in
if !(error != nil)
{
for items in vid!
{
if let myfav1 = items["vid1"] as? NSArray
{
self.videoDescription1 = myfav1[2] as! String
self.videoTitle1 = myfav1[1] as! String
self.videoIMG1 = myfav1[3] as! String
print(self.videoDescription1)
print(self.videoIMG1)
print(self.videoTitle1)
self.vid1array.append(self.videoTitle1)
print(self.videoTitle1)
}
}
}
}
I'm printing a successful save and each element of the saved array. When I try to add one of those elements to vid1array the app crashes I get "Fatal error: unexpectedly found nil while unwrapping an Optional value". Please help.
* UPDATE *
When I print vid! I get this...
vid1 = (
"YiiqHq_kNnU",
"INFINITE \"Back\" Official MV",
"If you like this video, plz click \"LIKE\" and \"SUBSCRIBE\". INFINITE \"Back\" Official MV INFINITE Official Website : http://www.ifnt7.com INFINITE Official YouTube ...",
"https://i.ytimg.com/vi/YiiqHq_kNnU/default.jpg"
);
It's not nil but I don't see array brackets either, could that be it? I'm printing out the elements I just want to save them to my array so I can use them in my tableview later and the array is coming up nil.
* FOLLOW UP QUESTION *
Would it be advised to place this in viewWillAppear vs. I currently have it in viewDidLoad?

Detect a Null value in NSDictionary

I have an NSDictionary that's populated from a JSON response from an API server. Sometimes the values for a key in this dictionary are Null
I am trying to take the given value and drop it into the detail text of a table cell for display.
The problem is that when I try to coerce the value into an NSString I get a crash, which I think is because I'm trying to coerce Null into a string.
What's the right way to do this?
What I want to do is something like this:
cell.detailTextLabel.text = sensor.objectForKey( "latestValue" ) as NSString
Here's an example of the Dictionary:
Printing description of sensor:
{
"created_at" = "2012-10-10T22:19:50.501-07:00";
desc = "<null>";
id = 2;
"latest_value" = "<null>";
name = "AC Vent Temp";
"sensor_type" = temp;
slug = "ac-vent-temp";
"updated_at" = "2013-11-17T15:34:27.495-07:00";
}
If I just need to wrap all of this in a conditional, that's fine. I just haven't been able to figure out what that conditional is. Back in the Objective-C world I would compare against [NSNull null] but that doesn't seem to be working in Swift.
You can use the as? operator, which returns an optional value (nil if the downcast fails)
if let latestValue = sensor["latestValue"] as? String {
cell.detailTextLabel.text = latestValue
}
I tested this example in a swift application
let x: AnyObject = NSNull()
if let y = x as? String {
println("I should never be printed: \(y)")
} else {
println("Yay")
}
and it correctly prints "Yay", whereas
let x: AnyObject = "hello!"
if let y = x as? String {
println(y)
} else {
println("I should never be printed")
}
prints "hello!" as expected.
You could also use is to check for the presence of a null:
if sensor["latestValue"] is NSNull {
// do something with null JSON value here
}
I'm using this combination and it also checks if object is not "null".
func isNotNull(object: AnyObject?) -> Bool {
guard let object = object else { return false }
return isNotNSNull(object) && isNotStringNull(object)
}
func isNotNSNull(object: AnyObject) -> Bool {
object.classForCoder != NSNull.classForCoder()
}
func isNotStringNull(object: AnyObject) -> Bool {
guard let object = object as? String where object.uppercaseString == "NULL" else {
return true
}
return false
}
It's not that pretty as extension but work as charm :)
NSNull is a class like any other. Thus you can use is or as to test an AnyObject reference against it.
Thus, here in one of my apps I have an NSArray where every entry is either a Card or NSNull (because you can't put nil in an NSArray). I fetch the NSArray as an Array and cycle through it, switching on which kind of object I get:
for card:AnyObject in arr {
switch card { // how to test for different possible types
case let card as NSNull:
// do one thing
case let card as Card:
// do a different thing
default:
fatalError("unexpected object in card array") // should never happen!
}
}
That is not identical to your scenario, but it is from a working app converted to Swift, and illustrates the full general technique.
my solution for now:
func isNull(someObject: AnyObject?) -> Bool {
guard let someObject = someObject else {
return true
}
return (someObject is NSNull)
}
tests look good so far...
I had a very similar problem and solved it with casting to the correct type of the original NSDictionary value. If your service returns a mixed type JSON object like this
{"id":2, "name":"AC Vent Temp", ...}
you'll have to fetch it's values like that.
var id:int = sensor.valueForKey("id") as Int;
var name:String? = sensor.valueForKey("name") as String;
This did solve my problem. See BAD_INSTRUCTION within swift closure

Resources