Save iOS 8 Documents to iCloud Drive - ios

I want to have my app save the documents it creates to iCloud Drive, but I am having a hard time following along with what Apple has written. Here is what I have so far, but I'm not for sure where to go from here.
UPDATE2
I have the following in my code to manually save a document to iCloud Drive:
- (void)initializeiCloudAccessWithCompletion:(void (^)(BOOL available)) completion {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
self.ubiquityURL = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil];
if (self.ubiquityURL != nil) {
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(#"iCloud available at: %#", self.ubiquityURL);
completion(TRUE);
});
}
else {
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(#"iCloud not available");
completion(FALSE);
});
}
});
}
if (buttonIndex == 4) {
[self initializeiCloudAccessWithCompletion:^(BOOL available) {
_iCloudAvailable = available;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *pdfPath = [documentsDirectory stringByAppendingPathComponent:selectedCountry];
NSURL* url = [NSURL fileURLWithPath: pdfPath];
[self.manager setUbiquitous:YES itemAtURL:url destinationURL:self.ubiquityURL error:nil];
}];
}
I have the entitlements set up for the App ID and in Xcode itself. I click the button to save to iCloud Drive, and no errors pop up, the app doesn't crash, but nothing shows up on my Mac in iCloud Drive. The app is running on my iPhone 6 Plus via Test Flight while using iOS 8.1.1.
If I run it on Simulator (I know that it won't work due to iCloud Drive not working with simulator), I get the crash error: 'NSInvalidArgumentException', reason: '*** -[__NSPlaceholderDictionary initWithObjects:forKeys:count:]: attempt to insert nil object from objects[3]'

Well, you've got me interested in this matter myself and as a result I've spent way to much time on this question, but now that I've got it working I hope it helps you as well!
To see what actually happens in the background, you can have a look at ~/Library/Mobile Documents/, as this is the folder where the files eventually will show up. Another very cool utility is brctl, to monitor what happens on your mac after storing a file in the iCloud. Run brctl log --wait --shorten from a Terminal window to start the log.
First thing to do, after enabling the iCloud ability (with iCloud documents selected), is provide information for iCloud Drive Support (Enabling iCloud Drive Support). I also had to bump my bundle version before running the app again; took me some time to figure this out. Add the following to your info.plist:
<key>NSUbiquitousContainers</key>
<dict>
<key>iCloud.YOUR_BUNDLE_IDENTIFIER</key>
<dict>
<key>NSUbiquitousContainerIsDocumentScopePublic</key>
<true/>
<key>NSUbiquitousContainerSupportedFolderLevels</key>
<string>Any</string>
<key>NSUbiquitousContainerName</key>
<string>iCloudDriveDemo</string>
</dict>
</dict>
Next up, the code:
- (IBAction)btnStoreTapped:(id)sender {
// Let's get the root directory for storing the file on iCloud Drive
[self rootDirectoryForICloud:^(NSURL *ubiquityURL) {
NSLog(#"1. ubiquityURL = %#", ubiquityURL);
if (ubiquityURL) {
// We also need the 'local' URL to the file we want to store
NSURL *localURL = [self localPathForResource:#"demo" ofType:#"pdf"];
NSLog(#"2. localURL = %#", localURL);
// Now, append the local filename to the ubiquityURL
ubiquityURL = [ubiquityURL URLByAppendingPathComponent:localURL.lastPathComponent];
NSLog(#"3. ubiquityURL = %#", ubiquityURL);
// And finish up the 'store' action
NSError *error;
if (![[NSFileManager defaultManager] setUbiquitous:YES itemAtURL:localURL destinationURL:ubiquityURL error:&error]) {
NSLog(#"Error occurred: %#", error);
}
}
else {
NSLog(#"Could not retrieve a ubiquityURL");
}
}];
}
- (void)rootDirectoryForICloud:(void (^)(NSURL *))completionHandler {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSURL *rootDirectory = [[[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil]URLByAppendingPathComponent:#"Documents"];
if (rootDirectory) {
if (![[NSFileManager defaultManager] fileExistsAtPath:rootDirectory.path isDirectory:nil]) {
NSLog(#"Create directory");
[[NSFileManager defaultManager] createDirectoryAtURL:rootDirectory withIntermediateDirectories:YES attributes:nil error:nil];
}
}
dispatch_async(dispatch_get_main_queue(), ^{
completionHandler(rootDirectory);
});
});
}
- (NSURL *)localPathForResource:(NSString *)resource ofType:(NSString *)type {
NSString *documentsDirectory = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
NSString *resourcePath = [[documentsDirectory stringByAppendingPathComponent:resource] stringByAppendingPathExtension:type];
return [NSURL fileURLWithPath:resourcePath];
}
I have a file called demo.pdf stored in the Documents folder, which I'll be 'uploading'.
I'll highlight some parts:
URLForUbiquityContainerIdentifier: provides the root directory for storing files, if you want to them to show up in de iCloud Drive on your Mac, then you need to store them in the Documents folder, so here we add that folder to the root:
NSURL *rootDirectory = [[[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil]URLByAppendingPathComponent:#"Documents"];
You also need to add the file name to the URL, here I copy the filename from the localURL (which is demo.pdf):
// Now, append the local filename to the ubiquityURL
ubiquityURL = [ubiquityURL URLByAppendingPathComponent:localURL.lastPathComponent];
And that's basically it...
As a bonus, check out how you can provide an NSError pointer to get potential error information:
// And finish up the 'store' action
NSError *error;
if (![[NSFileManager defaultManager] setUbiquitous:YES itemAtURL:localURL destinationURL:ubiquityURL error:&error]) {
NSLog(#"Error occurred: %#", error);
}

If you are intending to work with UIDocument and iCloud, this guide from Apple is pretty good:
https://developer.apple.com/library/ios/documentation/DataManagement/Conceptual/UsingCoreDataWithiCloudPG/Introduction/Introduction.html
EDITED:
Don't know of any better guide of hand, so this may help:
You will need to fetch the ubiquityURL using the URLForUbuiquityContainerIdentifier function on NSFileManager (which should be done asynchronously).
Once that is done, you can use code like the following to create your document.
NSString* fileName = #"sampledoc";
NSURL* fileURL = [[self.ubiquityURL URLByAppendingPathComponent:#"Documents" isDirectory:YES] URLByAppendingPathComponent:fileName isDirectory:NO];
UIManagedDocument* document = [[UIManagedDocument alloc] initWithFileURL:fileURL];
document.persistentStoreOptions = #{
NSMigratePersistentStoresAutomaticallyOption : #(YES),
NSInferMappingModelAutomaticallyOption: #(YES),
NSPersistentStoreUbiquitousContentNameKey: fileName,
NSPersistentStoreUbiquitousContentURLKey: [self.ubiquityURL URLByAppendingPathComponent:#"TransactionLogs" isDirectory:YES]
};
[document saveToURL:fileURL forSaveOperation:UIDocumentSaveForCreating completionHandler:^(BOOL success) {
}];
You'll also want to look into using NSMetadataQuery to detect documents uploaded from other devices and potentially queue them for download, and observing the NSPersistentStoreDidImportUbiquitousContentChangesNotification to find about changes made via iCloud, among other things.
** Edit 2 **
Looks like you are trying to save a PDF file, which is not quite what Apple considers a "document" in terms of iCloud syncing. No need to use UIManagedDocument. Remove the last 3 lines of your completion handler and instead just use NSFileManager's
setUbiquitous:itemAtURL:destinationURL:error: function. The first URL should be a local path to the PDF. The second URL should be the path within the ubiquiuty container to save as.
You may also need to look into NSFileCoordinator perhaps.
I think this guide from Apple may be the most relevant:
https://developer.apple.com/library/ios/documentation/FileManagement/Conceptual/FileSystemProgrammingGuide/iCloud/iCloud.html

Related

App rejected due to data storeage

My app was rejected cause it must follow the iOS Data Storage Guidelines. I have already read some answer here on stackoverflow, and i have already read some blogs... I know my problem, at first application launch i download unzip sqlite db file from server and zip it ,after that i remove unzip file from temp folder.
I am using following code also.
+ (BOOL)addSkipBackupAttributeToItemAtURL:(NSURL *)URL {
NSError *error = nil;
BOOL success = [URL setResourceValue: [NSNumber numberWithBool: YES]
forKey: NSURLIsExcludedFromBackupKey error: &error];
if(!success){
NSLog(#"Error excluding %# from backup %#", [URL lastPathComponent], error);
}
return success;
}
calling this method here:-
+ (void) createEditableCopyOfDatabaseIfNeeded
{
NSLog(#"Creating editable copy of database");
BOOL success;
NSFileManager *fileManager = [NSFileManager defaultManager]; NSError *error;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *writableDBPath = [documentsDirectory stringByAppendingPathComponent:ddb];
[self addSkipBackupAttributeToItemAtURL:[NSURL URLWithString:writableDBPath]];
success = [fileManager fileExistsAtPath:writableDBPath];
if (success)
{
NSLog(#"ALready exists"); return;
}
NSString *defaultDBPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:ddb];
success = [fileManager copyItemAtPath:defaultDBPath toPath:writableDBPath error:&error];
[self addSkipBackupAttributeToItemAtURL:[NSURL URLWithString:defaultDBPath]];
if (!success)
{
NSAssert1(0, #"Failed to create writable database file with message '%#'.", [error localizedDescription]);
}
NSURL * fileURL;
fileURL = [ NSURL fileURLWithPath: ddb ];
[ fileURL setResourceValue: [ NSNumber numberWithBool: YES ] forKey: NSURLIsExcludedFromBackupKey error: nil ];
}
Still my application was rejected.Please help.
I got this respones from apple.
May 12, 2016 at 1:59 AM
From Apple
2.23 - Apps must follow the iOS Data Storage Guidelines or they will be rejected
Thank you for your resubmission. During our continued review, we found the following issue unresolved:
2.23 Details
On launch and content download, your app still stores 78.84 MB on the user's iCloud, which does not comply with the iOS Data Storage Guidelines.
Next Steps
Please verify that only the content that the user creates using your app, e.g., documents, new files, edits, etc. is backed up by iCloud as required by the iOS Data Storage Guidelines. Also, check that any temporary files used by your app are only stored in the /tmp directory; please remember to remove or delete the files stored in this location when it is determined they are no longer needed.
Data that can be recreated but must persist for proper functioning of your app - or because users expect it to be available for offline use - should be marked with the "do not back up" attribute. For NSURL objects, add the NSURLIsExcludedFromBackupKey attribute to prevent the corresponding file from being backed up. For CFURLRef objects, use the corresponding kCRUFLIsExcludedFromBackupKey attribute.
Resources
To check how much data your app is storing:
- Install and launch your app
- Go to Settings > iCloud > Storage > Manage Storage
- Select your device
- If necessary, tap "Show all apps"
- Check your app's storage
For additional information on preventing files from being backed up to iCloud and iTunes, see Technical Q&A 1719: How do I prevent files from being backed up to iCloud and iTunes.
If you have difficulty reproducing a reported issue, please try testing the workflow described in Technical Q&A QA1764: How to reproduce bugs reported against App Store submissions.
If you have code-level questions after utilizing the above resources, you may wish to consult with Apple Developer Technical Support. When the DTS engineer follows up with you, please be ready to provide:
- complete details of your rejection issue(s)
- screenshots
- steps to reproduce the issue(s)
- symbolicated crash logs - if your issue results in a crash log
NSString *writableDBPath = [documentsDirectory stringByAppendingPathComponent:ddb];
This kinda points out ddb is some random string.
NSURL * fileURL;
fileURL = [ NSURL fileURLWithPath: ddb ];
[fileURL setResourceValue: [ NSNumber numberWithBool: YES ] forKey: NSURLIsExcludedFromBackupKey error: nil ];
here you are not getting the path of where you copied the db, instead
just opening url with string value which is why i think it is failing.
To fix this call the method after this line
success = [fileManager copyItemAtPath:defaultDBPath toPath:writableDBPath error:&error];
[self addSkipBackupAttributeToItemAtURL:[NSURL URLWithString:writableDBPath]];
(1) Make sure your large file is located in the Library folder.
(2) Use the NSURLIsExcludedFromBackupKey option or the addSkipBackupAttributeToItemAtPath in AppDelegate.m .
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
/* create a file outside of the Document folder like filePath1 */
/* preven os from copying data file for iCloud */
[self addSkipBackupAttributeToItemAtPath:[self filePathA]];
return YES;
}
- (NSString *)filePathA {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory,NSUserDomainMask,YES);
return [[paths objectAtIndex:0] stringByAppendingPathComponent:#"Data"];
}
- (NSString *)filePath1 {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory,NSUserDomainMask,YES);
return [[[paths objectAtIndex:0] stringByAppendingPathComponent:#"Data"] stringByAppendingPathComponent:#"Data1.data"];
}
- (BOOL)addSkipBackupAttributeToItemAtPath:(NSString *)path {
NSURL *url = [NSURL fileURLWithPath: path];
assert([[NSFileManager defaultManager] fileExistsAtPath:[url path]]);
NSError *error = nil;
BOOL success = [url setResourceValue: [NSNumber numberWithBool: YES] forKey: NSURLIsExcludedFromBackupKey error: &error];
if(!success){
NSLog(#"Error excluding %# from backup %#",[url lastPathComponent],error);
}
return success;
}

newsstand memory storage issue, how do i get the app cache directory?

I have a newsstand app which has magazines and uses the newsstand framework. I realized there was something wrong when deleting the magazines and/or when downloading them because when I accessed settings/usage my app keeps growing in memory usage when downloading and deleting the same magazine.
Found the issue... when downloading the issue in the delegate method:
-(void)connectionDidFinishDownloading:(NSURLConnection *)connection destinationURL:(NSURL *)destinationURL
I just needed to add something like this at the end:
NSError *error;
[[NSFileManager defaultManager] removeItemAtPath:[destinationURL path] error:&error];
if (error){
NSLog(#"ERROR:%#", error);
}
Even the directory is called "caches" you need to manually delete. Ok problem solved but what about the customers who already download my app and have tons of MBs dead in the cache directory.
I wanted to know how to get this directory and delete everything on it at launch and only once...
I can do it only once using a NSUserdefault but how do I get this directory and delete any zip files in it... an example of this directory and a file within is:
/private/var/mobile/Applications/1291CC20-C55F-48F6-86B6-B0909F887C58/Library/Caches/bgdl-280-6e4e063c922d1f58.zip
but this path varies with the device. I want to do this at launch so I'm sure there are no downloads in progress but any other solutions are welcome, thanks in advance.
Everything that you need is enumerate all files from Caches directory and remove ones that have zip extension:
- (void)removeZipFilesFromCachesDirectory {
static NSString *const kZIPExtension = #"zip";
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *cachesDirectoryPath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSError *error = nil;
NSArray *fileNames = [fileManager contentsOfDirectoryAtPath:cachesDirectoryPath error:&error];
if (error == nil) {
for (NSString *fileName in fileNames) {
NSString *filePath = [cachesDirectoryPath stringByAppendingPathComponent:fileName];
if ([filePath.pathExtension.lowercaseString isEqualToString:kZIPExtension]) {
NSError *anError = nil;
[fileManager removeItemAtPath:filePath error:&anError];
if (anError != nil) {
NSLog(#"%#", anError);
}
}
}
} else {
NSLog(#"%#", error);
}
}

How to Delete an iCloud ubiquity containers on the iPhone?

I have the same issue as this question where the iCloud ubiquity container is not being cleaned up when I delete the app.
But when I try to delete the ubiquity container I get an error message (The operation couldn’t be completed. (Cocoa error 513.)). How can I delete it?
This is what I'm using:
NSString *path = #"/private/var/mobile/Library/Mobile Documents/XXXXXX";
[[NSFileManager defaultManager] removeItemAtPath:path error:&error];
EDIT: Even if I delete the App on the device and all iCloud data (Settings App->iCloud->Storage & Backup->Manage Storage->App Name) there's still some data left over on the iCloud ubiquity container. This is the data I want to delete the first time the app is launched (in case the user re-installs the app).
You should be able to remove files INSIDE the ubiquity container by going to Settings App->iCloud->Storage & Backup->Manage Storage->App Name and then delete any files. I think you may only see files in the iCloud/Documents directory though so you may need code to clear anything else.
Alternately use a Mac and go to ~/Library/Mobile Documents and remove files there.
To get the iCloud container use this:
NSURL *iCloudURL = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:ubiquityID];
where ubiquityID is your apps iCloud container ID.
To list all files in the iCloud container use something like this passing in the iCloudURL
/*! Recursively lists all files
#param dir The directory to list
#param padding A string padding to indent the output depending on the level of recursion
*/
- (void)listAllFilesInDirectory:(NSURL*)dir padding:(NSString*)padding {
NSArray *docs = [[NSFileManager defaultManager] contentsOfDirectoryAtURL:dir includingPropertiesForKeys:nil options:0 error:nil];
for (NSURL* document in docs) {
FLOG(#" %# %#", padding, [document lastPathComponent]);
BOOL isDir;
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:document.path isDirectory:&isDir];
if (fileExists && isDir) {
[self listAllFilesInDirectory:document padding:[NSString stringWithFormat:#" %#", padding]];
}
}
}
And to delete stuff from the ubiquity container you need to user a fileCoordinator something like this:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {
NSFileCoordinator* fileCoordinator = [[NSFileCoordinator alloc] initWithFilePresenter:nil];
[fileCoordinator coordinateWritingItemAtURL:fileURL options:NSFileCoordinatorWritingForDeleting
error:nil byAccessor:^(NSURL* writingURL) {
NSFileManager* fileManager = [[NSFileManager alloc] init];
NSError *er;
//FLOG(#" deleting %#", writingURL);
bool res = [fileManager removeItemAtURL:writingURL error:&er];
if (res) {
LOG(#" iCloud files removed");
}
else {
LOG(#" document NOT removed");
FLOG(#" error %#, %#", er, er.userInfo);
}
}];
}

iOS Dropbox sync before app quits

I'm trying to sync files created in my app to Dropbox, however it seems the syncing only happens after the app quits, and not in real time when files are created and moved between locations in different folders in the app or created/deleted. Is there a certain call I have to make for instance? Appreciate your help!
Below is the code I am using for syncing:
-(void)createFilePathinFolder:(NSString *)folderName FileName:(NSString *)fileName {
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *folder = [self localDocumentsRootPath];
if (![folderName isEqualToString:#"root"]) {
folder = [folder stringByAppendingPathComponent:folderName];
}
NSString *file = [folder stringByAppendingPathComponent:fileName];
if (![fileManager fileExistsAtPath:file]) {
[fileManager createFileAtPath:file contents:[#"0" dataUsingEncoding:NSUTF8StringEncoding] attributes:nil];
}
//Insert to FileTable
[[DBHelper shared]insertToFileTableWithFolder:folderName FileName:fileName MetaFileName:nil Tag:nil Title:nil];
if ([NetworkHelper shared].canSyncWithCloud) {
NSString *filePathStr = [folderName stringByAppendingPathComponent:fileName];;
if ([folderName isEqualToString:#"root"]) {
filePathStr = fileName;
}
DBPath *filePath = [[DBPath root] childPath:filePathStr];
DBError *error;
DBFile *destFile =[[DBFilesystem sharedFilesystem] createFile:filePath error:&error];
NSData *fileData = [NSData dataWithContentsOfFile:file];
[destFile writeData:fileData error:&error];
//[destFile writeContentsOfFile:file shouldSteal:NO error:&error];
[destFile close];
if (error) {
NSLog(#"Error when creating file %# in Dropbox, error description:%#", fileName, error.description);
}
}
}
Your error checking is all wrong. Your code should be more like this:
DBPath *filePath = [[DBPath root] childPath:filePathStr];
DBError *error = nil;
DBFile *destFile =[[DBFilesystem sharedFilesystem] createFile:filePath error:&error];
if (destFile) {
NSData *fileData = [NSData dataWithContentsOfFile:file];
if (![destFile writeData:fileData error:&error]) {
NSLog(#"Error when writing file %# in Dropbox, error description: %#", fileName, error);
}
[destFile close];
} else {
NSLog(#"Error when creating file %# in Dropbox, error description: %#", fileName, error);
}
The file should sync right away with the code that you have. This assumes you have properly linked your app to an account and all.
What version of the Dropbox Sync API are you using? 1.0.7 has some potential networking issues. I have a beta of 1.0.8 that seems to solve these issues. You may need to wait until 1.0.8 comes out.
You can verify if Dropbox is hung. While running your app in the debugger, wait a minute after the file has been created. If the file doesn't appear, pause your app in the debugger and look at all of the threads. You should see one or more dropbox related threads. If one looks blocked with a reference to dbx_cfhttp_request then you have hit a bug in the Dropbox framework. Putting your device in Airplane mode for 10-15 seconds then turning Airplane mode off again should kick it back into gear.

NSFileManager removeItemAtPath: error: did not actually free disk space

NSFileManager* fileManager = [NSFileManager defaultManager];
NSURL* url = [[fileManager URLsForDirectory:NSCachesDirectory inDomains:NSUserDomainMask] lastObject];
NSString* directory = [url path];
NSString* filePath = [directory stringByAppendingPathComponent:FILE_NAME];
if ([fileManager fileExistsAtPath:filePath])
{
[fileManager removeItemAtPath:filePath error:nil];
}
Here's my code. When it is executed, the file is deleted, but the space remains occupied. Here's the code for storing something into the file.
NSFileManager* fileManager = [NSFileManager defaultManager];
NSURL* url = [[fileManager URLsForDirectory:NSCachesDirectory inDomains:NSUserDomainMask] lastObject];
NSString* directory = [url path];
NSString* filePath = [directory stringByAppendingPathComponent:FILE_NAME];
NSArray* oldArray = nil;
if ([fileManager fileExistsAtPath:filePath])
{
oldArray = [[NSArray alloc] initWithContentsOfFile:filePath];
[fileManager removeItemAtPath:filePath error:nil];
}
NSMutableArray* mergeArray = [[NSMutableArray alloc] initWithArray:arrayOfPersons];
[mergeArray addObjectsFromArray:oldArray];
if ( [mergeArray writeToFile:filePath atomically:YES]) NSLog(#"Written");
By the way, it cost 1 MB to store an array with only 1 object(an NSDictionary with 2 keys). Is there a cheaper way to store it?
You need to be much more careful with your experiments. The unix file system does lots of stuff with files. In fact, when you "delete" a file, all you do is unlink it from the file system. If that file is open with another file descriptor, anywhere in the OS, it will remain open.
Furthermore, there are lots of optimizations to reuse file nodes. Just because you delete a file, does not mean that space goes back automatically. It could be "reserved" in your app for several reasons, for other files to use. No sense giving it back to the file system until the file system needs it.
settings->general->usage is a very rough measurement of file system utilization. A better measurement would be accessing the attributes of the file and file system directly.
Using your code as a base, consider this:
- (NSString*)workingDirectory {
NSFileManager* fileManager = [NSFileManager defaultManager];
NSURL* url = [[fileManager URLsForDirectory:NSCachesDirectory
inDomains:NSUserDomainMask] lastObject];
return [url path];
}
- (NSString*)filePath {
return [[self workingDirectory] stringByAppendingPathComponent:FILE_NAME];
}
Now, you can see all the attributes of the entire file system with this:
NSDictionary *attributes = [[NSFileManager defaultManager]
attributesOfFileSystemForPath:[self workingDirectory] error:0];
NSLog(#"file system attributes: %#", attributes);
and those for the specific file with this:
NSDictionary *attributes = [[NSFileManager defaultManager]
attributesOfItemAtPath:[self filePath] error:0];
NSLog(#"file attributes: %#", attributes);
Pay attention to NSFileSystemFreeSize and NSFileSize.
Run your app, and dump both of these values. Create your file, and dump them again. Delete the file, and dump them again.
After all that, you may actually see the NSFileSystemFreeSize go UP, even after the delete. Remember, the system itself is creating temporary files, and is probably caching those file system nodes for future use.
You can get more consistent results if you quit all other apps. Then, quit yours (double-click power button, X all running apps). Delete the file before doing this.
Now, start your app, without the file existing.
Dump file system data.
Create the file.
Dump file system data.
Dump file data.
You should see the file taking up about 200-250 bytes, and the file system free size should drop 8192.
Delete the file.
Dump file system data. Is probably at least as big as it was before deleting file.
Quit app (not in XCode -- double-click power, X the app).
Run the app.
Dump file system data. You should see the data back to about what it was when you started earlier.
In conclusion, while it may look like the file system has not released the data, it really has, but maybe the tool you are using to query just does not know the details of the file system.
Note, also, that when an app is running, it will use lots of file system resources for stuff that you are not explicitly doing.
I hope that made sense...
Your code to delete the file looks correct, but you are switching between URLs and Paths when you don't need to. You should also be checking for an error when you try to delete the file so that you can see why it doesn't work. Try this:
NSFileManager *fileManager = [NSFileManager defaultManager];
NSArray *directoryURLs = [fileManager URLsForDirectory:NSCachesDirectory
inDomains:NSUserDomainMask];
NSURL *directoryURL = [directoryURLs objectAtIndex:0];
NSURL *fileURL = [directoryURL URLByAppendingPathComponent:FILE_NAME];
if (!fileURL)
{
NSLog(#"Could not create URL for file.");
return;
}
NSError *err = nil;
if (![fileURL checkResourceIsReachableAndReturnError:&err])
{
NSLog(#"File is not reachable.\n"
"Error: %# %d %#", [err domain], [err code], [[err userInfo] description]);
return;
}
err = nil;
[fileManager removeItemAtURL:fileURL error:&err];
if (err)
{
NSLog(#"Unable to delete existing file.\n"
"Error: %# %d %#", [err domain], [err code], [[err userInfo] description]);
return;
}
May it be, that the length of the ˚FILE_NAME` is greater or equal to 300 chars? This brought me to similar issues with NSFileManager some time ago...

Resources