Save current user's message list in parse with swift - ios

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

Related

Delete a row from a class in Parse - In Swift

I'm trying to make some voting buttons for my film app.
I use Parse, and I've created a new class called Votes_Up. In this class their are 2 columns: User_Voting and Film_VotedFor.
My code below is actioned when the button is pressed. It takes the currentUser and the film object that the button has been pressed against, and adds them to Parse. My database looks like this:
What I need
so they way it currently works, if the user presses the vote button, it adds the info to the DB and adds 1 to the count. When the user presses it again, it just updates the count by taking 1 away.
I would also want to remove the row it would have added to the database, By the User that voted for it. How can I do this??
My code:
#IBAction func upVoteButton(sender: UIButton) {
let hitPoint = sender.convertPoint(CGPointZero, toView: self.tableView)
let hitIndex = self.tableView.indexPathForRowAtPoint(hitPoint)
let object = objectAtIndexPath(hitIndex)
if PFUser.currentUser() != nil {
if userPressedUpButton == false {
userPressedUpButton = true
let voteUp = PFObject(className: "Votes_Up")
voteUp["User_Voting"] = PFUser.currentUser()
voteUp["Film_VotedFor"] = object!
object!.incrementKey("UpVoteCount")
object!.saveInBackground()
voteUp.saveInBackgroundWithBlock({ (success, error) in
if success == true {
// Object(s) was/were successfully saved
} else if error != nil {
// Display an alert to the user
} else {
// Display an alert to the user - something went wrong
}
})
} else {
userPressedUpButton = false
// I need to removed the row from the class here that was added, as the user has retracted their vote!
object!.incrementKey("UpVoteCount", byAmount: -1)
object!.saveInBackground()
}
} else {
// No user is logged in so they can't vote
performSegueWithIdentifier("Votes_LoginPopup", sender: self)
}
self.tableView.reloadData()
}
Try this:
var query = PFQuery(className:"Votes_Up")
query.whereKey("User_Voting", equalTo:PFUser.currentUser())
query.limit = 1
query.findObjectsInBackgroundWithBlock {
(votesUp: [AnyObject]?, error: NSError?) -> Void in
if error == nil {
if let objects = votesUp as? [PFObject] {
var firstObject = objects[0]
dispatch_async(dispatch_get_main_queue(),{
// do delete here
firstObject.deleteEventually();
})
}
}
}
or this:
let query = PFQuery(className: "Votes_Up")
query.whereKey("User_Voting", equalTo: PFUser.currentUser())
query.findObjectsInBackgroundWithBlock {
(objects: [AnyObject]?, error: NSError?) -> Void in
for object in objects {
object.deleteEventually()
}
}

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!")
}
}

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)
}
}

swift - retrieve objectId field causes fatal error

Here is my code:
#IBAction func saveSettings(sender: AnyObject) {
var settings:PFObject = PFObject(className: "Settings")
settings["routes"] = routesSetting as String
settings["sortBy"] = sortBySetting as String
settings["user"] = PFUser.currentUser()
settings.saveInBackgroundWithBlock{(success:Bool!, error:NSError!) ->Void in
if success != nil {
NSLog("%#","OK-settings data saved")
NSLog("%#",self.routesSetting as String)
}
else
{
NSLog("%#",error)
}
}
}
#IBAction func updateSettings(sender: AnyObject) {
var settings:PFObject = PFObject(className:"Settings")
var id = settings["objectId"] as String
var query = PFQuery(className:"Settings")
println(settings)
println(id)
println(query)
query.getObjectInBackgroundWithId(id) {
(settings: PFObject!, error: NSError!) -> Void in
if error != nil {
NSLog("%#", error)
} else {
settings["routes"] = self.routesSetting as String
settings["sortBy"] = self.sortBySetting as String
settings.save()
}
}
I can run the saveSettings code with no issues. I have set it up to run when a new user signs up with the application. I have verified that a new row is inserted into the settings table in the Parse cloud DB. But I would now like to simply UPDATE the single row instead of create a new row every time there is a save. So I have been working on the updateSettings function. I have followed the Parse documentation for updating objects (https://parse.com/docs/ios_guide#objects-updating/iOS). When I click on the Update button to run the function, I get:
fatal error: unexpectedly found nil while unwrapping an Optional value
(lldb)
The line it points to is:
var id = settings["objectId"] as String
I am a complete beginner to Parse.
Some recent additional information:
The results of the println statements:
<Settings: 0x7fd423805260,
objectId: new, localId: (null)> {
}
nil
<PFQuery: 0x7fd4217191f0>
So part of the problem is it is not retrieving the objectId?
PFObject has a property called "objectId", it is not stored in a dictionary, so you can return it as
var id = settings.objectId

Swift + Parse.com : how to fetch user relation using a join table

I have an app like instagram where i have to make relationship between users.
For that i decided to use the join table method.
It'' s just a table named "Activity" where i created rows "fromUser", "toUser" and a row for the activity type "type" which in this case is set to "followingAction".
Here how i set up the table :
var activity = PFObject(className:"Activity")
let currentUser = PFUser.currentUser()
let follow : String = "followingAction"
activity.setObject(currentUser, forKey: "fromUser")
activity.setObject(user, forKey: "toUser") // user is a another PFUser in my app
activity.setObject(follow, forKey: "type")
activity.saveEventually()
Ok, now i want to fetch all users that i m currently following (currentUser) and display them in a tableView
Following the doc https://parse.com/docs/relations_guide#manytomany-jointables
i made this but it only give me an array of users which only contain the user objectId, i can't have the email, name which are set up in the regular User table :
func loadUser () {
followingUserList.removeAllObjects()
let findUserObjectId = PFQuery(className: "Activity")
findUserObjectId.whereKey("fromUser", equalTo: userPassed)
findUserObjectId.whereKey("type", equalTo: "followingAction")
findUserObjectId.findObjectsInBackgroundWithBlock { (objects:[AnyObject]!, error:NSError!) -> Void in
if error == nil {
// The find succeeded.
println("succesfully loaded the fromUser in Activity class")
// Do something with the found objects
for object in objects {
let user : PFUser = object["toUser"] as PFUser
self.followingUserList.addObject(user)
println("User added to following user list : \(user)")
println("followingUserlist = \(self.followingUserList)")
self.tableView.reloadData()
} } else {
// Log details of the failure
println("error loadind user ")
println(error)
}
}
}
if i print the followingUserList which is the array where i put the fetched users, here is what i have :
followingUserlist = (
"<PFUser: 0x7d9b93c0, objectId: DQJihBpW5E, localId: (null)> {\n}"
)
When i make a regular query (PFUser.query()) for the regular User table, i have more detail :
ex :
<PFUser: 0x7db5af80, objectId: niwftRrB5x, localId: (null)> {
backgroundImage = "<PFFile: 0x7db5f080>";
email = "kiki#kiki.com";
emailVerified = 0;
profileImage = "<PFFile: 0x7db62910>";
username = kiki;
}
Here we can see i have the complete PFUser with it email, username etc etc.
Because the "fromRow" in my "Activity" table is a pointer to my regular User table, why the fetched result in my loadUser() method isn't complete ?
Ok i finally found the solution, i just used the getObjectInBackgroundWithId method like this :
func loadUser () {
followingUserList.removeAllObjects()
let findUserObjectId = PFQuery(className: "Activity")
findUserObjectId.whereKey("fromUser", equalTo: userPassed)
findUserObjectId.whereKey("type", equalTo: "followingAction")
findUserObjectId.findObjectsInBackgroundWithBlock { (objects:[AnyObject]!, error:NSError!) -> Void in
if error == nil {
// The find succeeded.
println("succesfully loaded the fromUser in Activity class")
// Do something with the found objects
for object in objects {
let user : PFUser = object["toUser"] as PFUser
let queryUsers = PFUser.query()
queryUsers.getObjectInBackgroundWithId(user.objectId, block: { (userGet :PFObject!,error : NSError!) -> Void in
self.followingUserList.addObject(userGet)
self.tableView.reloadData()
})
} } else {
// Log details of the failure
println("error loadind user ")
println(error)
}
}
}

Resources