How to prevent Parse from saving PFObject children's?
I'm facing a very common issue with Parse and iOS.
I have a class POST with the following structure:
text(String)
Image (PFFile)
LikesUsers (Array of String)
LikesCount (Int)
From (Pointer to User who posted it)
and if the user (already logged in) likes a post. I'm just incrementing the likes and the add Objectid of the user to the array
For example : User-2 likes User-1's Post.
PostObject.incrementKey("Likes")
PostObject.addObject((PFUser.currentUser()?.objectId)!, forKey: "LikesUsers")
PostObject.saveEventually()
The issue is here. I can't save a the PostObject as long as it has a pointer to another user (than the logged in) I'm getting the error :
User cannot be saved unless they have been authenticated via logIn or signUp
So how to prevent from saving the ParseObject Children ("From")
I don't want to use a CloudCode, I want to keep it simple and to Use SaveEventually for a better user experience.
From the parse.com forums:
When you save an object with a pointer, Parse looks at the entirety of the object and saves the fields that are "dirty" (changed since last save). It also inspects all the objects being pointed to by pointers. If your object has a pointer to PFUser and the instance of the PFUser is "dirty", then Parse will save the object and then attempt to save the instance of the PFUser as well. My hypothesis is that somewhere in your code you are setting a value on a user and then not saving the user. This, I suspect, is the source of your error. Go through your code and look for anywhere you set a PFUser instance and make sure there's a corresponding save. If you can't find it at first glance, be sure to check all blocks and ensure that you are not asynchronously dirtying a user and subsequently trying to save it.
Are you trying to make any changes to the user that the post was made by?
Short answer:
Try to set from
field as:
let author = PostObject["from"] as! PFObject
PostObject["from"] = PFObject(withoutDataWithClassName: "_User",
objectId: author.objectId)
This is not tested.
But I suggest you to change the architecture
I was facing the same problem and finally decided to move likes
field to User
class instead and make it Relation<Post>
type. Parse documentation says that Relation
type is better for keeping many objects. Since LikesUsers
is an array of objects, the performance may drop significantly if a post will get many likes: the app will download all the users liked this post. See this for more info: https://parse.com/docs/ios/guide#objects-relational-data
Here is how my class structure looks like (simplified):
User:
Post:
I also moved like/dislike logic to CloudCode function:
/// The user liked or disliked the post.
Parse.Cloud.define("likeDislikePost", function(request, response) {
var userProfileId = request.params.userProfileId
var postId = request.params.postId
// Shows whether the user liked or disliked the post. Bool value
var like = request.params.like
var query = new Parse.Query("_User");
query.equalTo("objectId", userProfileId);
query.first({
success: function(userProfile) {
if (userProfile) {
var postQuery = new Parse.Query("Post");
postQuery.equalTo("objectId", postId);
postQuery.first({
success: function(post) {
if (post) {
var relation = userProfile.relation("postLikes");
if (like) {
relation.add(post);
post.increment("likesCount");
}
else {
relation.remove(post)
post.increment("likesCount", -1);
}
post.save();
userProfile.save();
console.log("The user with user profile id " + userProfileId + " " + (like ? "liked" : "disliked") + " the post with id " + postId);
response.success();
}
else {
response.error("Unable to find a post with such ID");
}
},
error: function() {
response.error("Unable to like the post");
}
});
}
else {
response.error("Unable to find a user profile with such ID");
}
},
error: function() {
response.error("Unable to like the post");
}
});
});
Works just fine.
I created some project from scratch for you. I think you miss some thing when you are creating your PFClass. I don't know. Whatever look my codes,
This is the ViewController
and it contains like Button Action ;
import UIKit
class ViewController: UIViewController {
private let test = Test() // PFObject SubClass
private let post = Post() // PFObject SubClass
@IBAction func likeButton() {
self.test.fromUser = PFUser.currentUser() // Current User
self.test.likedUsers.append(Post().user // In there your post should be a Subclass of PFObject too like your this Test class and it should be contains Owner property. So you can grab the Post owner PFUser or User Object ID.)
self.test.saveEventually() {
(let success, error) in
if error == nil {
// Success
} else {
print(error?.localizedDescription)
}
}
}
}
In your AppDelegate
init your ParseSDK and Register your new Parse subclasses.
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
Parse.setApplicationId("YOUR_API_KEY", clientKey: "YOUR_CLIENT_KEY")
Test.registerSubclass()
Post.registerSubclass()
return true
}
Test Subclass ;
import Foundation
import Parse
class Test: PFObject, PFSubclassing {
// Your Properties
@NSManaged var likedUsers: [PFUser]
@NSManaged var fromUser: PFUser
static func parseClassName() -> String {
return "Test" // Your Class Name
}
}
Post Subclass ;
class Post: PFObject, PFSubclassing {
// Your Properties
@NSManaged var owner: PFUser
@NSManaged var likeCount: NSNumber
static func parseClassName() -> String {
return "Post" // Your Class Name
}
}
In my case it works fine. If you get an error please inform me.
Have a nice coding.
链接地址: http://www.djcxy.com/p/90572.html