UIRefreshControl Crash App Parse.com Query - ios

I have a UICollectionView with a UIRefreshControl. The UIRefreshControl runs a query to get objects from Parse.com. When I perform the refresh by "pulling down" it causes the app to crash and display this message:
fatal error: Cannot index empty buffer
However when I press a button or in the ViewDidLoad to run the same refresh code it does not crash and performs the query as required. Does this mean that there is something wrong with the dragging rather than the refresh code?
Here is the refresh code below (is it to do with the positioning of self.refreshControl.endRefreshing()?)
func refresh(sender:AnyObject)
{
println("Refresh")
self.orderedIdArray = []
self.idArray = []
self.organizerNameArray = []
self.categoryNameArray = []
self.classNameArray = []
var query = PFQuery(className:"Rides")
query.orderByAscending("date")
query.findObjectsInBackgroundWithBlock {
(objects: [AnyObject]!, error: NSError!) -> Void in
if error == nil {
// The find succeeded.
NSLog("Successfully retrieved \(objects.count) scores.")
// Do something with the found objects
for object in objects {
NSLog("%#", object.objectId)
var testId = object.objectId
println(testId)
self.orderedIdArray.append(testId)
var query = PFQuery(className:"Rides")
query.getObjectInBackgroundWithId(testId) {
(gameScore: PFObject!, error: NSError!) -> Void in
if error == nil {
NSLog("%#", gameScore)
//Gets the Values from Parse.com
self.organizerNameString = gameScore["organizer"] as String
self.categoryNameString = gameScore["category"] as String
self.classNameString = gameScore["class"] as String
self.organizerNameArray.append(self.organizerNameString)
self.categoryNameArray.append(self.categoryNameString)
self.classNameArray.append(self.classNameString)
self.idArray.append(object.objectId)
NSLog("%#", self.idArray)
} else {
println("Do not add to the array")
}
}
} else {
NSLog("%#", error)
}
self.collectionView?.reloadData()
}
}
} else {
// Log details of the failure
NSLog("Error: %# %#", error, error.userInfo!)
}
self.refreshControl.endRefreshing()
NSLog("Ordered: %#", self.orderedIdArray)
}
println("Completed the query")
}

Related

Parse.com some columns not updated on segue

I am trying to update a few columns on parse. Here , only gotpromoCode gets updated before segue . But if I come back from the next view controller, on the same button click function gets called again and other columns promoCode and senderUserId are updated. I have set breakpoints and seen that the code for updating the columns is called before segue for these two columns but first time they are still not getting updated.
var promoCode = ""
//if promocode is nil
if ((self.currentUser["promoCode"]) == nil)
{
let nameString = self.firstname.text!+self.lastname.text!
PFCloud.callFunctionInBackground("createPromoCode", withParameters: ["nameString" : nameString]){ response, error in
if let error = error {
print (error)
}
else {
print("Invite sent")
print("the invitation code is: \(String(response!))")
promoCode = String(response!)
PFUser.currentUser()!.setValue(promoCode, forKey: "promoCode")
}
}
}
//validating promo code
if ( self.promocodeText.text?.isEmpty == false )// && PFUser.currentUser()!["gotpromoCode"] == nil )
{
var query1 = PFQuery(className:"_User")
query1.whereKey("promoCode", equalTo:self.promocodeText.text!)
query1.findObjectsInBackgroundWithBlock {
(objects: [PFObject]?, error: NSError?) -> Void in
if error == nil {
PFUser.currentUser()!.setValue(self.promocodeText.text, forKey: "gotpromoCode")
// The find succeeded.
print("Successfully retrieved \(objects!.count) scores.")
// Do something with the found objects
if let objects = objects {
for object in objects {
print(object.objectId)
// self.senderUserId = object.objectId!
PFUser.currentUser()!.setValue(object.objectId!, forKey: "senderUserId")
print("senderUserId is: \(object.objectId!)")
}
}
} else {
// Log details of the failure
print("Error: \(error!) \(error!.userInfo)")
self.displayAlert("Error!", body: "Promo Code does not exists")
}
}
}
PFUser.currentUser()!.saveInBackgroundWithBlock {
(success: Bool, error: NSError?) -> Void in
if (success) {
self.performSegueWithIdentifier(self.goToAccount, sender: self)
} else {
// There was a problem, check error.description
}
}
I have checked the values in breakpoints and am out of ideas why this is happening.
I solved it by saving the result after setting the values.
PFUser.currentUser()!.saveInBackground()
so I used this like
PFUser.currentUser()!.setValue(object.objectId!, forKey: "senderUserId")
PFUser.currentUser()!.saveInBackground()
similarly for the promoCode , then it worked.

iOS : Parse query data

Got a question regarding query from Parse.
I have a list of users on Parse and for every single user, information, like a Timeline, regarding their life events : when was born, what did he do in a certain year, everything displayed in a UITableView.
The thing is that when I press the button for synchronization with Parse, not all data is retrieved. For example, I can get the data for some of them, but for others not.
What could be the reason for this ?
func queryParseForEventsWithCompletionHandler(completionHandler:(success:Bool) -> Void)
{
var query = PFQuery(className:"Event")
query.findObjectsInBackgroundWithBlock
{
(objects: [AnyObject]!, error: NSError!) -> Void in
if error == nil
{
// The find succeeded.
NSLog("Successfully retrieved \(objects.count) events.")
// save parse objects to core data
Event.MR_truncateAll()
for object in objects
{
if object.objectForKey("user") != nil
{
var userEvent = object["user"] as! PFObject
userEvent.fetchIfNeededInBackgroundWithBlock
{(userObj: PFObject!, error: NSError!) -> Void in
self.saveToCoreDataEvent(object as AnyObject, userId: userObj.objectId as NSString)
}
}
else
{
self.saveToCoreDataEvent(object as AnyObject, userId: "")
}
}
completionHandler(success: true)
return
}
else
{
// Log details of the failure
NSLog("Error: %# %#", error, error.userInfo!)
completionHandler(success: false)
return
}
}
}

Retrieve values out of PFObject

I have a save button to save Score and Playername to GameScore in Parse. When I load the GameScore from Parse I want to set the value that i loaded to the variable "score". This don't work, can anyone please tell me what i am doing wrong?
Thanks
Exapmle: let score = gameScore["score"] as Int
// Load button tapped
#IBAction func loadButtonTapped(sender: UIButton) {
var query = PFQuery(className:"GameScore")
query.getObjectInBackgroundWithId("F1efANYzOE") {
(gameScore: PFObject?, error: NSError?) -> Void in
if error == nil && gameScore != nil {
println(gameScore)
let score = gameScore["score"] as Int
} else {
println(error)
}
}
}
}
Try this following code for retrieving specific data from specific columns. You have to enter your object name, Object ID and column name in the below code and run it. It will work.
let query = PFQuery(className:"Your Object name")
query.getObjectInBackgroundWithId("Your Object ID") {
(gameScore: PFObject?, error: NSError?) -> Void in
if error == nil {
print(gameScore!.objectForKey("your column name") as! String)
} else {
print(error)
}
}

Save current user's message list in parse with swift

I use parse for my app. I want to let user able to type messages that they want to send via textField and save it to that user's messages column in parse with PFRelation via save button in view controller and the messages will be saved as an array and show it in tableView.
The problem is I don't know how to add text in textfield to an array and save it to parse.
Any help is appreciated and let me know if you need any additional information!
UPDATE:
These are screenshots of my parse's class "User"
This is my current user's friend list inside "Friends" column
I've not yet create Messages column because when run relationForKey code in Xcode it will automatically create for me
UPDATE 2:
This is my code:
#IBAction func addMessage(sender: AnyObject) {
var newMessage = addMessageText.text
let message = PFObject(className: "Messages")
var query = PFQuery(className: "Messages")
message["messageTextColumn"] = newMessage
message.saveInBackgroundWithBlock {
(success: Bool, error: NSError?) -> Void in
if (success) {
println("added to Message Class")
query.whereKey("messageTextColumn", equalTo: newMessage)
query.getFirstObjectInBackgroundWithBlock{(object:PFObject!, error: NSError!) -> Void in
if error == nil {
let relation = PFUser.currentUser().relationForKey("Messages")
var addMessageWithObject = object
if addMessageWithObject != nil {
relation.addObject(addMessageWithObject)
println("Added with getFirstObject")
}
else{
println("Error Added with getFirstObject")
}
}
}
} else {
println("added to Message class Error")
}
}
}
I save new message to the array first and then I save it with saveInBackgroundWithBlock.. and inside I query that message to add it to relation.
The messages that I've added appear on Messages class table but not in that user's relation but it shows log
"added to Message Class" and "Added with getFirstObject"
Which means that my code execute exactly like it should be. Probably about the method?
UPDATE 3 this is the object println
<Messages: 0x7fd4484f75f0, objectId: LFXoSaHfQl, localId: (null)> {
ACL = "<PFACL: 0x7fd4484d2e70>";
messageTextColumn = 9;
}
UPDATE 4
this is my code
#IBAction func addMessage(sender: AnyObject) {
var newMessage = addMessageText.text
let message = PFObject(className: "Messages")
var user = PFUser.currentUser()
var query = PFQuery(className: "Messages")
message["messageTextColumn"] = newMessage
message.saveInBackgroundWithBlock {
(success: Bool, error: NSError?) -> Void in
if (success) {
println("added to Message Class")
query.getFirstObjectInBackgroundWithBlock{(object:PFObject!, error: NSError!) -> Void in
if error == nil {
var addMessageWithObject = object
if addMessageWithObject != nil {
user.saveInBackground()
println("Added with getFirstObject")
}
else{
println("Error Added with getFirstObject")
}
}
}
}
}
}
user column is (undefined) as in screenshot here
and the error log can't add non pointer to relation is back
how do I fix this? Thanks!
Here's what you do:
Manually create your Message table on Parse
Add a messages column to your user table of type Relation with Target Class as your Message table.
In your code, in your buttons trigger:
// Get the message text from your textField
let messageText = textField.text
// Create your new Message object
let newMessage = PFObject(className: "Message")
// ... Add your data to your new message object
newMessage["messageTextColumn"] = messageText
newMessage.saveInBackgroundWithBlock {
(success: Bool, error: NSError?) -> Void in
if (success) {
// Add the new message to the user's relation
let relation = yourUser.relationForKey("messagesColumnName")
relation.addObject(newMessage)
// Save the user object
yourUser.saveInBackground()
} else {
// There was a problem, check error.description
}
}
Here's a link to Parse's Relation reference.
UPDATE:
Missing code to save your user object.
query.getFirstObjectInBackgroundWithBlock{(object:PFObject!, error: NSError!) -> Void in
if error == nil {
let relation = PFUser.currentUser().relationForKey("Messages")
var addMessageWithObject = object
if addMessageWithObject != nil {
relation.addObject(addMessageWithObject)
PFUser.currentUser().saveInBackground()
println("Added with getFirstObject")
}
else{
println("Error Added with getFirstObject")
}
}
}
UPDATE 2:
Messages without PFRelation:
Add a column (let's say user) of type Pointer with Target Class as _User to the Messages table to identify each message by their user.
Saving new messages: Save the new message object like above (just without adding the relation and it'e related code):
#IBAction func addMessage(sender: AnyObject) {
var newMessage = addMessageText.text
let message = PFObject(className: "Messages")
message["messageTextColumn"] = newMessage
message["user"] = PFUser.currentUser()
message.saveInBackgroundWithBlock {(success: Bool, error: NSError?) -> Void in
if (success) {
println("added to Message Class")
} else {
// Error saving message
}
}
}
Querying the messages for a user: You can query using the current user as a constraint so no matter which device a particular switches to, he/she will get only his messages.
var query = PFQuery(className:"Messages")
query.whereKey("user", equalTo:PFUser.currentUser())
query.findObjectsInBackgroundWithBlock {
...
}

Retrieve object from parse.com and wait with return until data is retrieved

How can I wait until data is retrieved from parse.com?
This is the function I have that returns an empty string since the response from parse.com is too slow. If I put a breakpoint inside the success area it will break "long" after the data is needed. I guess there is a way to get the data synchronous so it will wait?
func getObjectId(localPersonId:NSString) -> NSString{
var currentObjectId:NSString = ""
var query = PFQuery(className:"myClass")
query.whereKey("personId", equalTo:localPersonId)
query.whereKey("groupId", equalTo:self.currentGroupId)
query.findObjectsInBackgroundWithBlock {
(objects: [AnyObject]!, error: NSError!) -> Void in
if error == nil {
// should not use a for loop since this should
// only return one row
for object in objects {
currentObjectId = object["objectId"] as NSString
}
} else {
// Log details of the failure
NSLog("Error: %# %#", error, error.userInfo!)
}
}
return currentObjectId
}
In this case the getObjectId function will return an empty string. Anyone?
I realize this is 3 months old but although the Parse docs are incredibly good/useful, there isn't a whole lot out there answering IOS Parse related questions.
This should work. It uses a completion handler, which is a simple way of dealing with this issue.
(for more on completion handlers in asynch context: https://thatthinginswift.com/completion-handlers/ )
func getObjectId(localPersonId:NSString, completionHandler: (currentObjectId: [String]) -> ()){
var currentObjectId:NSString = ""
var query = PFQuery(className:"myClass")
query.whereKey("personId", equalTo:localPersonId)
//query.whereKey("groupId", equalTo:self.currentGroupId)
query.findObjectsInBackgroundWithBlock {
(objects, error) -> Void in
if error == nil {
// should not use a for loop since this should
// only return one row
for object in objects {
completionHandler(currentObjectId: currentObjectId)
}
} else {
// Log details of the failure
NSLog("Error: %# %#", error!, error!.userInfo!)
}
}
}

Resources