parse.com Updating object creates new object ID - parse-platform

I am new to Parse. I am trying to update a object already saved on the parse backend. I use the getObjectInBackgroundWithID and supply the object ID. When I try and update with new data the app tells me it successfully save a new record and when i look on the backend, I now have two records with different object ID's. Below is my code in the update button. In my app it passes in the object ID, but I have tried hard coding the object ID with the same result.
#IBAction func updateAccountPressed(sender: AnyObject) {
let query = PFQuery(className:"Accounts")
query.getObjectInBackgroundWithId("dS7fHCoabI") {
(accountInfo: PFObject?, error: NSError?) -> Void in
if error != nil {
print(error)
} else if let accountInfo = accountInfo {
accountInfo["Type"] = self.pickedAccontType
accountInfo["NumberOrNickname"] = self.accountNumNickname.text
accountInfo["InitialBalance"] = self.initialBalance.text
accountInfo.saveInBackground()
}
}

When you do
...
} else if let accountInfo = accountInfo {
...
You are actually creating a new variable called accountInfo and assigning the object you fetched to it. You are then calling the saveInBackground() method on a new PFObject you just created, thus creating a new record in Parse. Just change your if statement:
if error != nil {
print(error)
} else {
accountInfo["Type"] = self.pickedAccountType
accountInfo["NumberOrNickname"] = self.accountNumNickname.text
accountInfo["InitialBalance"] = self.initialBalance.text
accountInfo.saveInBackground()
}

It turns out I had somehow linked my updated button with both my update and the add func. After removing the link it updates fine with no new objectID.

Related

I'm trying to delete a record out of Core Data in xCode 8/Swift 3 & latest core data syntax

I'm trying to delete an entire record out of coreData. I've retrieved the data and placed it in an array for manipulation (I have another function that lets the user edit the data using this method and it works fine) But I can't figure out how to just delete the record. [.remove(at: index)] doesn't work and neither does the code below. I can set all the fields to empty but that's not what I want, I want the record gone completely.
I went through the solutions given for similar problems but to no avail
#IBAction func Delete(_ sender: UIButton) { // The delete function
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "DestinationsOne")
let context = appDelagate.persistentContainer.viewContext
var destArray = [DestinationsOne]() // The data array
do {
try destArray = context.fetch(request) as! [DestinationsOne]} //Fetching the data and placing it in the array
catch{
//error message
}
for index in (0..<destArray.count - 1){ //Go through the records
if destArray[index].destID == IDTitle!{ //Picks the record to edit
let object = destArray[index]
context.delete(object
}
appDelagate.saveContext()
}
I figured this one out. I'm posting the solution in case anyone else has the same question
func deleteRecords() -> Void { //The function to delete the record
let moc = getContext()
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "DestinationsOne")
let result = try? moc.fetch(fetchRequest)
let resultdata = result as! [DestinationsOne] // result as entity
for object in resultdata { // Go through the fetched result
if object.destID == self.IDTitle{ // If there is a match
moc.delete(object) // delete the object
}
}
do {
try moc.save() // Save the delete action
} catch let error as NSError {
print("Could not save \(error), \(error.userInfo)")
} catch {
}
}
func getContext () -> NSManagedObjectContext {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
return appDelegate.persistentContainer.viewContext
}
deleteRecords() // Call the function
Why not applying a predicate to search this particular record. It's much more efficient than looping through a huge list.
func deleteRecords() { //The function to delete the record
let moc = getContext()
let fetchRequest = NSFetchRequest<DestinationsOne>(entityName: "DestinationsOne")
let predicate = NSPredicate(format: "destID == %#", self.IDTitle)
fetchRequest.predicate = predicate
do {
let resultdata = try moc.fetch(fetchRequest) // no type cast needed
if let objectToDelete = resultdata.first {
moc.delete(objectToDelete) // delete the object
try moc.save() // Save the delete action
}
} catch {
print("Could not save error: ", error)
}
}
Here are some issues with your code:
viewContext should be treated as readonly - you should use performBackgroundTask for all changes to core-data
You are fetching ALL of the entities and then then going through each one to find the one you want to delete. It is a lot faster to have core-data only fetch the one you want. You can do this by setting a predicate to the fetch request.
Instead of displaying your records by doing a fetch and using the array as a model, it is better to use a NSFetchedResultsController to do the fetch and manage the results. The fetchedResultsController will keep the data in sync when objects are changed, inserted or deleted. It also has delegate methods that will inform you when there are changes so you can update your view.
remove appDelagate.saveContext from your project. Apple's template code is wrong. You should never be writing to the viewContext so you should never have a reason to save it.
where is IDTitle being set? are you sure it is not nil?
(minor) for index in (0..<destArray.count - 1){ can be replaced with for (index, element) in destArray.enumerated() { which is clearer to read.

Swift 2 + Parse: Array index out of range

I have a UITableViewController which is basically a news feed. I have also implemented a pull to refresh feature. However sometimes when I pull to refresh it gives me the error
'Array index out of range'.
I know this means an item it is trying to get does not exist but can you tell me why? Here is my code:
override func viewDidLoad() {
super.viewDidLoad()
refresher = UIRefreshControl()
refresher.attributedTitle = NSAttributedString(string: "Pull to refresh")
refresher.addTarget(self, action: "refresh", forControlEvents: UIControlEvents.ValueChanged)
self.tableView.addSubview(refresher)
refresh()
tableView.delegate = self
tableView.dataSource = self
}
and the refresh() function:
func refresh() {
//get username and match with userId
let getUser = PFUser.query()
getUser?.findObjectsInBackgroundWithBlock({ (objects, error) -> Void in
if let users = objects {
//clean arrays and dictionaries so we don't get indexing error
self.messages.removeAll(keepCapacity: true)
self.usernames.removeAll(keepCapacity: true)
for object in users {
if let user = object as? PFUser {
//make userId = username
self.users[user.objectId!] = user.username!
}
}
}
})
let getPost = PFQuery(className: "Posts")
getPost.findObjectsInBackgroundWithBlock { (objects, error) -> Void in
if let objects = objects {
self.messages.removeAll(keepCapacity: true)
self.users.removeAll(keepCapacity: true)
self.usernames.removeAll(keepCapacity: true)
for object in objects {
self.messages.append(object["message"] as! String)
self.usernames.append(self.users[object["userId"] as! String]!)
self.tableView.reloadData()
}
}
}
self.refresher.endRefreshing()
}
It appears you are removing everything from users and then trying to access it in getPost.findObjectsInBackgroundWithBlock.
Specifically, self.users.removeAll(keepCapacity: true) is called just before self.usernames.append(self.users[object["userId"] as! String]!).
Also, be aware that the two queries execute asynchronously. You have no guarantee that users has been populated when the second query's completion block is reached. You will most likely want to restructure your two queries into one compound query or nest them (not recommended).
Lastly, from the looks of it, you may want to use removeAll(keepCapacity: false) rather than keeping the capacity with removeAll(keepCapacity: true).

Facebook Friend List Save As Array to Parse - Swift

I want to convert the friend list ids that I am getting from facebook as an array to save in parse. My code is as below but I am getting a "unexpectedly found nil while unwrapping an Optional value" error. What should I do to save the result to parse and retrieve it as array when required?
let fbRequest = FBSDKGraphRequest(graphPath:"/me/friends", parameters: nil);
fbRequest.startWithCompletionHandler { (connection : FBSDKGraphRequestConnection!, result : AnyObject!, error : NSError!) -> Void in
if error == nil {
print("Friends are : \(result)")
if let dict = result as? Dictionary<String, AnyObject>{
let profileName:NSArray = dict["name"] as AnyObject? as! NSArray
let facebookID:NSArray = dict["id"] as AnyObject? as! NSArray
print(profileName)
print(facebookID)
}
}
else {
print("Error Getting Friends \(error)");
}
}
When I use the code below in print() I get the result below:
Friends are : {
data = (
{
id = 138495819828848;
name = "Michael";
},
{
id = 1105101471218892;
name = "Johnny";
}
);
The issue is that you are trying to access the name and id elements from the top-level dictionary, where you need to be accessing data.
When you call the FB Graph API for friends it will return an array of dictionaries (one per friend).
Try this:
let fbRequest = FBSDKGraphRequest(graphPath:"/me/friends", parameters: nil)
fbRequest.startWithCompletionHandler { (connection : FBSDKGraphRequestConnection!, result : AnyObject!, error : NSError!) -> Void in
if error == nil {
print("Friends are : \(result)")
if let friendObjects = result["data"] as? [NSDictionary] {
for friendObject in friendObjects {
println(friendObject["id"] as NSString)
println(friendObject["name"] as NSString)
}
}
} else {
print("Error Getting Friends \(error)");
}
}
You should also check out this SO post with more information on the FB Graph API. Here's a brief snippet.
In v2.0 of the Graph API, calling /me/friends returns the person's
friends who also use the app.
In addition, in v2.0, you must request the user_friends permission
from each user. user_friends is no longer included by default in every
login. Each user must grant the user_friends permission in order to
appear in the response to /me/friends. See the Facebook upgrade guide
for more detailed information, or review the summary below.

Set values of a PFObject array to a Swift array

(I'm new to programming and totally new to Parse, so simplified explanations are certainly appreciated)
I imagine this is pretty straightforward; I'm just stuck. I have a PFObject saved in Parse.com that contains an array containing strings. I'm trying to set an array in my Swift app with the values in the Parse array.
var query = PFQuery(className:"ParseHat")
query.getObjectInBackgroundWithId("xxxxxxxxxx")
submittedNames = query["theHat"] as [String]
// submittedNames is declared elsewhere in the code. "theHat" is the key where
the array is stored in the PFobject
I get the error 'PFQuery' does not have a member named 'subscript'. I've tried doing a few things I didn't fully understand to the code but have gotten other errors so I'm just posting this as it seems to most closely resemble the method for retrieving objects in the Parse docs.
Try this out...
var query = PFQuery(className: "ParseHat")
query.getObjectInBackgroundWithId("XXXXXXXXX") {
(objects: PFObject?, error: NSError?) -> Void in
if error == nil {
//fetching users
for object in objects{ //looping through returned data
self.resultsArray.append(object.objectForKey("XXXXXXXX") as! String)
//adding the string to var resultsArray = [String]()
}
} else {
println("error :(")
}
}

finduser query returning nil Parse and swift

I'm trying to find which user commented on the blog post. but it always returns nil and total objects 0, i'm not sure what am i doing wrong. This is my code to get the user's username
var finduser:PFQuery = PFUser.query()
finduser.whereKey("ObjectId", equalTo: commentclass.objectForKey("byuser").objectId)
finduser.findObjectsInBackgroundWithBlock { (objects:[AnyObject]!, error:NSError!) -> Void in
if error == nil {
if let aobjects = objects {
let puser = (aobjects as NSArray).lastObject as? PFUser
cell.userName.text = puser?.username
println(puser) // returns nil
println(aobjects.count) // returns 0
}
}
}
It should be objectId and not ObjectId, also make sure there is no ACL set for the user object that might prohibit the requesting user from seeing this object.

Resources