我的其中一个应用程序非常偶尔会将其存储(通过设置 - >常规 - >使用 - >存储)报告为4GB,实际上,应用程序沙箱(文档,库,tmp)中所有文件的总大小平均值大约10MB左右.
我有点在我的智慧结束,并想知道是否有人经历过这样的事情.我怀疑这是与UIDocument有关的东西,但不能肯定.现在提交雷达似乎太少了.
在某些情况下,应用程序将强制系统显示一个对话框,警告用户系统存储空间不足.当发生这种情况时,似乎系统会协调它认为应用程序正在使用的存储与现实之间的差异,然后存储数量将下降到10MB左右.
这真的很奇怪.
关于我可能会看到的事情的任何想法将不胜感激.
contentsForType的实现:错误:
- (id) contentsForType: (NSString *) inTypeName
error: (NSError **) outError
{
NSFileWrapper *newWrapper, *audioFileWrapper;
NSString *audioFilename;
NSURL *newAudioWrapperURL;
newWrapper = [[[NSFileWrapper alloc] initDirectoryWithFileWrappers: nil] autorelease];
// add updated info
[newWrapper addRegularFileWithContents: [NSKeyedArchiver archivedDataWithRootObject: self.testInfo] preferredFilename: QSDocumentInfoKey];
// scan audio files and clean up where needed
for (NSDictionary *wordInfo in self.wordInfoList) {
if ((audioFilename = [wordInfo objectForKey: QSInfoAudioKey]) != nil) {
newAudioWrapperURL = [self.fileURL URLByAppendingPathComponent: audioFilename];
if ([[NSFileManager defaultManager] …Run Code Online (Sandbox Code Playgroud) 我有一个基于NSDocument的应用程序,它使用filewrappers来保存和加载其数据.该文档可以拥有各种资源,因此我不想将所有内容加载到内存中.我可能会做一些根本错误的事情,但是一旦我更改了一个(内部)文件然后保存,我就无法读取任何尚未加载到内存中的文件.
我已将相关代码分离到一个单独的项目中以重现此行为,并得到相同的结果.基本流程如下:
如果用户想要编辑其他文件(sub2),则无法加载.出现的错误:
-[NSFileWrapper regularFileContents] tried to read the file wrapper's contents lazily but an error occurred: The file couldn’t be opened because it doesn’t exist.
Run Code Online (Sandbox Code Playgroud)这是我项目中的相关代码:
此代码可能更容易阅读这个要点:https: //gist.github.com/bob-codingdutchmen/6869871
#define FileName01 @"testfile1.txt"
#define FileName02 @"testfile2.txt"
/**
* Only called when initializing a NEW document
*/
-(id)initWithType:(NSString *)typeName error:(NSError *__autoreleasing *)outError {
self = [self init];
if (self) {
self.myWrapper = [[NSFileWrapper alloc] initDirectoryWithFileWrappers:nil]; …Run Code Online (Sandbox Code Playgroud) 我正在尝试UIDocument使用a 导出我的子类UIDocumentPickerViewController.子类将数据写入a FileWrapper并且其UTI符合com.apple.package.
但是,所提供的文档选择器显示"iCloud Drive中的文档无法使用,因为iCloud Drive设置已禁用."

正如我从导出的容器包中看到的那样,文档已成功写入缓存.
当我更改文档子类和自定义UTI以符合单个文件(例如public.plain-text)时,文档选择器工作正常,我可以导出文件.所以问题似乎与文档类型或导出的UTI有关.
我做错了什么或这是一个错误?
的Info.plist
<key>CFBundleDocumentTypes</key>
<array>
<dict>
<key>CFBundleTypeIconFiles</key>
<array/>
<key>CFBundleTypeName</key>
<string>Custom Doc</string>
<key>LSHandlerRank</key>
<string>Owner</string>
<key>LSItemContentTypes</key>
<array>
<string>com.zxzxlch.documentsandbox.customdoc</string>
</array>
<key>LSTypeIsPackage</key>
<true/>
</dict>
</array>
...
<key>UTExportedTypeDeclarations</key>
<array>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>com.apple.package</string>
</array>
<key>UTTypeDescription</key>
<string>Custom Doc File</string>
<key>UTTypeIdentifier</key>
<string>com.zxzxlch.documentsandbox.customdoc</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>zzz</string>
</array>
</dict>
</dict>
</array>
Run Code Online (Sandbox Code Playgroud)
CustomDocument.swift
private let textFilename = "contents.txt"
class CustomDocument: UIDocument {
var content = "Test"
override func load(fromContents contents: Any, …Run Code Online (Sandbox Code Playgroud) 给定一个NSFileWrapper对象(对于文件或目录),有没有办法获得磁盘上实际文件位置的完整路径?
[fileWrapper filename] 只返回文件名,而不是路径,所以它不是我想要的.
我有一个使用基于NSFileWrapper的UIDocument的应用程序.我的文件包装器是一个名为"XXX.cp"的目录,有两个子文件"photo.data"和"photo.metadata".它似乎可以保存和加载文档,但是当我转到Settings\Manage Storage\Unknown时,子文件会单独列出:

我期待它显示"XXX.cp"而不是这两个子文件.我想我已经正确设置并导出文件UTI:

我认为我正在创建文件包装器(特别是因为它读/写正常):
- (void)encodeObject:(id<NSCoding>)object toWrappers:(NSMutableDictionary *)wrappers preferredFilename:(NSString *)preferredFilename {
@autoreleasepool {
NSMutableData * data = [NSMutableData data];
NSKeyedArchiver * archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
[archiver encodeObject:object forKey:@"data"];
[archiver finishEncoding];
NSFileWrapper * wrapper = [[NSFileWrapper alloc] initRegularFileWithContents:data];
[wrappers setObject:wrapper forKey:preferredFilename];
}
}
- (id)contentsForType:(NSString *)typeName error:(NSError *__autoreleasing *)outError {
if (self.captionedPhotoMetadata == nil || self.captionedPhoto == nil) {
*outError = [[NSError alloc] initWithDomain:CaptionedPhotoErrorDomain code:CaptionedPhotoInvalidDocument userInfo:[NSDictionary dictionaryWithObjectsAndKeys:NSLocalizedString(@"Invalid document!", @""), NSLocalizedDescriptionKey, nil]];
return nil;
}
NSMutableDictionary * wrappers = [NSMutableDictionary dictionary]; …Run Code Online (Sandbox Code Playgroud) 我正在制作一个基于文档的Cocoa应用程序,其中文档是动态的文件集合(用户可以添加或删除文件).特别是,保存和打开操作应该尽可能快.
如果我正确理解文档,我应该使用NSFileWrapper并实现fileWrapperOfType:error和readFromFileWrapper:ofType:error:.但是,我找不到完整的代码示例.我该如何实现以下方法?
#pragma mark - NSDocument
- (NSFileWrapper *)fileWrapperOfType:(NSString *)typeName error:(NSError **)outError {
return nil;
}
- (BOOL)readFromFileWrapper:(NSFileWrapper *)fileWrapper ofType:(NSString *)typeName error:(NSError **)outError {
return YES;
}
#pragma mark - My methods
- (void) addFileToDocumentFromURL:(NSURL*)fileURL {
// Add a file to the document given the file URL
}
- (void) removeFileFromDocumentWithName:(NSString*)name {
// Remove a file from the document given the file name
}
Run Code Online (Sandbox Code Playgroud) 我正在使用NSFileWrapper我的包文件.有时,当我请求包中的文件数据时,我得到了nil.
这是我查询包内文件数据的方法:
- (NSData*) dataOfFile(NSString*)filename {
NSFileWrapper *fileWrapper = [self.documentFileWrapper.fileWrappers objectForKey:filename];
return fileWrapper.regularFileContents; // This returns nil sometimes. Why?
}
Run Code Online (Sandbox Code Playgroud)
对于某些文件(并非所有文件),此方法最终开始返回nil.可悲的是,我没有设法一致地重现这个问题.
如果它有帮助,这就是我打开包的方式:
- (BOOL) readFromFileWrapper:(NSFileWrapper *)fileWrapper ofType:(NSString *)typeName error:(NSError *__autoreleasing *)outError {
self.documentFileWrapper = fileWrapper;
return YES;
}
Run Code Online (Sandbox Code Playgroud)
这是我更新包内文件数据的方法:
- (void) updateFile:(NSString*)filename withData:(NSData*)data {
SBFileWrapper *fileWrapper = [self.documentFileWrapper.fileWrappers objectForKey:filename];
if (fileWrapper) {
[self.documentFileWrapper removeFileWrapper:fileWrapper];
}
NSFileWrapper *fileWrapper = [[SBFileWrapper alloc] initRegularFileWithContents:data ];
fileWrapper.preferredFilename = filename;
[self.documentFileWrapper addFileWrapper:fileWrapper];
}
Run Code Online (Sandbox Code Playgroud)
这是我保存包的方式:
- (NSFileWrapper*) fileWrapperOfType:(NSString *)typeName error:(NSError *__autoreleasing *)outError …Run Code Online (Sandbox Code Playgroud) 我有一个UIDocument基于应用程序,使用NSFileWrappers来存储数据.'master'文件包装器包含许多其他目录文件包装器,每个包装器代表文档的不同页面.
保存仅修改了一页的一小部分的大型文档UIDocument时,在后台花费很长时间写入更改(in writeContents:andAttributes:safelyToURL:forSaveOperation:error:).当然它应该只写出这个文件包装器的一个小改动......什么花了这么长时间?
我的contentsForType:error:覆盖返回一个新的目录文件包装器,其中包含主文件包装器的内容(例如,WWDC 2012会话218 - 使用带有UIDocument的iCloud):
- (id)contentsForType:(NSString *)typeName error:(NSError *__autoreleasing *)outError
{
if (!_fileWrapper) {
[self setupEmptyDocument];
}
return [[NSFileWrapper alloc] initDirectoryWithFileWrappers:[_fileWrapper fileWrappers]];
}
Run Code Online (Sandbox Code Playgroud)
这里是Time Profiler的堆栈跟踪的可爱图片:

顺便提一下,它表示要保存的工作线程约为1.6s - 在实际运行时间内,这相当于大约8秒.
编辑:
有什么方法可以检查文件包装器是否需要写入磁盘?正因为如此,我可以确认我做某些奇怪的事情,比如当我做一个小改动时更新每个子文件包装器(尽管我确定我不是......).
编辑:
我进一步使用了CloudNotes示例应用程序,看起来NSFileWrapper 确实实现了增量保存,至少在这种情况下!我通过初始化一个包含100个音符的文档来测试它,每个音符包含大约5MB的数据.我在这里和那里做了一个小编辑(文本视图的单个字符更改将文档标记为需要保存),并大致记录每次保存所花费的时间.测试相对粗糙(并在模拟器上运行),但结果是这样的:
显然有很多因素会影响它所花费的时间,特别是因为它在后台线程中使用文件协调来节省,但总的来说趋势似乎总是这种指数衰减,直到所有写入变得非常快.
但我仍然想弄清楚为什么这不会发生在我的应用程序中.对于大型多页文档(大型,但仍然比我上面执行的CloudNotes测试的文档小很多倍),用户可以等待很多秒才能关闭文档.我不想把旋转器放在一个应该是瞬间的东西上.
我有一个relativley简单的应用程序,它将数据保存到位于文档文件夹中的plist文件中.数据在启动时加载到UITableView中.然后,用户可以编辑,删除或添加记录,任何更改都会保存回plist文件.
现在我想使用iCloud跨设备共享此数据(plist文件).我查看了文档,我的理解是我需要创建一个UIDocument来"管理"plist文件.
我查看了几个iCloud教程,但是它们都在UIDocument类的属性中存储了一个简单的字符串,而不是整个文件(如plist).
如何使用UIDocument对象将我的plist文件(或任何其他文件)与iCloud共享?
我会将plist文件内容转换为NSData,然后将其保存在UIDocument中的属性中吗?我应该使用NsFileWrapper吗?
我似乎很难绕着UIDocument/iCloud安排我的脑袋.我可能会让它变得更加复杂.
我正在研究使用UIDocumenten NSFileWrapper来存储包含大量视频文件和一些小文本文件的"项目".我遇到了一些问题,我开始怀疑UIDocument是否仍然是正确的策略.
性能
据我所知,NSFileWrapper将所有内容加载到内存中.使用大型视频文件时,这可能是一个问题.我认为可以通过使用放弃标准的自定义保存和加载方法来解决这个问题NSFileWrapper.
元数据
我想显示所有文档的列表以及一些元数据.这可以例如包括预览图像,记录的场景的数量,视频的长度等.现在获取该数据的唯一方法是打开每个文档并检索它.可能很慢,特别是对于大型文档.
解决方案?
我现在看到两个解决方案:完全抛弃UIDocument并转向自定义架构,或者使用某种集中式元数据文件.后者的缺点是我必须在两个不同的地方管理元数据,我需要手动保持它们同步.
UIDocument仍然是去这里的方式,如果是这样的话:什么可以解决这些问题?
nsfilewrapper ×10
ios ×6
uidocument ×4
cocoa ×3
icloud ×3
macos ×3
nsdocument ×3
objective-c ×3
ipad ×1
iphone ×1
metadata ×1
performance ×1
persistence ×1
plist ×1
save ×1
uti ×1