11

Referencing iCloud + Storage of media in iPhone Documents folder, which shows how to set the iOS 5.0.1 "Do Not Backup" attribute for a file.

Is there an efficient way to do this for an entire folder/file hierarchy? E.g., my app creates /Library/PrivateDocs, and populates that with several folders, sub-folders, and files. Can I just set the do-not-backup attribute on the top-level folder, or must it be set on every individual file and folder under that also?

And, if it must be set on each file/subfolder, what's an efficient way to do so?

Community
  • 1
  • 1
Don Jones
  • 9,367
  • 8
  • 39
  • 49

6 Answers6

25

You could put one specific directory inside the documents dir for this purpose, put everything inside and only mark that single directory as do-not-backup using the

 addSkipBackupAttributeToItemAtURL

method shown in the article you linked, or use this one that uses a path instead of an URL:

+ (void)addSkipBackupAttributeToPath:(NSString*)path {
    u_int8_t b = 1;
    setxattr([path fileSystemRepresentation], "com.apple.MobileBackup", &b, 1, 0, 0);
}

example using a directory:

NSString *docsDirPath = [(AppDelegate*)[[UIApplication sharedApplication] delegate] applicationDocumentsDirectory];
NSString *yourContentsDirPath = [docsDirPath stringByAppendingPathComponent:gContentsDirName];

[Utilities addSkipBackupAttributeToPath:yourContentsDirPath];

[EDIT]

I forgot this method use in the delegate to get the documents dir:

- (NSString *)applicationDocumentsDirectory {

    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : nil;
    return basePath;
}
k1th
  • 1,332
  • 10
  • 25
  • 2
    I had to include #include in older SDK 4.3 APP. – PetrV Jan 06 '12 at 17:48
  • 1
    Do I call this once on app open? or every time I write to the folder? – box86rowh Jan 11 '12 at 14:20
  • if you solve the problem. Then explain it in brief.once on app open? or every time. – Ayaz Mar 28 '12 at 04:03
  • You call this when you create the folder. you don't have to set it every time. only once. – k1th Mar 28 '12 at 07:28
  • Does this work on hidden folders also? If we enable the "external storage" flag on a binary data field in a core data model, core data will create a hidden folder in the same folder as your DB. Unfortunately, you cannot set this attribute using this technique on the hidden folder that gets created. If we move one level higher than where the DB sits and set the do not backup flag will it also fully propagate to hidden folders as well? – radesix Apr 29 '14 at 15:34
9

For all my friends here, who needs in Swift - just look below (iOS8.0)

func addSkipBackupAttributeToItemAtURL(URL:NSURL) ->Bool{

let fileManager = NSFileManager.defaultManager()
assert(fileManager.fileExistsAtPath(URL.absoluteString))

var error:NSError?
let success:Bool = URL.setResourceValue(NSNumber.numberWithBool(true),forKey: NSURLIsExcludedFromBackupKey, error: &error)

if !success{

    println("Error excluding \(URL.lastPathComponent) from backup \(error)")
}

return success;

}
Tharif
  • 13,794
  • 9
  • 55
  • 77
kurtanamo
  • 1,808
  • 22
  • 27
  • this throws an error in swift 2 in line: let success:Bool = URL.setResourceValue(NSNumber.numberWithBool(true),forKey: NSURLIsExcludedFromBackupKey, error: &error) //Extra argument 'error' in call – George Asda Mar 07 '16 at 12:47
  • you're right its changed in swift 2.1 - no more error attribute now – kurtanamo Mar 07 '16 at 13:05
  • I have updated the code for anyone using swift 2 in an answer below – George Asda Mar 07 '16 at 13:42
2

For me, in Swift, the previously answered functions didn't quite work. In particular the assert line failed. I needed to update it from URL.absoluteString! to URL.path! So in the end mine looks like this:

func addSkipBackupAttributeToItemAtURL(URL:NSURL) ->Bool{

    let fileManager = NSFileManager.defaultManager()
    assert(fileManager.fileExistsAtPath(URL.path!))

    var error:NSError?
    let success:Bool = URL.setResourceValue(NSNumber(bool: true),forKey: NSURLIsExcludedFromBackupKey, error: &error)

    if !success{
        println("Error excluding \(URL.lastPathComponent) from backup \(error)")
    }

    return success;
}
1

maybe this would help someone using swift 2:

Just before @UIApplicationMain add this:

extension NSFileManager{
    func addSkipBackupAttributeToItemAtURL(url:NSURL) throws {
        try url.setResourceValue(true, forKey: NSURLIsExcludedFromBackupKey)
    }
}

In your lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator? = { after you declare your URL you can add this:

 do {
            let url = url
            try NSFileManager.defaultManager().addSkipBackupAttributeToItemAtURL(url)

        } catch {
            // Handle error here
            print("Error: \(error)")
        }
George Asda
  • 2,119
  • 2
  • 28
  • 54
-1

Correction on above method,use this for swift

 func addSkipBackupAttributeToItemAtURL(URL:NSURL) ->Bool {

    let fileManager = NSFileManager.defaultManager()
    assert(fileManager.fileExistsAtPath(URL.absoluteString!))

    var error:NSError?
    let success:Bool = URL.setResourceValue(NSNumber(bool: true),forKey: NSURLIsExcludedFromBackupKey, error: &error)

    if !success{

        println("Error excluding \(URL.lastPathComponent) from backup \(error)")
    }

    return success;
}
itsji10dra
  • 4,603
  • 3
  • 39
  • 59
Rahul gupta
  • 129
  • 8
-1

you can do the following in swift:

func addSkipBackupAttributeToItemAtPath(path:String) -> Bool {


    let filePath = path.fileSystemRepresentation()
    let attrName  = "com.apple.MobileBackup"

    var attrValue : uint_fast8_t = 1

    let result = setxattr(filePath, attrName, &attrValue, sizeof(attrValue.dynamicType), 0, 0)

    return result == 0
}
Bobj-C
  • 5,276
  • 9
  • 47
  • 83