转自:http://blog.163.com/ray_jun/blog/static/1670536422011101225132544/
出处:http://superman474.blog.163.com/blog/static/120661462011101115811199/
关于iOS 5的本地文件储存Marco(Instapaper 的开发者)写过一篇很好的帖子阐述过相关问题,有兴趣的同学可以先阅读下他的文章然后再看下文。
在苹果开发者的论坛上也有许多相关问题的讨论贴:
如果我想让文件永久保存且不会和iTunes同步,我该把文件保存在哪里?
几点困惑
在苹果开发者论坛的讨论中,总结出以下几点令人困惑的问题:
- 关于缓存和临时文件目录的含义
- 苹果开发文档的更新修改
- 应用审核被拒
- iTunes和iCloud会备份哪些文件
- iOS 5的机制改变
下面让我们逐个讨论:
关于缓存和临时文件目录的含义
如果你有OS X或者Unix的开发背景,就会很容易明白苹果的立场:即无法保证数据在这两个目录中能持续地保存多久。
实际上在应用沙盒(sandbox)里的临时文件目录(tmp directory)和根目录下临时文件目录(root /tmp)不太相同,但也不需要区别对待这些目录。
过去如果你从没观察到文件在这些目录里被删除,那并不保证以后不会。特别是当这个改变和开发文档说明一致时,这是一个普遍的规律。
苹果开发文档的更新修改
直到2011年6月的官方开发文档中关于 <Application_Home>/Documents 的说法是:
“使用这个目录来存储用户文档和应用数据文件”
这个用法相当明确。而iOS 5改变了Documents 目录用法却不给出任何合适的替代方法,因此难怪开发者感到不高兴。
而关于 <Application_Home>/Library/Caches 的说法是:
“使用这个目录来写入任意应用的专属支持文件,以便你可以使它们在应用程序启动时或者在应用程序更新时保持不变。
你的应用程序通常要负责这些文件的添加和删除,有些情况下也要能够重新创建所需文件,因为iTunes会在恢复模式下删除保存在这里的文件。”
这段话的涵义很不明确。我读完觉得大意是苹果在iOS 5上做了个根本上的改变,而使得看这段说明很矛盾。但是如果你仔细看字眼“通常要”(”generally”)和“能重新创建”(”able to re-create”)的话,在苹果警告你的应用内文件不合规范时,你就会明白那些地方需要改进了。
关于iOS 数据存储指导手册(iOS Data Storage Guidelines)的说明:
“为了尽力确保文件备份高效,请务必根据以下的指导来保存你的应用数据:
1、只有那些用户生成的文档和其他数据或者是那些不能被你的应用所重建的数据应当保存在<Application_Home>/Documents 目录内。这些数据文件将会自动的通过iCloud备份。
2、那些可以重新下载或者重新创建的数据应当保存在<Application_Home>/Library/Caches 目录内。你可以把数据库缓存文件或者可下载的内容如杂志、报纸、地图应用的数据等放入缓存目录里(Caches directory)
3、临时需要的数据应该保存在<Application_Home>/tmp 目录内。尽管这些文件不会备份到iCloud里,请记住在你不再需要它们时立即删除掉这些文件,这样它们就不会继续浪费用户设备的储存空间了。”
事实上许多报纸、杂志和地图的应用单纯的目的就是想离线显示内容,如果我们暂时无视这点,那么以上的指导讲的很清楚,可以去参考。
应用审核被拒
开发者目前报告说那些在Document 目录内保存任意/少量/大量数据的应用正在审核中被拒。
应用审核部门不太可能面面俱到,比如理清楚哪些文件该储存到哪些目录内、哪些文件是用户生成的、哪些数据是可以重新下载或重新被创建的。有些开发者报告中说,他们跟应用审核部门解释清楚应用是如何保存数据、如何遵守指导原则的,之后他们的应用也得到了通过。
iTunes和iCloud会备份哪些文件
应用里home 目录内的所有数据都会被备份除了:
- 编译后的应用包文件 (.app)
- <Application_Home>/tmp 目录内的文件
- <Application_Home>/Library/Caches 目录内的文件
这些在iOS数据储存指导手册上(iOS Data Storage Guidelines)和Michael Jurewitz的评论里已讲的很清楚了。
其他开发文档里也明确的指出Application Support 目录内的文件也会被iTunes备份(假设iCloud也会)。在讨论中有些开发者认为Application Support 目录内保存文件相比Caches 目录更安全点(更加持久)。我觉得应用审核部门会拒掉那些在Application Support 目录内保存大量数据的应用,这和Document 目录内的严格审核是一样的,都是拜iCloud的储存空间不足所赐。
还有些什么值得注意的?
再也没有一个目录可以让你的应用保存文件于其中并可以:
- 不被iTunes或者iCloud备份
- 不会因空间受限而被清除
很明显在iOS 5.0上想做到这些已经迟了。但是如果足够多的开发者据理力争,让苹果知道他们非常需要在自己的应用内保持这个功能,或许下个版本会加入进来。提示:提交文件bug 报告。
开发者要做些什么?
如果你当前正在Documents 目录内保存文件的话
你的应用当然可以继续在iOS 5内正常工作,你的用户可能会抱怨有大量的数据被备份到了iCloud上。(详见以下内容)
然而当你更新你的应用时,可能会因为在Documents目录内保存太多数据而被拒绝通过审核。
如果你正在或者考虑到在Caches 目录内保存文件的话
请确保在Caches 目录内你保存的文件忽然消失的情况下,你的应用依然可以处理妥当。一种处理的方法是,把保存在Caches目录内的所有文件的源URL(原始路径或地址)列入进一个清单里。这样应用通过遍历清单就可以验证文件是否依然存在了。
如果有任何文件消失了你可以显示对话框向用户致歉,解释清原因并询问是否要重新下载文件。假如设备是离线的,你只能对用户致歉然后告诉用户“你完了”。
还有许多比这两种更复杂的情况,例如:分装的数据哪些还能使用。你需要决定显示哪些数据,显示多少等。
一名开发者在苹果论坛上讲的用户使用案例,我觉得很有趣:他的应用是为飞行员显示地图的。 如果他把可以重新下载的地图放到Caches 目录内,那么如果地图数据被iOS 5突然删掉,这时飞机还在天上,可能就悲剧了。让飞行员重新下载地图数据的对话框绝对会深深地伤害到他的感情。
迁移已存在的数据
如果你服从 iOS 5或iCloud的新规则去更新应用并把文件储存到Caches 目录内的话,那么你可能需要把已存放在Document 内的文件转移到 Caches 内。我确信应用审核部分不会去测试这个,因为他们没有你存有数据的老版本应用。但是这样做很对。
记住不要在应用程序启动时的主线程中消耗太多的资源来进行文件转移。这样会使你的应用被启动时间监视程序Kill掉。
提前警告
当应用在运行时,如果设备正处于空间不足的情况下,你可以告知用户。虽然这样不能阻止文件被删掉,但至少可以让用户认识到这个问题的存在。
我不清楚在iOS 5的清除程序运行前,磁盘空间的最低值是多少,并且我也怀疑苹果会给出具体细节。如果你有任何自己试验出的结果请务必在下面添加评论指出。
让苹果意识到这是个很大的问题
提交文件bug 报告(File a bug report)。
用户能做什么?
一直到现在,那些保存许多数据在目录内的应用对于备份来说很头疼,因为iTunes备份它们要花很长的时间。当有许多的文件必须备份时,这种情况尤其恼人。
通过iCloud备份的话,用户们可能不想占用他们那可怜的5GB储存空间(或是花钱购买额外空间)来备份那些他们认为不重要的数据。单个的应用可 以关掉iCloud备份。在应用设置中能很容易的找到设置:iCloud > 储存与备份>管理储存空间>备份。在备份选项列表里每一个应用都可以选择是否备份。可能你的用户不太容易能找出设置,你可能需要发邮件去指导 他们。
这些是我的理解,尽管我还没来得及测试关掉iCloud备份对iTunes的备份是否有影响。但是对于那些再也不用数据线连接电脑来同步的用户,按上述说明关掉iCloud备份的应用是没有备份数据的。
以下函数可使某个路径的文件免于iCloud备份
- (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
NSLog(@"%d",[URL setResourceValue:[NSNumber numberWithBool:YES] forKey:NSURLIsExcludedFromBackupKey error:nil]);
return [URL setResourceValue:[NSNumber numberWithBool:YES] forKey:NSURLIsExcludedFromBackupKey error:nil];
}
}
我的经验:当应用程序曝出如下错误信息时,你的Caches文件夹下的内容可能就被自动删除了。
//空间不足时 malloc: stack logs being written into /private/var/mobile/Containers/Data/Application/819156CF-C8B8-43FF-BF63-0EABF59CB655/tmp/stack-logs.1373.15a3000.esvideo.aQPqEl.index esvideo(1373,0x39c8a9dc) malloc: recording malloc and VM allocation stacks to disk using standard recorder esvideo(1373,0x39c8a9dc) malloc: process 1338 no longer exists, stack logs deleted from /private/var/mobile/Containers/Data/Application/819156CF-C8B8-43FF-BF63-0EABF59CB655/tmp/stack-logs.1338.1508000.esvideo.tYs7hy.index 2015-08-19 15:22:47.000 esvideo[1373:382143] iRate verbose logging enabled.
或
//空间不足时,应用程序奔溃 malloc: Unable to write to stack logging file /private/var/mobile/Containers/Data/Application/F20F8C6C-9709-490A-9DDA-E294C1EF3B50/tmp/stack-logs.1234.1549000.esvideo.mNh6B0.index (No space left on device) esvideo(1234,0x39c8a9dc) malloc: stack logging disabled due to previous errors. 2015-08-19 14:57:06.950 esvideo[1234:373855] Unable to copy temp file. Error: Error Domain=NSCocoaErrorDomain Code=512 "The operation couldn’t be completed. (Cocoa error 512.)" UserInfo=0x19e68e10 {NSSourceFilePathErrorKey=/private/var/mobile/Containers/Data/Application/F20F8C6C-9709-490A-9DDA-E294C1EF3B50/Library/Caches/com.apple.nsurlsessiond/Downloads/com.easou.esvideo/CFNetworkDownload_BHOOzH.tmp, NSUserStringVariant=( Copy ), NSFilePath=/private/var/mobile/Containers/Data/Application/F20F8C6C-9709-490A-9DDA-E294C1EF3B50/Library/Caches/com.apple.nsurlsessiond/Downloads/com.easou.esvideo/CFNetworkDownload_BHOOzH.tmp, NSDestinationFilePath=/var/mobile/Containers/Data/Application/F20F8C6C-9709-490A-9DDA-E294C1EF3B50/Library/Caches/DownLoad/Video/火影忍者605_554cd72c0cf29e8153e068a6/火影忍者605_554cd72c0cf29e8153e068a6_0, NSUnderlyingError=0x19e69b50 "The operation couldn’t be completed. Result too large"}
关于Caches的官方描述:
tmp: Use this directory to write temporary files that do not need to persist between launches of your app. Your app should remove files from this directory when it determines they are no longer needed. Caches: Use this directory to write any app-specific support files that your app can re-create easily. Your app is generally responsible for managing the contents of this directory and for adding and deleting files as needed. In iOS 2.2 and later, the contents of this directory are not backed up by iTunes. In addition, iTunes removes files in this directory during a full restoration of the device. On iOS 5.0 and later, the system may delete the Caches directory on rare occasions when the system is very low on disk space. This will never occur while an app is running. However, you should be aware that iTunes restore is not necessarily the only condition under which the Caches directory can be erased.
转自:http://my.oschina.net/u/1266799/blog/165631
有这样一个问题,用户用iOS设备下载了大量的数据,保存在设备本地,如果用户升级了应用本身,这些文件是否仍然存在。
找了一些官方解释和Stackflow上的说明
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 inside your app’s home directory. 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:
-
Put user data in the <Application_Home>/Documents/. User data is any data that cannot be recreated by your app, such as user documents and other user-generated content.
-
Handle support files—files your application downloads or generates and can recreate as needed—in one of two ways:
-
In iOS 5.0 and earlier, put support files in the <Application_Home>/Library/Caches directory to prevent them from being backed up
-
In iOS 5.0.1 and later, put support files in the <Application_Home>/Library/Application Support directory and apply thecom.apple.MobileBackup extended attribute to them. This attribute prevents the files from being backed up to iTunes or iCloud. If you have a large number of support files, you may store them in a custom subdirectory and apply the extended attribute to just the directory.
-
-
Put data cache files in the <Application_Home>/Library/Caches directory. Examples of files you should put in this directory include (but are not limited to) database cache files and downloadable content, such as that used by magazine, newspaper, and map apps. Your app should be able to gracefully handle situations where cached data is deleted by the system to free up disk space.
-
Put temporary data in the <Application_Home>/tmp directory. Temporary data comprises any data that you do not need to persist for an extended period of time. Remember to delete those files when you are done with them so that they do not continue to consume space on the user’s device.
也就是说,一般从网上下载的那些内容,包括杂志、报纸、视频什么的,都要放在 <Application_Home> /Library/Caches 目录下面
<Application_Home>/Library/ |
This directory is the top-level directory for files that are not user data files. You typically put files in one of several standard subdirectories but you can also create custom subdirectories for files you want backed up but not exposed to the user. You should not use this directory for user data files. The contents of this directory (with the exception of the Caches subdirectory) are backed up by iTunes. For additional information about the Library directory, see “The Library Directory Stores App-Specific Files.” |
Library目录下面的内容,也会被被iTunes备份,但是Caches目录除外,也就是说这些网络下载内容文件放在这里是不会被备份的,
Caches |
Use this directory to write any app-specific support files that your app can re-create easily. Your app is generally responsible for managing the contents of this directory and for adding and deleting files as needed. In iOS 2.2 and later, the contents of this directory are not backed up by iTunes. In addition, iTunes removes files in this directory during a full restoration of the device. On iOS 5.0 and later, the system may delete the Caches directory on rare occasions when the system is very low on disk space. This will never occur while an app is running. However, you should be aware that iTunes restore is not necessarily the only condition under which the Caches directory can be erased. |
上面写的的比较清楚,Library/Caches目录下,一般情况下是不会被删除的,我理解,也包括stackoverflow网友的证明,应用升级的时候也不会被删除,实际上,应用升级的具体系统操作是这样的:
Files Saved During Application Updates When a user downloads an application update, iTunes installs the update in a new application directory. It then moves the user’s data files from the old installation over to the new application directory before deleting the old installation. Files in the following directories are guaranteed to be preserved during the update process:
- Application_Home/Documents
- Application_Home/Library
Although files in other user directories may also be moved over, you should not rely on them being present after an update.
系统先新建一个应用目录,然后安装一个新版本应用,然后再把旧版本的应用数据拷贝过来,然后再删除旧版本的应用安装目录。
最后注意一下,Library/Caches目录下的数据虽然在一般情况下不会被删除,但是在系统恢复和其他一些罕见的情况下(比如非常底的磁盘空间条件下有可能)会被清除,所以你的程序每次都要检查一些,这些文件都还在不在了,不在的话只能重新下了。
Application_Home/Library/Caches Use this directory to write any application-specific support files that you want to persist between launches of the application or during application updates. Your application is generally responsible for adding and removing these files. It should also be able to re-create these files as needed because iTunes removes them during a full restoration of the device. In iOS 2.2 and later, the contents of this directory are not backed up by iTunes.
参考连接:http://stackoverflow.com/questions/7155964/will-application-home-library-caches-be-clear-on-app-update/7277797#7277797
File System Programming Guide
https://developer.apple.com/library/ios/documentation/FileManagement/Conceptual/FileSystemProgrammingGuide/FileSystemOverview/FileSystemOverview.html#//apple_ref/doc/uid/TP40010672-CH2-SW1