How to stop unwrapping nil values from Parse Array? - ios

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?

Related

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 sort NSDate in descending order from Parse in ios swift

I am looking to get the Parse data of my past meetings. My issue is I want to see the most recent events first. If I fetch the data with following code, am getting it in ascending order. i.e. most recent meeting goes to the last and the oldest comes first.
//let oldDate = NSDate(timeIntervalSinceReferenceDate: -123456789.0)
let query:PFQuery = PFQuery(className: "Events")
//query.whereKey("EventSTDTime", greaterThan: oldDate)
query.whereKey("EventSTDTime", lessThan: NSDate())
query.findObjectsInBackgroundWithBlock {
(object, error) -> Void in
if object != nil
{
if(object!.count != 0)
{
for messageObject in object! {
let meetingName:String! = (messageObject as! PFObject)["MeetingName"] as? String
}
}
}
I tried with removing the comment, I still dont get any difference. I want the most recent meetings at first and then oldest event at the last.
Please help
Add this to your query.
[query addDescendingOrder:#"EventSTDTime"];

Update values on parse

Is there a way to update a number on parse not just by replacing it or creating a new object id then deleting the old one but by actually incrementing the value from the stored value on parse and the new value being added to it. Ie.
On parse: Correct = 5 ; On app: Correct = 10 ; new value on parse: 15
This is my code but it just creates a new object id with the new values every time...
func saveScoresOnParse() {
scores["Right"] = rightAnswers
scores["Wrong"] = wrongAnswers
scores["Skipped"] = skippedQuestions
scores["User"] = PFUser.currentUser()
scores.saveInBackground()
}
On parse:
I want the values to be added up and as well as only have one objectid for each one.
let scoreQuery = PFQuery(className: "Scores")
scoreQuery.whereKey("user", equalTo: PFUser.currentUser()!)
scoreQuery.getFirstObjectInBackgroundWithBlock { (object, error) -> Void in
if error == nil {
if let scores = object {
scores["Right"] = rightAnswers
scores["Wrong"] = wrongAnswers
scores["Skipped"] = skippedQuestions
scores.saveInBackground()
}
}
}

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

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

Retrieving objects from Parse iOS

I am new to programming and am trying to develop an iOS app using Swift. However, I ran into a problem trying to retrieve previously saved information from Parse to use in my app.
To save the information I use the following code:
var user = PFUser.currentUser()
var number = self.phoneNumber.text as String
var insta = self.instagramUsername.text as String
var snapp = self.snapchatName.text as String
var twitter = self.twitterHandle.text as String
var bio = self.profileBio.text as String
var socialData = PFObject(className: "socialData")
socialData["phoneNumber"] = number
socialData["instagram"] = insta
socialData["snapchat"] = snapp
socialData["twitter"] = twitter
socialData["bio"] = bio
socialData["user"] = user
socialData.save()
This saves the information on Parse correctly but then when I try to retrieve the Instagram name or anything else specifically using a query I get an error. Here is how I have been trying to retrieve it:
var user = PFUser.currentUser()
var query = PFQuery(className:"socialData")
query.whereKey("user", equalTo: user)
query.findObjectsInBackgroundWithBlock {
(objects: [AnyObject]!, error: NSError!) -> Void in
if error == nil {
// The find succeeded.
// Do something with the found objects
var socialData = PFObject(className: "socialData")
let instaUsername = socialData["instagram"] as String
println(instaUsername)
} else {
// Log details of the failure
NSLog("Error: %# %#", error, error.userInfo!)
}
}
The logs say fatal error: unexpectedly found nil while unwrapping an Optional value. After the app crashes. Yet, the information is correctly displayed on Parse. Any help is greatly appreciated, thanks!
Remove this line within your findObjectsInBackgroundWithBlock block entirely:
var socialData = PFObject(className: "socialData")
and replace this line:
let instaUsername = socialData["instagram"] as String
with this:
let instaUsername = objects[0]["instagram"] as String
so you're actually utilizing the object array retrieved from the query, accessing the first object which matches the current user, then getting the "instagram" key's stored value from that PFObject dictionary.

Resources