沙盒存储踩坑总结

2018-09-26  本文已影响0人  陈_振

Path-based URL,File reference URL,String-based path区别

All of the following entries are valid references to a file called MyFile.txt in a user’s Documents directory:

Path-based URL: 
file://localhost/Users/steve/Documents/MyFile.txt

File reference URL: 
file:///.file/id=6571367.2773272/

String-based path:  
/Users/steve/Documents/MyFile.txt

存储文件路径尽可能地使用NSURL(Path-based URL)。因为基于路径的url更容易操作、更容易调试,而且通常是NSFileManager等类的首选。

File reference URL的优点是,在程序运行时,如果用户在Finder中移动文件,任何Path-based URL都会失效,必须更新到新的路径。但是,只要文件在同一磁盘上移动,它的唯一ID就不会改变,任何File reference URL都一直有效。有一点需要注意,系统重启后,File reference URL可能会改变。

  1. NSString 转 NSURL 时,NSString不能包含空格,否则转换得到的NSURL为nil

  2. 使用- (BOOL)moveItemAtURL:toURL: error:使用该方法时,两个URL参数都要确保是fileURL(路径字符串以file:开头),否则会无法move。使用如下方法将NSString转为NSURL:
    [NSURL fileURLWithPath:@"/desktop/."]

  3. 将图片保存到本地后,千万不要保存全路径,比如:/var/mobile/Containers/Data/Application/E710C3F0-844A-420C-91D9-016D06B22A36/Library/Caches/VideoThumbnails/20180821224508.png

只存储自己创建的目录及文件路径即可(上面例子Caches/之后的路径),取数据的时候再通过系统提供的接口(NSHomeDiretory())等方法去拼接完整路径。

原因是每一个App的沙盒路径在运行时会改变,不是唯一确定的值。

File System

An iOS app operating within its own sandbox directory:

屏幕快照 2018-09-25 下午4.10.58.png

Where You Should Put Your App’s Files

To prevent the syncing and backup processes on iOS devices from taking a long time, be selective about where you place files. Apps that store large files can slow down the process of backing up to iTunes or iCloud. These apps can also consume a large amount of a user's available storage, which may encourage the user to delete the app or disable backup of that app's data to iCloud. With this in mind, you should store app data according to the following guidelines:

Files, Concurrency, and Thread Safety

Because file-related operations involve interacting with the hard disk and are therefore slow compared to most other operations, most of the file-related interfaces in iOS and macOS are designed with concurrency in mind. Several technologies incorporate asynchronous operation into their design and most others can execute safely from a dispatch queue or secondary thread. Table 1-4 lists some of the key technologies discussed in this document and whether they are safe to use from specific threads or any thread. For specific information about the capabilities of any interface, see the reference documentation for that interface.

屏幕快照 2018-09-25 下午4.14.34.png

It's good habit to alloc/init the file manager for move/copy operations, just in case you decide to add a delegate later.

为App中的文件创建自定义目录

- (NSURL*)applicationDirectory
{
    NSString* bundleID = [[NSBundle mainBundle] bundleIdentifier];
    NSFileManager*fm = [NSFileManager defaultManager];
    NSURL*    dirPath = nil;
 
    // Find the application support directory in the home directory.
    NSArray* appSupportDir = [fm URLsForDirectory:NSApplicationSupportDirectory
                                    inDomains:NSUserDomainMask];
    if ([appSupportDir count] > 0)
    {
        // Append the bundle ID to the URL for the
        // Application Support directory
        dirPath = [[appSupportDir objectAtIndex:0] URLByAppendingPathComponent:bundleID];
 
        // If the directory does not exist, this method creates it.
        // This method is only available in macOS 10.7 and iOS 5.0 or later.
        NSError*    theError = nil;
        if (![fm createDirectoryAtURL:dirPath withIntermediateDirectories:YES
                   attributes:nil error:&theError])
        {
            // Handle the error.
 
            return nil;
        }
    }
 
    return dirPath;
}

拷贝,移动文件或目录

- (void)backupMyApplicationData {
   // Get the application's main data directory
   NSArray* theDirs = [[NSFileManager defaultManager] URLsForDirectory:NSApplicationSupportDirectory
                                 inDomains:NSUserDomainMask];
   if ([theDirs count] > 0)
   {
      // Build a path to ~/Library/Application Support/<bundle_ID>/Data
      // where <bundleID> is the actual bundle ID of the application.
      NSURL* appSupportDir = (NSURL*)[theDirs objectAtIndex:0];
      NSString* appBundleID = [[NSBundle mainBundle] bundleIdentifier];
      NSURL* appDataDir = [[appSupportDir URLByAppendingPathComponent:appBundleID]
                               URLByAppendingPathComponent:@"Data"];
 
      // Copy the data to ~/Library/Application Support/<bundle_ID>/Data.backup
      NSURL* backupDir = [appDataDir URLByAppendingPathExtension:@"backup"];
 
      // Perform the copy asynchronously.
      dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
         // It's good habit to alloc/init the file manager for move/copy operations,
         // just in case you decide to add a delegate later.
         NSFileManager* theFM = [[NSFileManager alloc] init];
         NSError* anError;
 
         // Just try to copy the directory.
         if (![theFM copyItemAtURL:appDataDir toURL:backupDir error:&anError]) {
            // If an error occurs, it's probably because a previous backup directory
            // already exists.  Delete the old directory and try again.
            if ([theFM removeItemAtURL:backupDir error:&anError]) {
               // If the operation failed again, abort for real.
               if (![theFM copyItemAtURL:appDataDir toURL:backupDir error:&anError]) {
                  // Report the error....
               }
            }
         }
 
      });
   }
}
上一篇 下一篇

猜你喜欢

热点阅读