I'm trying to delete a saved Object in Parse and Replace it. My code is not working. My Parse Database is only adding objects with the same array name. Here is my code.......
#IBAction func finalSaveBTN(sender: AnyObject)
{
videoARY = [videoId, vidTitleText, vidDescription, vidIMG]
let videoSave = PFObject(className: "UserVideos")
videoSave.deleteInBackgroundWithBlock { (success, error) -> Void in
if success == true
{
videoSave["userObjectId"] = PFUser.currentUser()!.objectId
videoSave["vid\(self.saveValueLBL.text!)"] = self.videoARY
videoSave.saveInBackgroundWithBlock { (success, error ) -> Void in
if success == true
{
print("Succesfull")
}
}
}
else
{
print("Error")
}
}
}
I would like to delete the object, but if anyone knows how to successfully update a Parse array that'll help too. Thank you.
*** UPDATE ****
I'm trying this, not working either, what could be wrong....
#IBAction func finalSaveBTN(sender: AnyObject)
{
videoARY = [videoId, vidTitleText, vidDescription, vidIMG]
let videoSave = PFObject(className: "UserVideos")
let query = PFQuery(className: "UserVideos")
query.whereKey("userObjectId", equalTo: PFUser.currentUser()!.objectId!)
query.findObjectsInBackgroundWithBlock {
(objects: [AnyObject]?, error: NSError?) -> Void in
for object in objects!
{
let vid = object["vid\(self.saveValueLBL.text!)"]!
vid!.delete()
}
}
videoSave["userObjectId"] = PFUser.currentUser()!.objectId
videoSave["vid\(self.saveValueLBL.text!)"] = self.videoARY
videoSave.saveInBackgroundWithBlock { (success, error ) -> Void in
if success == true
{
print("Succesful")
}
}
}
**** UPDATE *****
I'm deleting all vids for videoSave. If you have any suggestions on how to target specific array I'll appreciate it. I'll try to rework and save as simply PFFile
#IBAction func finalSaveBTN(sender: AnyObject)
{
videoARY = [videoId, vidTitleText, vidDescription, vidIMG]
let videoSave = PFObject(className: "UserVideos")
let query = PFQuery(className: "UserVideos")
query.whereKey("userObjectId", equalTo: PFUser.currentUser()!.objectId!)
query.findObjectsInBackgroundWithBlock {
(objects: [AnyObject]?, error: NSError?) -> Void in
for object in objects!
{
if let vid = object["vid\(self.saveValueLBL.text!)"]!
{
vid.deleteInBackground()
vid.saveInBackground()
}
}
}
videoSave["userObjectId"] = PFUser.currentUser()!.objectId
videoSave["vid\(self.saveValueLBL.text!)"] = self.videoARY
videoSave.saveInBackgroundWithBlock { (success, error ) -> Void in
if success == true
{
print("Succesful")
}
}
There're a few obstacles here, let me walk you through them.
1:
let videoSave = PFObject(className: "UserVideos")
videoSave.deleteInBackgroundWithBlock {...}
The first problem is that you're trying to delete a brand new object you're creating, which hasn't been saved to the server yet. That's what let ... = PFObject(className:...) does, it creates a new object.
2: Updating parse arrays is really easy! If you have the object in your code, you can simply change your object with functions like, or , and then use .saveInBackgroundWithBlock, and Voila! If you don't have the object, you'll need to first create a version of your object without the data from the server, and then have it fetch it's info from your parse server, and THEN you can modify, and save it. Here's how you'd do those two things
PFObject(withoutDataWithObjectId: objectId)
PFObject().fetchIfNeededInBackgroundWithBlock({})
Finally, if you don't have the objectId of your object, then you'll have to find it using a PFQuery, and then using there .whereKey(...) to filter until found.
3: Are you aware that by calling videoSave["vid\(self.saveValueLBL.text!)"] = self.videoARY, you're saving to a column in your parse server named vid+the string of self.saveValueLBL.text!? You might be creating parse columns on the fly. Just a heads up!
4: Another problem is the videoSave["vid\(self.saveValueLBL.text!)"] = self.videoARY line. You can't save arrays of PFFiles. You'll have to keep that information in a separate column, with the designated type of PFFile.
5: In your new block of code, I don't think delete() works the way you think it does. If you wanna delete the entire object, use object.deleteInBackground(), if you just wanna delete an attribute of that object, you can use object.removeObjectForKey(...), and then object.saveInBackground().
Does this all make sense?
I didn't have to turn my array into a PFFile. I simply needed to add a second query. Basically I was querying all vids for current user. Addition of query.whereKeyExists narrowed it down to specific vid. It will also make my retrieving query easier. Here it is........
#IBAction func finalSaveBTN(sender: AnyObject)
{
videoARY = [videoId, vidTitleText, vidDescription, vidIMG]
let query = PFQuery(className: "UserVideos")
query.whereKey("userObjectId", equalTo: PFUser.currentUser()!.objectId!)
query.whereKeyExists("vid\(self.saveValueLBL.text!)")
query.findObjectsInBackgroundWithBlock {
(objects: [AnyObject]?, error: NSError?) -> Void in
for object in objects!
{
object.deleteInBackground()
object.saveInBackground()
}
}
let videoSave = PFObject(className: "UserVideos")
videoSave.setObject(self.videoARY, forKey: "vid\(self.saveValueLBL.text!)")
videoSave["userObjectId"] = PFUser.currentUser()!.objectId
videoSave.saveInBackgroundWithBlock { (success, error ) -> Void in
if success == true
{
print("Succesful")
}
}
}
Related
I've spent a few hours trying to get a fetch to work in my film sheet. I need to open film's View of my colectionview Items. I could follow different guide and post but it always give me an empty array. I'm newbie, sorry for my question but I need your help.
Here's my code:
var taskArrayScheda : NewFilm?
override func viewDidLoad() {
super.viewDidLoad()
self.fetchData()
if(self.taskArrayScheda != nil) {
let schedaOk = taskArrayScheda
mostraDatiNellaScheda(schedaOk!)
} else { print("errore array vuoto") }
}
func mostraDatiNellaScheda(_ sched:NewFilm) {
// get title
titoloScheda.text = sched.titolo
}
func fetchData() {
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "NewFilm")
do {
taskArrayScheda = try context.fetch(NewAnime.fetchRequest())
💥ERROR ::::: Cannot assign value of type '[Any]' to type 'NewFilm?'
} catch {
print(error)
}
}
The fetch() returns an array. But currently you assign the fetch() result to the single object var taskArrayScheda.
You'll need something like:
var taskArrayScheda: [NewFilm]?
Then you should do:
taskArrayScheda = try context.fetch(NewAnime.fetchRequest()) as? [NewFilm]
I assume here that NewAnime is a subclass of NewFilm, which seems to make sense looking at these two class names.
I am trying to load, then modify and resave an array.
Here is code, modify func is the top one:
func modifyUserGroupsRequestee(){
print("step2")
acceptedUsersArray.append(groupNameLbl.text!)
//error
userGroupRecordToUpdate.setObject(acceptedUsersArray as CKRecordValue?, forKey: "userGroups")
database.save(recordToUpdate) { (savedRecord, error) in
if error != nil{
print(error.debugDescription)
}else{
print("SAVED RECORD")
}
}
}
func resaveUserGroups(){
print(addedUser)
print("step1")
// add group to requestees user groups
let pred = NSPredicate(format: "username = %#", "\(addedUser)")
let query = CKQuery(recordType: "PersonalUser", predicate: pred)
let operation = CKQueryOperation(query: query)
//operation.resultsLimit = CKQueryOperationMaximumResults
operation.recordFetchedBlock = { (record: CKRecord!) in
if record != nil{
self.userGroupRecordToUpdate = record
// self.acceptedUsersArray = (record.object(forKey: "userGroups") as! Array)
print("usergroup names:: \(self.acceptedUsersArray)")
if let acceptedUserArrays = record.object(forKey: "userGroups") as? [String] {
// self.feedTableView.reloadData()
self.acceptedUsersArray = acceptedUserArrays
print("looks like we r going forward")
self.modifyUserGroupsRequestee()
// }
//self.feedTableView.reloadData()
print(groupNames.count)
print(self.acceptedUsersArray)
}
}
database.add(operation)
//self.tableView.reloadData()
// print(leaderboardInfo.count)
}
}
The function prints step1 but never gets to step2. In the bottom function, I have an if let statement I tried to create to solve my nil issue (I commented my previous code above that line- self.acceptedUsersArray... Anyway, I believe I am implementing the if let statement incorrectly, because no data is loaded, even though there is data in cloud kit.
And I do have my personal user cloudKit records set up, here's a pic:
You should try to keep your code always indented consistently.
(In Xcode editor, Cmd+A (Select All), then Ctrl+I (Re-Indent).)
With confusing comments removed, your resaveUserGroups shows as:
func resaveUserGroups() {
print(addedUser)
print("step1")
// add group to requestees user groups
let pred = NSPredicate(format: "username = %#", "\(addedUser)")
let query = CKQuery(recordType: "PersonalUser", predicate: pred)
let operation = CKQueryOperation(query: query)
operation.recordFetchedBlock = { (record: CKRecord!) in
if record != nil {
self.userGroupRecordToUpdate = record
print("usergroup names:: \(self.acceptedUsersArray)")
if let acceptedUserArrays = record.object(forKey: "userGroups") as? [String] {
self.acceptedUsersArray = acceptedUserArrays
print("looks like we r going forward")
self.modifyUserGroupsRequestee()
print(groupNames.count)
print(self.acceptedUsersArray)
}
}
database.add(operation)
}
}
Omitting some parts to clarify:
func resaveUserGroups() {
//...
operation.recordFetchedBlock = { (record: CKRecord!) in
if record != nil {
//...
}
database.add(operation)
}
}
The line database.add(operation) exists inside the recordFetchedBlock.
You may need to fix some more parts (that's another story), but at least, you need to move the line out of the closure to execute the operation you have created:
func resaveUserGroups() {
//...
operation.recordFetchedBlock = { (record: CKRecord!) in
if record != nil {
//...
}
//database.add(operation)
} //↓
database.add(operation)
}
I just solved it. Apparently there always needs to be some kind of value inside the array even if it was just created. I was trying to query an array that existed in the recordType, but not yet under the specific record.
I am working with Parse and would like to download images for offline use. I understand that this is not possible with Local Datastore so I have decided to add them to Core Data.
I have successfully downloaded the PFFiles and put them in to an Array. I am then trying to create an Array for the NSData, but the Array count is always 0 when I use the code below
class DealsDownloadViewController: UIViewController {
#IBOutlet weak var imageView: UIImageView!
var trailID = [Int]()
var trailStep = [Int]()
var dealNumber = [Int]()
var imageFile = [PFFile]()
var imagesArray = [UIImage]()
var imageDataArray = [NSData]()
var number = 0
override func viewDidLoad() {
super.viewDidLoad()
let appDel: AppDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let context: NSManagedObjectContext = appDel.managedObjectContext
let dealsQuery = PFQuery(className: ("Deals"))
dealsQuery.orderByAscending("TrailId")
dealsQuery.findObjectsInBackgroundWithBlock { (objects, error) -> Void in
if let objects = objects {
for object in objects {
self.trailID.append(object["TrailID"] as! Int)
self.trailStep.append(object["TrailStep"] as! Int)
self.dealNumber.append(object["dealNumber"] as! Int)
self.imageFile.append(object["dealImage"] as! PFFile!)
}
for file in self.imageFile {
let dealImage = file
dealImage.getDataInBackgroundWithBlock({ (imageData: NSData?, error: NSError?) -> Void in
if error == nil {
let image = UIImage(data: imageData!)
self.imageDataArray.append(imageData!)
self.imagesArray.append(image!)
} else {print("error here")}
})
print(self.trailID.count)
print(self.trailStep.count)
print(self.dealNumber.count)
print(self.imageDataArray.count)
print(self.imagesArray.count)
}
} else {print("problem making arrays")}
}
}
If I move the Print statement up, I just get it printing every iteration of the loop.
for file in self.imageFile {
let dealImage = file
dealImage.getDataInBackgroundWithBlock({ (imageData: NSData?, error: NSError?) -> Void in
if error == nil {
let image = UIImage(data: imageData!)
self.imageDataArray.append(imageData!)
self.imagesArray.append(image!)
} else {print("error here")}
print(self.trailID.count)
print(self.trailStep.count)
print(self.dealNumber.count)
print(self.imageDataArray.count)
print(self.imagesArray.count)
})
}
} else {print("problem making arrays")}
}
}
In this case I can see that the data is added to both the imagesArray and imageDataArray.
This seems like such a simple issue but I am going crazy over it. What am I doing wrong, and is this the most efficient way of adding this data to Core Data? Am I overlooking something obvious?
I am new to programming so please do point out any mistakes I have made, and I am especially new as a questioner to stackoverflow (you have been indispensable while learning) so please let me know if you need any information that I have missed.
Thanks for your help.
Update 1
I have tried editing the code as explained in the comments and I am still getting the same result. I have moved the Print statement around on this code and it is still giving me the same results as above.
for file in self.imageFile {
let dealImage = file
dealImage.getDataInBackgroundWithBlock({ (imageData: NSData?, error: NSError?) -> Void in
if error == nil {
weak var aBlockSelf = self
let image = UIImage(data: imageData!)
aBlockSelf!.imageDataArray.append(imageData!)
self.imagesArray.append(image!)
}
print(self.trailID.count)
print(self.trailStep.count)
print(self.dealNumber.count)
print(self.imageDataArray.count)
print(self.imagesArray.count)
})
}
} else {print("problem making arrays")}
}
}
Am I missing something very simple? Thanks again for your help.
Update 2
This is the same code with (I think) the print statements moved outside of the For Loop. This is giving me counts of 9,9,9,0,0 from the print statements, whereas I think I should be expecting 9,9,9,9,9.
for file in self.imageFile {
let dealImage = file
dealImage.getDataInBackgroundWithBlock({ (imageData: NSData?, error: NSError?) -> Void in
if error == nil {
weak var aBlockSelf = self
let image = UIImage(data: imageData!)
aBlockSelf!.imageDataArray.append(imageData!)
self.imagesArray.append(image!)
}
})
}
print(self.trailID.count)
print(self.trailStep.count)
print(self.dealNumber.count)
print(self.imageDataArray.count)
print(self.imagesArray.count)
} else {print("problem making arrays")}
}
}
There is no issue here!
You are being deceived by the way asynchronous block works. Asynchronous block gets queued up to get executed some point later in next run loop.
Your first print statement is just after you pass the code to block which is yet to be executed. Which is why you do see your image array empty.
I have an array of items in a column in Parse.
I am able to fetch that array with the code :
let query:PFQuery = PFQuery(className: "Names")
query.whereKey("date", greaterThan: NSDate())
query.findObjectsInBackgroundWithBlock {
(object, error) -> Void in
if object != nil
{
if(object!.count != 0)
{
for messageObject in object! {
self.arrayNames = ((messageObject as! PFObject)["arrayNames"] as? [String])!
}
} else {
print("No Objects")
}
}
} // self.arrayNames = ["Aruna", "Bala", "Chitra", "Divya"]
In this I want to delete an single item and again save it to the parse.
I can delete it locally as removeAtIndex but how can I remove that from Parse?
After you have retrieved your array, remove the one item you do not want, reassign the new array to the retrieved object and then save.
In the names, if I wanted to delete Aruna,
self.arrayNames.removeAtIndex(0)
Then to update this array in Parse,
let query:PFQuery = PFQuery(className: "Names")
query.whereKey("date", greaterThan: NSDate())
query.findObjectsInBackgroundWithBlock {
(object, error) -> Void in
if object != nil {
object!.setValue(self.arrayNames, forKey: "arrayNames")
object!.saveInBackgroundWithBlock {
(success: Bool, error: NSError?) -> Void in
if(success) {
print("Success")
} else {
print("Error")
}
}
}
}
I found that, i cant directly delete an single element from an array in a column in Parse. So I am updating that array with my local array. It works!
If you read the docs you will find one of the delete methods useful such as deleteInBackgroundWithBlock:
object.deleteInBackgroundWithBlock { (succeeded: Bool, error: NSError?) -> Void in
// do whatever you need to do
}
var titles = [String]()
var descriptions = [String]()
func retrieveData () {
var query = PFQuery(className: "Main")
// get the actual data
query.getFirstObjectInBackgroundWithBlock {
(object: PFObject?, error: NSError?) -> Void in
if error != nil || object == nil {
println("Error retrieving data")
} else {
self.titles.append(object["Labels"] as! String) // ERROR!
self.descriptions.append(object["desc1"] as! String) // ERROR!
}
}
}
I have 2 arrays and I want to retrieve data from Parse and add it to those arrays, but I get this error:
Cannot invoke 'append' with an argument list of type '(String)'
What am I doing wrong ?
Edit: this is what I get when I println(object) :
Optional(<Main: 0x7fc24b84e410, objectId: jy7LrEOMk0, localId: (null)> {
Labels = labels;
desc1 = desc1;
desc2 = desc2;
desc3 = desc3;
desc4 = desc4;
desc5 = desc5;
})
Message from debugger: got unexpected response to k packet: OK
After spending several hours trying & searching, this is the correct answer:
self.titles.append(object?.objectForKey("Labels") as! String)
self.descriptions.append(object?.objectForKey("desc1") as! String)
The answer is so simple, but somehow the Parse.com docs don't have a single sample of it. Anyway I hope that helps anyone else who may get stuck at the same problem.