I'm using RestKit to map an XML file. In that file are several items that map to a class, let's call it ListItem. These listitems have a reference to a thumbnail image file. As soon as the mapping is done I'm starting the download of the thumbnails so I can be sure they are available when I need them.
Now I'd like to make sure these files are downloaded properly. Checking for the existance of the files in the cache won't be a problem, but I'd like the context only to be saved when the download of all files was successful.
I just can't figure out at which point the saving is being done. After I call the mapping method
[objectManager loadObjectsAtResourcePath:#"data.xml" delegate:self];
the mapping is being done and I get the result in
- (void)objectLoader:(RKObjectLoader*)objectLoader didLoadObjects:(NSArray*)objects
This is the point where I start the image download, but at that point the context has already been saved. I don't know how to prevent this behavior.
The only idea I came up with is duplicating the sql file and using the duplicate-file for the objectStore to perform the sync. When the sync is successful overriding the original sql with the duplicate.
Does anybody know a better way to do this? Did I miss a method that is being called in the mapping process?
Related
I have an app with subclass of NSDocument that has overridden method writeToURL:(NSURL *) ofType:(NSString *) error:(NSError **) which saves data at given NSURL location, but also can save additional file (with appended .my2ext) with debug information. Previously it worked well (I created the app several years ago), but now I see that instead of user selected location the method gets some temporary directory:
file:///var/folders/yv/gwf3_hjs0ps7sb3psh3d0w3m0000gn/T/TemporaryItems/(A%20Document%20Being%20Saved%20By%20MyApp%202)/myfilename.myext
Then, as I understand, the framework relocates the main file (at given url), but the additional file gets lost. So, can I somehow obtain the user selected path to save directly into it? Or prevent using temp directories at all?
I've already turned off the SandBox mode, but this didn't help. I also know that I can use "File Package" approach, but my app is created for a few people only, so, there is not interest in good production approach, only in simplicity.
I tried to google any possible solution, but found nothing helpful or just related. Even the documentation says nothing about using temporary directories! So, I decided to override different NSDocument methods. After several experiments I almost lost hope, but then I found that the method
saveToURL: ofType: forSaveOperation: delegate: didSaveSelector: contextInfo: provides real, user selected location. And this finally solved the problem.
I'm sandboxing my app, and trying to allow for import/export of multiple files, using an XML file to refer to them. To allow my app (or another sandboxed app) access to the files listed in the XML, I'm also including a serialized security-scoped bookmark. I'm serializing it as described in this answer, and my unit tests (which are not sandboxed) write and read the XML data without issue. When my app resolves the bookmark, the NSURL returned is nil, as is the NSError reference. Since I don't believe that should be the case, why is it happening? I can work around it by prompting the user to select a file/directory with an NSOpenPanel, but I'd still like to get the bookmarks to work as they should.
Reproduced in a test project
To reproduce at home, create a new Cocoa app in Xcode, and use the following Gist for the files in the project: https://gist.github.com/2582589 (updated with a proper next-view loop)
Then, follow Apple's instructions to code-sign the project. You reproduce the problem (which I submitted to Apple as rdar://11369377) by clicking the buttons in sequence. You pick any file on disk (outside the app's container), then an XML to export to, and then the same XML to import.
Hopefully you guys will be able to help me figure out what I'm doing wrong. Either I'm doing something wrong and the framework is erroneously keeping to itself, or I'm doing it right and it's totally broken. I try not to blame the framework, so which is it? Or is there another possibility?
Sample Code
Exporting the XML to docURL:
// After the user picks an XML (docURL) destination with NSSavePanel
[targetURL startAccessingSecurityScopedResource];
NSData *bookmark = [targetURL bookmarkDataWithOptions:NSURLBookmarkCreationWithSecurityScope
includingResourceValuesForKeys:nil
relativeToURL:docURL
error:&error];
[targetURL stopAccessingSecurityScopedResource];
Importing the XML from docURL:
// After the user selected the XML (docURL) from an NSOpenPanel
NSURL *result = [NSURL URLByResolvingBookmarkData:bookmarkData
options:NSURLBookmarkResolutionWithSecurityScope
relativeToURL:docURL
bookmarkDataIsStale:nil
error:&error];
I tried surrounding this call with[docURL ..AccessingSecurityScopedResource], which didn't make a difference (as expected, since the docURL is already within scope after having been selected in the Open Panel
Also, I specify the following in my app.entitlements file:
com.apple.security.files.user-selected.read-write
com.apple.security.files.bookmarks.app-scope
com.apple.security.files.bookmarks.collection-scope
As mentioned above, the second step (resolving the bookmark) completes, but leaves both error and result nil. As I've been implementing sandboxing, most of the mistakes I've made have resulted in an NSError being returned, which helped me to resolve the bug. But now there's no error, and no URL is resolved.
Miscellaneous troubleshooting steps
I tried placing the XML file into my app's sandbox, which didn't make a difference, so access to the XML file is not the problem
The app uses ARC, but so do the unit tests, which succeed. I tried using an alloc/init instead of the autoreleased class method, too (just in case)
I pasted the URL resolution code immediately after creating the bookmark, and it runs fine, producing a security-scoped URL
I did a po on the originally created bookmark (before serialization), and then on the bookmark after deserialization, and they match 100%. Serialization is not the problem
I replaced the resolution call with CFURLCreateByResolvingBookmarkData(..), with no change. If it is a bug, it's present in the Core Foundation API as well as the Cocoa layer
Specifying a value for bookmarkDataIsStale: has no effect
If I specify 0 for options:, then I do get back a valid NSURL, but it has no security scope, and therefore subsequent calls to read the file do still fail
In other words, the deserialized bookmark does appear to be valid. If the bookmark data were corrupted, I doubt NSURL would be able to do anything with it
NSURL.h didn't contain any useful comments to point out something I'm doing wrong
Is anyone else using security-scoped document bookmarks in a sandboxed application with success? If so, what are you doing differently than I am?
OS Version Request
Can someone with access to the Mountain Lion beta verify whether or not my sample project shows the same (lack of an) error? If it's a bug that has been fixed after Lion, I won't worry about it. I'm not in the developer program yet, and so don't have access. I'm not sure if answering that question would violate the NDA, but I hope not.
In your Gist code, change the following line in AppDelegate.m (line 61):
[xmlTextFileData writeToURL:savePanel.URL atomically:YES];
to
[xmlTextFileData writeToURL:savePanel.URL atomically:NO];
Your code will then work.
The reason for this is likely the same reason for which it is necessary to have an existing (but empty) file that will contain the document-scoped bookmarks before calling [anURL bookmarkDataWithOptions]: While creating the NSData instance, the ScopedBookmarkAgent adds something (like a tag, probably an extended file attribute) to that file.
If you write data (i.e. the bookmark URLs) to that file atomically, in fact they're written not directly to the file but first to a temporary file that is renamed if the write operation was successful. It seems that the tag that has been added to the (empty, but existing) file that will contain the bookmarks is getting lost during this process of writing to a temporary file and then renaming it (and thereby likely deleting the original, empty file).
By the way: It shouldn't be necessary to create app-scoped bookmarks before passing the respective URLs to the xml file containing the document-scoped bookmarks.
Addition: com.apple.security.files.bookmarks.collection-scope has been renamed to com.apple.security.files.bookmarks.document-scope in 10.7.4.
I need to download a few web pages for later usee in my application, and I can't find an easy way to accomplish this task. I would prefer a solution where I don't need to parse the HTML to get the URLs of the images and other resources, but rather download these somehow automatically.
OK guys, here is my solution:
created my own cache object, derived from NSURLCache
added to it a "state" enum variable, with the possible states of: SAVING, LOADING, NOTHING
overwritten cachedResponseForRequest to do things according to the state
SAVING: created a NSMutableDictionary to store every download request
Downloaded the file in the request to a flat file, added the path to the file to the dictionary as an object, with the URL as the key
LOADING: used this dictionary as they did in this example to load back the stored content: http://cocoawithlove.com/2010/09/substituting-local-data-for-remote.html
set my cache object as the shared cache object using [NSURLCache setSharedURLCache:myCacheObject];
After this, when I want to save something I set the cache's state to SAVING, and load a request to an UIWebView. After this I set the state back to LOADING, load a request to an UIWebView, and if I stored my request previously, my cache will load it from the disk.
I think ASIHTTPRequest framework can be useful for you - try ASIWebPageRequest and see if it supports all features you need.
I’m currently creating an iOS app that uploads files to a server. As multiple uploads can be queued and have metadata attached that I want to store persistently, I’m using Core Data to model and store uploads. I’m also using NSFetchedResultsController to display all uploads in a table view. So far so good.
I’m now implementing a progress indicator and that’s where I’m unsure if my implementation is really a good idea. I’ve added a float property to my model which gets updated by my upload controller as the upload progresses. I’m then updating my UITableViewCell subclass with the help of NSFetchedResultsControllerDelegate and this works pretty well. However, it doesn’t really make sense to actually store this property persistently, since uploads can’t be resumed if the app gets terminated. I’m only using the property to connect my upload controller and view controller. Is there a better way to do this without losing the convenience of NSFetchedResultsController?
If you marker your property as Transient in the model editor it means that it wont be stored in the persistent file.
The property will reset to default each time the MO loads, though im unsure of the rules around at what point they will reset if you are not retaining specific instances of the MO's
This guy, http://2pi.dk/tech/cocoa/transient_properties.html seems to know.
Hey Guys,
In my app i need to verify that the file actually exist on the device before its being accessed by some file access methods (UIImage imageNamed, Cocos2d CCSprite method and so on).
I need to be sure that the file is on the device (and if not try to fetch it from the servers).
Can I do it without changing all the code to support it?
I thought on something like a 'Super Category' on the file system...
Is it possible???
I saw this idea, what do you think
overriding-methods-in-cocoa-without-subclassing
Thanks!
M.
it's often best to attempt the file/url read and fail gracefully - filesystems have a way of changing.
if you know the image's bundle, then use NSBundle.
You could use NSFileManager fileExistsAtPath: but from the docs:
/* The following methods are of limited utility. Attempting to predicate behavior based on the current state of the filesystem or a particular file on the filesystem is encouraging odd behavior in the face of filesystem race conditions. It's far better to attempt an operation (like loading a file or creating a directory) and handle the error gracefully than it is to try to figure out ahead of time whether the operation will succeed.
So probably just try to get the resource, if it fails, fetch and then retry.