Prevent iCloud Backup of Folder - iphone

I recently got rejected for my NSLibraryDirectory backing up wrong kind of data to iCloud. I am trying to prevent the entire directory from backing up to iCloud, as this directory doesn't contain anything but downloaded content. Would this code in the AppDelegate.m work?
- (NSString *)applicationDocumentsDirectory {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSURL *pathURL= [NSURL fileURLWithPath:documentsDirectory];
[self addSkipBackupAttributeToItemAtURL:pathURL];
return documentsDirectory;
}
- (BOOL)addSkipBackupAttributeToItemAtURL:(NSURL *)URL
{ if (NSURLIsExcludedFromBackupKey) {
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;
}
else {
assert([[NSFileManager defaultManager] fileExistsAtPath: [URL path]]);
const char* filePath = [[URL path] fileSystemRepresentation];
const char* attrName = "com.apple.MobileBackup";
u_int8_t attrValue = 1;
int result = setxattr(filePath, attrName, &attrValue, sizeof(attrValue), 0, 0);
return result == 0;
}
}

Related

Saving text file to documents directory in iOS 7

I am trying to save a plain text file to the Documents directory in iOS 7. Here is my code:
//Saving file
NSFileManager *fileManager = [[NSFileManager alloc] init];
NSArray *urls = [fileManager URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask];
NSString *url = [NSString stringWithFormat:#"%#", urls[0]];
NSString *someText = #"Random Text To Be Saved";
NSString *destination = [url stringByAppendingPathComponent:#"File.txt"];
NSError *error = nil;
BOOL succeeded = [someText writeToFile:destination atomically:YES encoding:NSUTF8StringEncoding error:&error];
if (succeeded) {
NSLog(#"Success at: %#",destination);
} else {
NSLog(#"Failed to store. Error: %#",error);
}
Here is the error I am getting:
2013-10-13 16:09:13.848 SavingFileTest[13675:a0b] Failed to store. Error: Error Domain=NSCocoaErrorDomain Code=4 "The operation couldn’t be completed. (Cocoa error 4.)" UserInfo=0x1090895f0 {NSFilePath=file:/Users/Username/Library/Application%20Support/iPhone%20Simulator/7.0-64/Applications/F5DA3E33-80F7-439B-A9AF-E8C7FC4E1630/Documents/File.txt, NSUserStringVariant=Folder, NSUnderlyingError=0x10902aeb0 "The operation couldn’t be completed. No such file or directory"}
I can't figure out why I am getting this error running on the simulator. This works if I use the NSTemporaryDirectory().
From Apple's Xcode Template:
/**
Returns the URL to the application's Documents directory.
*/
- (NSURL *)applicationDocumentsDirectory {
return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory
inDomains:NSUserDomainMask] lastObject];
}
You can save like this:
NSString *path = [[self applicationDocumentsDirectory].path
stringByAppendingPathComponent:#"fileName.txt"];
[sampleText writeToFile:path atomically:YES
encoding:NSUTF8StringEncoding error:nil];
Mundi's answer in Swift:
let fileName = "/File Name.txt"
let filePath = self.applicationDocumentsDirectory().path?.stringByAppendingString(fileName)
do {
try strFileContents.writeToFile(filePath!, atomically: true, encoding: NSUTF8StringEncoding)
print(filePath)
}
catch {
// error saving file
}
func applicationDocumentsDirectory() -> NSURL {
return NSFileManager.defaultManager().URLsForDirectory(NSSearchPathDirectory.DocumentDirectory, inDomains: NSSearchPathDomainMask.UserDomainMask).last!
}
-(void)writeATEndOfFile:(NSString *)content2
{
NSArray *paths = NSSearchPathForDirectoriesInDomains
(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
//make a file name to write the data to using the documents directory:
NSString *fileName = [NSString stringWithFormat:#"%#/textfile.txt",
documentsDirectory];
if([[NSFileManager defaultManager] fileExistsAtPath:fileName])
{
NSFileHandle *fileHandle = [NSFileHandle fileHandleForWritingAtPath:fileName];
[fileHandle seekToEndOfFile];
NSString *writedStr = [[NSString alloc]initWithContentsOfFile:fileName encoding:NSUTF8StringEncoding error:nil];
content2 = [content2 stringByAppendingString:#"\n"];
writedStr = [writedStr stringByAppendingString:content2];
[writedStr writeToFile:fileName
atomically:NO
encoding:NSStringEncodingConversionAllowLossy
error:nil];
}
else {
int n = [content2 intValue];
[self writeToTextFile:n];
}
}
-(void) writeToTextFile:(int) value{
//get the documents directory:
NSArray *paths = NSSearchPathForDirectoriesInDomains
(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
//make a file name to write the data to using the documents directory:
NSString *fileName = [NSString stringWithFormat:#"%#/textfile.txt",
documentsDirectory];
//create content - four lines of text
// NSString *content = #"One\nTwo\nThree\nFour\nFive";
NSString *content2 = [NSString stringWithFormat:#"%d",value];
content = [content2 stringByAppendingString:#"\n"];
//save content to the documents directory
[content writeToFile:fileName
atomically:NO
encoding:NSStringEncodingConversionAllowLossy
error:nil];
}

File from Documents into NSData

i want to grab a file from the Documents Directory into a NSData Object, but if i do so my NSData is always NIL:
filepath = [[NSString alloc] init];
filepath = [self.GetDocumentDirectory stringByAppendingPathComponent:fileNameUpload];
NSData *data = [[NSFileManager defaultManager] contentsAtPath:filepath];
-(NSString *)GetDocumentDirectory{
fileMgr = [NSFileManager defaultManager];
homeDir = [NSHomeDirectory() stringByAppendingPathComponent:#"Documents"];
return homeDir;
}
at this point, i always get an exception that my data is NIL:
[request addRequestHeader:#"Md5Hash" value:[data MD5]];
i checked, there´s no File but i dunno why! I created that file before with:
NSMutableString *xml = [[NSMutableString alloc] initWithString:[xmlWriter toString]];
NSArray *paths = NSSearchPathForDirectoriesInDomains
(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
//make a file name to write the data to using the documents directory:
NSMutableString *fileName = [NSMutableString stringWithFormat:#"%#/7-speed-",
documentsDirectory];
[xml writeToFile:fileName
atomically:NO
encoding:NSStringEncodingConversionAllowLossy
error:nil];
Solved it by:
[xml writeToFile:fileName
atomically:YES
encoding:NSUTF8StringEncoding
error:nil];
check file exists:
if([[NSFileManager defaultManager] fileExistsAtPath:filepath)
{
NSData *data = [[NSFileManager defaultManager] contentsAtPath:filepath];
}
else
{
NSLog(#"File not exits");
}
Swift 3 Version
let filePath = fileURL.path
if FileManager.default.fileExists(atPath: filePath) {
if let fileData = FileManager.default.contents(atPath: filePath) {
// process the file data
} else {
print("Could not parse the file")
}
} else {
print("File not exists")
}

iOS Copy SQLite Database and excluding it from iCloud

My application just rejected because I copied sqlite database in NSDocumentDirectory and didn't exclude it from being synced to iCloud. I tried to add code to exclude it from iCloud but it is still occupying same space in iCloud. Here is my code.
- (BOOL)addSkipBackupAttributeToItemAtURL:(NSURL *)URL {
if (&NSURLIsExcludedFromBackupKey == nil) { // iOS <= 5.0.1
const char* filePath = [[URL path] fileSystemRepresentation];
const char* attrName = "com.apple.MobileBackup";
u_int8_t attrValue = 1;
int result = setxattr(filePath, attrName, &attrValue, sizeof(attrValue), 0, 0);
return result == 0;
} else { // iOS >= 5.1
NSError *error = nil;
[URL setResourceValue:[NSNumber numberWithBool:YES] forKey:NSURLIsExcludedFromBackupKey error:&error];
return error == nil;
}
}
+ (void)copyDatabaseIfNeeded {
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error = nil;
NSString *toPath = [self getDBPath];
BOOL success = [fileManager fileExistsAtPath:toPath];
if(!success) {
NSString *fromPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:databaseName];
NSURL *toURL = [NSURL fileURLWithPath:toPath];
NSURL *fromURL = [NSURL fileURLWithPath:fromPath];
[[NSFileManager defaultManager] addSkipBackupAttributeToItemAtURL:toURL];
[[NSFileManager defaultManager] addSkipBackupAttributeToItemAtURL:fromURL];
success = [fileManager copyItemAtURL:fromURL toURL:toURL error:&error];
if (!success)
NSLog(#"Failed to create writable database file with message '%#'.", [error localizedDescription]);
}
}
+ (NSString *)getDBPath {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = [paths objectAtIndex:0];
return [documentsDir stringByAppendingPathComponent:databaseName];
}
Please help.
You set the skip back attribute to the file before coping it, since the file is not yet copied there the filemanager can't change the properties of that file:
Also you are not calling the addSkipBackupAttributeToItemAtURL: on self but on NSFileManager which does have this method declared.
You can addSkipBackupAttributeToItemAtURL: from a class method if you declared it as an instance methods, change it to + to make it a class method.
Change it to something like:
+ (BOOL)addSkipBackupAttributeToItemAtURL:(NSURL *)URL {
if (&NSURLIsExcludedFromBackupKey == nil) { // iOS <= 5.0.1
const char* filePath = [[URL path] fileSystemRepresentation];
const char* attrName = "com.apple.MobileBackup";
u_int8_t attrValue = 1;
int result = setxattr(filePath, attrName, &attrValue, sizeof(attrValue), 0, 0);
return result == 0;
} else { // iOS >= 5.1
NSError *error = nil;
[URL setResourceValue:[NSNumber numberWithBool:YES] forKey:NSURLIsExcludedFromBackupKey error:&error];
return error == nil;
}
}
+ (void)copyDatabaseIfNeeded {
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error = nil;
NSString *toPath = [self getDBPath];
BOOL success = [fileManager fileExistsAtPath:toPath];
if(!success) {
NSString *fromPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:databaseName];
NSURL *toURL = [NSURL fileURLWithPath:toPath];
NSURL *fromURL = [NSURL fileURLWithPath:fromPath];
success = [fileManager copyItemAtURL:fromURL toURL:toURL error:&error];
if (success) {
[self addSkipBackupAttributeToItemAtURL:toURL];
} else {
NSLog(#"Failed to create writable database file with message '%#'.", [error localizedDescription]);
}
}
}
Also a my comment stated I removed the [[NSFileManager defaultManager] addSkipBackupAttributeToItemAtURL:fromURL]; since that file will a not be included in an iCloud backup and b files in the bundle are readonly and can't there for be modified.
I was on the phone with an Apple support guy about this.
However, rather than repeating stuff, this answer covers it well: Setting NSDocumentDirectory so it doesn't backup to iCloud
Please refer to Technical Q&A QA1719 which describes that the technique you employ in addSkipBackupAttributeToItemAtURL is advised for iOS 5.0.1 and earlier. For iOS 5.1 and later, you should use the following:
- (BOOL)addSkipBackupAttributeToItemAtURL:(NSURL *)URL
{
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;
}
NSDocumentDirectory has nothing to do with iCloud. the documents directory for an iOS application is NOT automatically backed up to iCloud at all. Its the same as it ever was, just a sandbox directory for your app.
You only store things in iCloud if the following conditions are met:
Your app has entitlements specifying iCloud sandbox container name
Your user is logged into iCloud on their device
You explicitly get the ubiquity container's documents directory and store things there.
So if you dont want to store something in iCloud, dont get the documents directory for the ubiquity container, dont connect to iCloud at all...
Also the iCloud backup is not even an application level setting the user sets it, so I dont know why yo u even have iCloud enabled. Just put your data in the data directory and apple will have no problem with it.

which URL is given to for setting "Do not backup flag" in ios?

i am storing some downloaded files in NSDocumentDirectory and i need to mark those files as "do not backup".
here is the code i have given
- (BOOL)addSkipBackupAttributeToItemAtURL:(NSURL *)URL1
{
if (&NSURLIsExcludedFromBackupKey == nil) { // iOS <= 5.0.1
const char* filePath = [[URL1 path] fileSystemRepresentation];
const char* attrName = "com.apple.MobileBackup";
u_int8_t attrValue = 1;
int result = setxattr(filePath, attrName, &attrValue, sizeof(attrValue), 0, 0);
return result == 0;
} else { // iOS >= 5.1
NSError *error = nil;
[URL1 setResourceValue:[NSNumber numberWithBool:YES] forKey:NSURLIsExcludedFromBackupKey error:&error];
return error == nil;
NSLog(#"success");
}
}
littile bit confused about which url should given for ths method? downloading url or the downloaded file path url?
can i use like
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectoryPath = [[paths objectAtIndex:0]stringByAppendingPathComponent:#"MdMus.mp3"];
[receivedData writeToFile:documentsDirectoryPath atomically:YES];
need to use this one
NSURL *url=[NSURL fileURLWithPath:documentsDirectoryPath];
[self addSkipBackupAttributeToItemAtURL:url];
or this
[self addSkipBackupAttributeToItemAtURL:DownloadingURL];
need help
if you want filesharing all user-data(in DocumentDirectory all data) prevent backup. refer a following code.
- (void)addAttributeToAllFolder
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsPath = ([paths count] > 0) ? [paths objectAtIndex:0] : nil;
NSArray *dirContents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:documentsPath error:nil];
for (int i =0; i < [dirContents count]; i++) {
NSURL *url = [NSURL fileURLWithPath:[NSString stringWithFormat:#"%#/%#",documentsPath,[dirContents objectAtIndex:i]]];
//this is your method (addSkipBackupAttributeToItemAtURL:)
if ([self addSkipBackupAttributeToItemAtURL:url]) {
NSLog(#"success! could add do not backup attribute to folder");
}
}
}

How to avoid overwriting files on iPhone Documents folder?

I need to write files containing NSArrays into the Documents folder of my iPhone application. Next time I need to create a new file, not overwriting the previous one.
I tried like this, but it only writes doc0 and doc1.
allDocs in an NSArray declared elsewhere.
What's wrong? Thank you!
NSString *myDoc;
NSString *temp;
for (int i = 0; i < [allDocs count]; ++i){
NSFileManager* fileMgr = [NSFileManager defaultManager];
myDoc = [NSString stringWithFormat:#"doc%d.dat", i];
NSString* currentFile = [documentsDirectory stringByAppendingPathComponent:myDoc];
BOOL fileExists = [fileMgr fileExistsAtPath:currentFile];
if (fileExists == NO){
temp = [NSString stringWithFormat:#"doc%d.dat", i];
break;
} else {
temp = [NSString stringWithFormat:#"doc%d.dat",i++];
break;
}
}
NSString *myArray = [documentsDirectory stringByAppendingPathComponent:myDoc];
NSMutableArray *myMutableArray = [[NSMutableArray alloc] initWithContentsOfFile: myArray];
if(myMutableArray == nil)
{
myMutableArray = [[NSMutableArray alloc] initWithCapacity:10];
myMutableArray = anotherArray;
}
[myMutableArray writeToFile:myArray atomically:YES];
You break out of the for loop on the first iteration each time whether the file is found or not. You should be looping with incremented values for i until fileExists is false.
- (BOOL) workFileExists:(NSString *)name {
NSFileManager *fm = [NSFileManager defaultManager];
NSString *path = [NSHomeDirectory() stringByAppendingPathComponent:#"Documents"];
NSString *filename = [name stringByAppendingString:#".swrk"];
return [fm fileExistsAtPath:[path stringByAppendingPathComponent:filename]];
}
- (NSString *)uniqueUntitledName {
NSString *untitled = #"Untitled";
NSString *name = untitled;
int i = 1;
while ([self workFileExists:name]) {
name = [NSString stringWithFormat:#"%#%d", untitled, i];
i++;
}
return name;
}
UIImage *imageForShare = [UIImage imageNamed:#"anyImage.jpg"];
NSString *stringPath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)objectAtIndex:0]stringByAppendingPathComponent:#"New Folder"];
// New Folder is your folder name
NSError *error = nil;
//in this method you are checking the path is exist or not for Folder Name
if (![[NSFileManager defaultManager] fileExistsAtPath:stringPath])
[[NSFileManager defaultManager] createDirectoryAtPath:stringPath withIntermediateDirectories:NO attributes:nil error:&error];
//now checking the image name already exist or not
NSString *fileName = [stringPath stringByAppendingFormat:#"/image.jpg"];
if (![[NSFileManager defaultManager] fileExistsAtPath:fileName])
{
NSLog(#"Path is available.");
NSData *data = UIImageJPEGRepresentation(imageForShare, 1.0);
[data writeToFile:fileName atomically:YES];
}
else
{
NSLog(#"Path doesn't exist, same name of image is already exist.");
}
Thank You!!