Save eventually on PFObject with PFFile (Parse Local Datastore)?
Asked Answered
V

2

10

Goal

I am trying to save a PFObject that has a PFFile as an attribute. I am using the new Local Datastore for iOS, so I would like to save this PFObject with the saveEventually() method.

The Problem

The problem I am encountering is that the saveEventually() method doesn't seem to like saving the PFFiles. I tried to saveEventually() my object without any PFFile attached, and that worked fine. As soon as my PFFile was reattached, Xcode threw a couple of breakpoint notices (errors?) but did not terminate the app, and it appears as though all went well - however a check on the Parse Data Browser confirms that the save did not go through.

Prior to the Local Datastore feature I don't believe this save would have been possible - it would have thrown the "Unable to saveEventually a PFObject with a relation to a new, unsaved PFFile." error. It seems as though the Local Datastore feature has fixed this, as it states in the iOS Local Datastore docs:

"Pinning a PFObject is recursive, just like saving, so any objects that are pointed to by the one you are pinning will also be pinned. When an object is pinned, every time you update it by fetching or saving new data, the copy in the local datastore will be updated automatically. You don't need to worry about it at all."

I have updated the SDK to the latest version (v1.6.2). Any ideas?

Viscardi answered 25/1, 2015 at 1:44 Comment(0)
C
6

PFFiles still don't support saveEventually see here

That page was last updated : 2015-01-23

You could pinInBackgroundWithBlock and if successful save the PFFile to a temporary folder in you app bundle and delete it when necessary or unpinned

Crossgrained answered 25/1, 2015 at 2:33 Comment(8)
Shoot! However, your answer led me to discover the workaround: pin the object first, and then saveEventually the object! I can't give you best answer because the answer I came up with is simpler and stays within the Parse SDK, but you definitely deserve an upvote ;) !Viscardi
I spoke too soon. The object appeared in the data browser which led to my excitement, but then I realized the PFFile didn't save. I'm going to try replacing the saveEventually() with a saveInBackground().Viscardi
@Viscardi "stays within the Parse SDK" is neither good nor bad, it just is. You have to realize either way you save it to a temp folder or if you use Parse, they both get stored on the device. Using Parse can be easier, and keeping it within the same environment reduces risk in errors, however, there is no guarantee saveEventually will get called as soon as the app opens, it's also out of your control when it does get called. So saveInBackground is probably the best choice since it's guaranteed at that point in time, and works, plus cross-referened with reachability limits potential faults.Crossgrained
I was just saying it felt easier for me to try and use Parse than hack my own solution, and I was wondering if save eventually worked now with the introduction of the data store. But you're totally right. I realized that not knowing when the save goes through wouldn't be a good idea in my situation.Viscardi
A newer question had an answer similar to yours that added a file path to the PFObject: #28136675Viscardi
Yeah it's a good discussion @Viscardi I haven't read the other question, but actually it's not that much of a hack. You have complete control of where the file goes since your the one doing it and no more than 12 lines of code. But I'll tell you when Facebook bought parse a while back I got nervous a lot of core services would be changed to better suit Facebook so I tried Kinvey in my new app but keep parse in another too just to try it and so far it's pretty good. You should look into it. Pros and cons to both agencies though of course.Crossgrained
Very interested to see a generic solution for this topic.Brumbaugh
@Brumbaugh the issue to this question was answered. Saving files locally to a device is short of being on the Internet, you can find examples everywhere pinning the attributes or properties to a PFObject is also visible. I just simply offered an alternative or suggestion, doesn't mean it's the only workaround. However, since this particular issue (lack of saveEventually support) has been answered I would recommend posting a new question topic on SO so future answer seekers can experience the same results.Crossgrained
C
2

I just released a class which allows to saveEventually a PFFile.

You can find it here :

/*
     This example uses an UIImage, but this works with any file writable as NSData
     We begin by writing this image in our tmp directory with an uuid as name.
 */
UIImage *nyancat = [UIImage imageNamed:@"nyancat.jpg"];
NSData *imageData = UIImageJPEGRepresentation(nyancat, 0.5);

NSString *filename = [[NSUUID UUID] UUIDString];
NSURL *fileUrl = [PFFileEventuallySaver fileURLInTmpWithName:filename];

[imageData writeToURL:fileUrl atomically:YES];

 /*
     We create a PFObject (you can pass an array to below function if you need your file to be saved on several objects). If upload works on first time, do what you want with your file, like linking it on your PFobject.

     If saving fails, it'll be retried as soon as network is available, on this session or nexts launches of app.
     In that case, the pointer at key kPFFILE_MANAGER_OBJECT_FILE_KEY of your PFFObject will be set with the PFFile, then saved eventually within PFFileEventuallySaver
 */
PFObject *object = [PFObject objectWithClassName:kPFFILE_CONTAINER_OBJECT_CLASSNAME];

[[PFFileEventuallySaver getInstance] trySaveobjectAtURL:fileUrl associatedObjects:@[object] withBlock:^(PFFile *file, NSError *error) {
if(!error)
{
    NSLog(@"[First try, network is fine] File saved, saving PFObject");

    object[kPFFILE_MANAGER_OBJECT_FILE_KEY] = file;
    [object saveEventually];

    NSLog(@"Try again disabling your network connection");
}
else
{
    NSLog(@"No network, connect back your wifi, or relaunch app. Your file will be sent");
}
} progressBlock:^(int percentDone) {
    NSLog(@"[First try, network is fine] Sending file %d/100%%", percentDone);
}];
Clematis answered 10/9, 2015 at 8:57 Comment(1)
I had to modify this quite a bit to get it to work in my project but it got me on the right track. Many thanks.Genip

© 2022 - 2024 — McMap. All rights reserved.