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.
Related
As I understand it, the CKModifyRecordsOperation(recordsToSave:, recordsToDelete:) method should make it possible to modify multiple records and delete multiple records all at the same time.
In my code, recordsToSave is an array with 2 CKRecords. I have no records to delete, so I set recordsToDelete to nil. Perplexingly enough, it appears that recordsToSave[0] gets saved to the cloud properly while recordsToSave[1] does not.
To give some more context before I paste my code:
In my app, there's a "Join" button associated with every post on a feed. When the user taps the "Join" button, 2 cloud transactions occur: 1) the post's reference gets added to joinedList of type [CKReference], and 2) the post's record should increment its NUM_PEOPLE property. Based on the CloudKit dashboard, cloud transaction #1 is occurring, but not #2.
Here is my code, with irrelevant parts omitted:
#IBAction func joinOrLeaveIsClicked(_ sender: Any) {
self.container.fetchUserRecordID() { userRecordID, outerError in
if outerError == nil {
self.db.fetch(withRecordID: userRecordID!) { userRecord, innerError in
if innerError == nil {
var joinedList: [CKReference]
if userRecord!.object(forKey: JOINED_LIST) == nil {
joinedList = [CKReference]() // init an empty list
}
else {
joinedList = userRecord!.object(forKey: JOINED_LIST) as! [CKReference]
}
let ref = CKReference(recordID: self.post.recordID, action: .none)
// ... omitted some of the if-else if-else ladder
// add to list if you haven't joined already
else if !joinedList.contains(ref) {
// modifying user record
joinedList.append(ref) // add to list
userRecord?[JOINED_LIST] = joinedList as CKRecordValue // associate list with user record
// modifying post
let oldCount = self.post.object(forKey: NUM_PEOPLE) as! Int
self.post[NUM_PEOPLE] = (oldCount + 1) as CKRecordValue
let operation = CKModifyRecordsOperation(recordsToSave: [userRecord!, self.post], recordIDsToDelete: nil)
self.db.add(operation)
}
// omitted more of the if-else if-else ladder
else {
if let error = innerError as? CKError {
print(error)
}
}
}
}
else {
if let error = outerError as? CKError {
print(error)
}
}
}
}
EDIT
Here's the code I added per the request of the first commenter
operation.modifyRecordsCompletionBlock = { savedRecords, deletedRecordsIDs, error in
if error == nil {
DispatchQueue.main.async(execute: {
self.num.text = String(oldCount + 1) // UI update
})
}
else {
print(error!)
}
}
ANOTHER EDIT
let operation = CKModifyRecordsOperation(recordsToSave: [userRecord!, self.post], recordIDsToDelete: nil)
operation.perRecordCompletionBlock = { record, error in
if error != nil {
let castedError = error as! NSError
print(castedError)
}
}
operation.modifyRecordsCompletionBlock = { savedRecords, deletedRecordsIDs, error in
if error == nil {
DispatchQueue.main.async(execute: {
self.num.text = String(oldCount + 1) // UI update
})
}
else {
print(error!)
}
}
self.db.add(operation)
So I'm trying to create a registration page with availability by Zip Code. For instance, a user can only register if the service is available in their area (zip code).
So far I have a Text field for Zip Code and a button labeled "Check Availability".
I have a Parse Backend and I tested a connection to it using their setup guide and it works.
How can I go about checking the text that was inputted to see if it matches a zip code in my parse database? So if a the zip code the user entered matches one in the parse database I need a new ViewController called "Register" to open and the user can begin their singup/registration.
Current Code:
class checkAvailability: UIViewController {
#IBOutlet weak var zipCode: UITextField!
#IBAction func checkAvailBtn(sender: AnyObject) {
performSegueWithIdentifier("beginSignUp", sender: self)
}
func checkZip() {
var usersZipCode = zipCode.text
var queryZip = PFQuery(className: "zipCode")
queryZip.findObjectsInBackgroundWithBlock { (objects:[AnyObject]?, error:NSError?) -> Void in
if error == nil {
// The find succeeded.
println("Successfully retrieved \(objects!.count) zip codes.")
// Do something with the found objects
if let zipCodes = objects as? [PFObject] {
if zipCodes.contains({ $0["zipCodes"] == usersZipCode) {
print("your in!") // transition to the new screen
}
else {
print("your out.") // do whatever
}
}
} else {
// Log details of the failure
println("Error: \(error!) \(error!.userInfo!)")
}
}
override func viewDidLoad() {
super.viewDidLoad()
//Code
}
Thank you
Create a PFQuery to pull down the list of zip codes into the app, then simply check to see if the string the user entered is in the list.
-- EDIT --
let query = PFQuery(className:"ZipCode")
query.findObjectsInBackgroundWithBlock {
(objects: [AnyObject]?, error: NSError?) -> Void in
if error == nil {
// The find succeeded.
print("Successfully retrieved \(objects!.count) zip codes.")
// Do something with the found objects
if let zipCodes = objects as? [PFObject] {
if zipCodes.contains({ $0["zip_code"] as! String == usersZipCode }) {
print("your in!") // transition to the new screen
}
else {
print("your out.") // do whatever
}
}
} else {
// Log details of the failure
print("Error: \(error!) \(error!.userInfo)")
}
}
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)
}
}
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 {
...
}
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")
}