Parse not updating the core data Swift - ios

I am trying to make changes to the data already stored in the core data in Parse. But it is not making the necessary changes. And I looked at the documentation for parse regarding objects here: https://parse.com/docs/ios/guide#objects. And it seems that I am doing exactly what the document is telling me to do. Maybe I am missing something? Here is my code:
import UIKit
import Parse
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
var products = PFObject(className:"Products")
products["name"] = "ice cream"
products["description"] = "Strawberry"
products["price"] = 4.99
products.saveInBackgroundWithBlock {
(success, error) -> Void in
if (success) {
println("Object saved with id \(products.objectId)")
} else {
println("Not successful!")
print(error)
}
}
//ignore the code below this line for now please :)
var query = PFQuery(className: "Products")
query.getObjectInBackgroundWithId("7lmnxHxibK", block: { (object: PFObject?, error) -> Void in
if error != nil {
print(error)
} else if let product = object {
print("YO")
product["description"] = "Rocky Road"
product["price"] = 5.99
products.saveInBackground()
}
})
}
}
So the code above created an object with the ID 7lmnxHxibK. The description being Strawberry, the name being ice cream, and the price being 4.99. Which worked as it should. So now as an attempt to change the attributes in the object with the ID 7lmnxHxibK, I wrote the following code:
var query = PFQuery(className: "Products")
query.getObjectInBackgroundWithId("7lmnxHxibK", block: { (object: PFObject?, error) -> Void in
if error != nil {
print(error)
} else if let product = object {
print("YO")
product["description"] = "Rocky Road"
product["price"] = 5.99
products.saveInBackground()
}
})
This code should make the necessary changes to the object with the id 7lmnxHxibK. But rather than making the necessary changes to the object's attributes, it is creating a new object with it's description, name, and price all being (undefined). Anybody have a solution to fix this?

You have to change products.saveInBackground() to product.saveInBackground(). Also by the time you call your second query parse may not be done saving the object for the first time.

Related

Iterate through a custom Parse column in Swift app

I want to know how I could store the entire custom column (the user Pointer<_User> column from a custom class) and put them all in an array variable so that I can see if a the user exists in that class or not. This is what I have:
Old Code
var objectUserIdArray = [String]()
let objectUserIdQuery : PFQuery = PFQuery(className: "Scores")
objectUserIdQuery.findObjectsInBackgroundWithBlock {
(objects : [PFObject]? , error : NSError?) -> Void in
var objectID = objects! as [PFObject]
for i in 0..<objectID.count {
objectUserIdArray.append(objectID[i].objectId!)
}
for _ in objectID {
print(objectUserIdArray)
}
New Code
func saveScoresOnParse() {
objectUserIdQuery.whereKey("User", equalTo: PFObject(withoutDataWithClassName: "_User", objectId: userID))
objectUserIdQuery.findObjectsInBackgroundWithBlock {
(objects : [PFObject]? , error : NSError?) -> Void in
if error == nil {
//var objectID = objects! as [PFObject]
/*for i in 0..<objectID.count {
self.objectUserIdArray.append( objectID[i].objectId! )
}*/
for _ in objects! {
print(objects)
}
// The score key has been incremented
for (var i = 0 ; i < self.objectUserIdArray.count ; i++) {
if self.userID != objects![i] {
print("New Scores")
print("R: \(self.rightAnswers)")
print("W: \(self.wrongAnswers)")
print("S: \(self.skippedQuestions)")
self.scores["User"] = PFUser.currentUser()
self.scores["Right"] = self.rightAnswers
self.scores["Wrong"] = self.wrongAnswers
self.scores["Skipped"] = self.skippedQuestions
self.scores.saveInBackground()
} else if self.userID == objects![i] {
print("Updated Scores")
self.scores.incrementKey("Right", byAmount: 1)
self.scores.incrementKey("Wrong", byAmount: 1)
self.scores.incrementKey("Skipped", byAmount: 1)
print("R: \(self.rightAnswers)")
print("W: \(self.wrongAnswers)")
print("S: \(self.skippedQuestions)")
self.scores.saveInBackgroundWithBlock {
(success: Bool, error: NSError?) -> Void in
if (success) {
// The score key has been incremented
} else {
// There was a problem, check error.description
}
}
} else {
print("Error")
}
}
} else {
print(error)
}
}
But it only stores the objectId column and not the Pointer<_User> column. I know this because when I print the stuff that is inside, it prints out the objectIds.
This is what happens, instead of just updating the current user's scores, it just makes new ones. I want the if statement to check if the user already exists in that column and if it does updates the scores and if it doesn't, make new ones. (The new code's if statement doesn't work, i have to bring it out for it to save...)
Your updated question make clearer what you are actually wanting to do;
Save or update a user's scores in your Parse Score object. To do this, there is no reason to retrieve any object Ids or loop through any results. More often than not you don't do use Object Ids explicitly when using Parse; you can simply pass the object itself with Parse working out the references for you.
I am not sure how you exactly want to change the scores; in your code above you increment in one case but set the scores explicitly in another, but the code below shows the general approach.
If you are frequently or repeatedly going to update a score record then you could make your code more efficient by holding a reference to the Scores object in a property after you find it the first time and simply update & save it subsequently.
func saveScoresOnParse() {
if let currentUser=PFUser.currentUser() {
let scoreQuery= PFQuery(className: "Scores")
scoreQuery.whereKey("User",equalTo:currentUser)
scoreQuery.getFirstObjectInBackgroundWithBlock {
(object : PFObject? , error : NSError?) -> Void in
if error == nil {
var scoreObject=object ?? PFObject.objectWithClassName("Scores")
if (scoreObject["User"]==nil) {
scoreObject["User"]=currentUser
}
scoreObject["Right"]=self.rightAnswers
scoreObject.saveInBackground()
} else {
print(error)
}
}
} else {
print("No current user!")
}
}

Passing objectId from viewDidLoad to another function using Parse method getObjectInBackgroundWithId not working

I'm a beginner working with Parse and Swift. I need to update the object referred to in my viewDidLoad in another function within the same controller. How do I pass the currently loaded object's objectId without having to hardcode it like this:
query.getObjectInBackgroundWithId("8DkYgraEJq")
Here is my viewDidLoad function:
override func viewDidLoad() {
var query = PFQuery(className: "CheckedBaggage")
query.orderByAscending("createdAt")
query.whereKey("respondedTo", notEqualTo: true)
query.getFirstObjectInBackgroundWithBlock {
(CheckedBaggage: PFObject!, error: NSError!) -> Void in
if error != nil {
println("The getFirstObject request failed.")
} else {
// The find succeeded.
self.randomBaggageLabel.text = CheckedBaggage.objectForKey("message") as? NSString
CheckedBaggage.save()
println(CheckedBaggage.objectId)
let baggageId = CheckedBaggage.objectId
println("Successfully retrieved the object.")
}
}
I would like to try and pass the variable baggageId, which should be the object's ID as a string, as an argument to the getObjectInBackgroundWithId block in my carryIt function:
#IBAction func carryIt(sender: AnyObject!) {
println("CarryIt is being called")
var query = PFQuery(className: "CheckedBaggage")
query.getObjectInBackgroundWithId(baggageId) {
(CheckedBaggage: PFObject?, error: NSError?) -> Void in
if error != nil {
println(error)
} else if let CheckedBaggage = CheckedBaggage {
println("object hello!")
CheckedBaggage["respondedTo"] = true
CheckedBaggage["response"] = self.kindnessMessage.text
CheckedBaggage.save()
}
}
}
But I'm getting an "unresolved identifier" error. It updates my Parse database perfectly fine if I hardcode the object ID, but I can't do it this way. Here's a screenshot of the error:
Thank you so much for your help!
You have to initialize baggageId. To use it in multiple functions, it must be scoped at class level as the comment said. To set it after it has been declared, it must be a "var", not a constant "let".
var baggageId = ""
func viewDidload() {
var query = ...
query.get... {
baggageId = CheckedBaggege.objectId
}
}
func shipIt() {
var query = ...
query.getObjectWithId(baggageId) ...
}

Retrieving user data from Parse "_User" class using "ObjectId"

i am trying to retrive a user's data to get the user info from the _User class using the object id. i used this :
var data:NSMutableArray = NSMutableArray()
func loadData() {
data.removeAllObjects()
var profileQuery:PFQuery = PFUser.query()!
profileQuery.getObjectInBackgroundWithId(userId, block: { (objects, error) -> Void in
if error == nil {
self.data.addObject(objects!)
}
})
println(userId) // this is the userId as String.
println(self.data) ********* // empty array.
}
i am getting an empty array data here.. I've tried this also but same thing's happening here too. :
var profileQuery:PFQuery = PFUser.query()!
profileQuery.whereKey("objectId", equalTo: userId)
profileQuery.findObjectsInBackgroundWithBlock { (objects, error) -> Void in
if let objects = objects {
for object in objects {
self.data.addObject(object)
}
}
}
Remember that "findObjectsInBackgroundWithBlock" happens async! You need to put any logic pertaining to the data inside of the block.
var profileQuery:PFQuery = PFUser.query()!
profileQuery.getObjectInBackgroundWithId(userId, block: { (objects, error) -> Void in
if error == nil {
self.data.addObject(objects!)
println(self.data) //shouldn't be empty.
}
})
Putting aside why you're using an NSMutableArray for a singular PFUser object—you're basically expecting to see self.data populated in the wrong location. The user would be added to it (assuming a successful retrieval), inside the closure. So do something like:
var data:NSMutableArray = NSMutableArray()
func loadData() {
data.removeAllObjects()
var profileQuery:PFQuery = PFUser.query()!
profileQuery.getObjectInBackgroundWithId(userId, block: { (objects, error) -> Void in
if error == nil {
self.data.addObject(objects!)
println(self.data) //...shouldn't be empty here
} else {
println("Error retrieving user: \(error.description")
}
})
}

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 {
...
}

Swift - Creating a Parse Class with an Object that is a Pointer to an object in another class

Excuse me if this is already explained somewhere in Swift, I know it is simple but I simply can't find the answer anywhere.
So essentially my problem is that I have a class in Parse called "Groups" that has a "title" object in it. Then in the code below, I am creating a new class called "RankedItems" that has it's own objects. One of the objects is "groupOwner" and the objective here is to assign it to a pointer to the "title" object in the "Groups" class.
My code is listed below. Clearly I have the wrong syntax in the line of code that attempts to create "groupOwner", I have been trying everything so I figured I would leave that in as a placeholder.
Can anyone point me in the right direction as to how I should create "groupOwner" as a pointer to an object in the "Groups" class? Thanks!
// Add Parse Group Object
var itemRank:PFObject = PFObject(className: "RankedItems")
itemRank["itemName"] = newItem
itemRank["groupOwner"] = PFObject(withoutDataWithClassName: "Groups", objectId: "title")
itemRank.saveInBackgroundWithBlock {
(success: Bool, error: NSError!) -> Void in
if (success) {
} else {
// There was a problem, check error.description
println("Error adding group to parse")
}
}
self.typedItems.append(newItem)
self.tableView.reloadData()
}))
try this
// Add Parse Group Object
var itemRank:PFObject = PFObject(className: "RankedItems")
itemRank["itemName"] = newItem
itemRank["groupOwner"] = PFObject(withoutDataWithClassName: "Groups", objectId: PFUser.current()?.objectId)
itemRank.saveInBackgroundWithBlock {
(success: Bool, error: NSError!) -> Void in
if error == nil {
if success {
// saved successfully
} else {
// not error, and not saved for some reason... it could be impossible to reach this point
}
} else {
// There was a problem, check error.description
println("Error adding group to parse")
}
}
self.typedItems.append(newItem)
self.tableView.reloadData()
}))
I corrected
objectId: "Title"
to
objectId: PFUser.current()?.objectId

Resources