xcode 保存在 NSDocumentDirectory 中好吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11632636/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
is saving in NSDocumentDirectory okay?
提问by Bazinga
My app is using the NSDocumentDirectory
to save images in it, I just wanna ask if its the safe way to save images(100 maximum). I have read several thread & questions with answers about it, though I dont know which to follow.Some say that its okay to save there. Some say I shouldnt use NSDocumentDirectory
for saving, because it will be back-up by the iCloud
. So where can I save it that when the user exit the app then run the app again, then images should still be there?. I dont know much about the tmp
directory or cache
directory. But if its either one of the 2 that I should use, How can I use them in my code here:
我的应用程序正在使用NSDocumentDirectory
将图像保存在其中,我只是想问问它是否是保存图像的安全方式(最多 100 个)。我已经阅读了几个线程和问题的答案,但我不知道该关注哪个。有人说可以保存在那里。有人说我不应该用它NSDocumentDirectory
来保存,因为它会被iCloud
. 那么我在哪里可以保存它,当用户退出应用程序然后再次运行应用程序时,图像应该仍然存在?我不太了解tmp
目录或cache
目录。但是,如果它是我应该使用的 2 个之一,我如何在我的代码中使用它们:
NSArray *paths = NSSearchPathForDirectoriesInDomains( NSDocumentDirectory, NSUserDomainMask ,YES );
NSString *documentsDir = [paths objectAtIndex:0];
NSString *savedImagePath = [documentsDir stringByAppendingPathComponent:[NSString stringWithFormat:@"Images%d.png", i]];
ALAssetRepresentation *rep = [[info objectAtIndex: i] defaultRepresentation];
UIImage *image = [UIImage imageWithCGImage:[rep fullResolutionImage]];
//----resize the images
image = [self imageByScalingAndCroppingForSize:image toSize:CGSizeMake(256,256*image.size.height/image.size.width)];
NSData *imageData = UIImagePNGRepresentation(image);
[imageData writeToFile:savedImagePath atomically:YES];
Thank you so much for the help.
十分感谢你的帮助。
回答by andycam
The tmp
and cache
directories are periodically cleaned up by iOS. If the images are for general use, use the camera roll as the other two answers suggest. However if these images are intended just for the scope of your app, you can still safely store them in the Documents directory, you just have to include an "exclude from iCloud backup" function call to each file after saving, in order to prevent Apple rejecting your app for using too much iCloud space. Of course there's a trade-off, disabling this means the user will lose their photos anyway should they delete the app or get another device(etc), but this caveat is preferable to not getting the App on the store at all.
该tmp
和cache
目录定期的iOS清理。如果图像用于一般用途,请按照其他两个答案的建议使用相机胶卷。但是,如果这些图像仅用于您的应用程序范围,您仍然可以安全地将它们存储在 Documents 目录中,您只需在保存后对每个文件包含“从 iCloud 备份中排除”函数调用,以防止 Apple拒绝您的应用程序使用过多的 iCloud 空间。当然有一个权衡,禁用这意味着用户无论如何都会丢失他们的照片,如果他们删除应用程序或获取另一台设备(等),但这个警告比根本不在商店中获取应用程序更可取。
To disable iCloud backup on a file, there's two methods for iOS versions > 5.0:
要在文件上禁用 iCloud 备份,iOS 版本 > 5.0 有两种方法:
UPDATE! MERGED BOTH METHODS INTO A SINGLE FUNCTION THAT AUTOMATICALLY HANDLES iOS VERSION:
更新!将两种方法合并为一个自动处理 iOS 版本的函数:
#include <sys/xattr.h> // Needed import for setting file attributes
+(BOOL)addSkipBackupAttributeToItemAtURL:(NSURL *)fileURL {
// First ensure the file actually exists
if (![[NSFileManager defaultManager] fileExistsAtPath:[fileURL path]]) {
NSLog(@"File %@ doesn't exist!",[fileURL path]);
return NO;
}
// Determine the iOS version to choose correct skipBackup method
NSString *currSysVer = [[UIDevice currentDevice] systemVersion];
if ([currSysVer isEqualToString:@"5.0.1"]) {
const char* filePath = [[fileURL path] fileSystemRepresentation];
const char* attrName = "com.apple.MobileBackup";
u_int8_t attrValue = 1;
int result = setxattr(filePath, attrName, &attrValue, sizeof(attrValue), 0, 0);
NSLog(@"Excluded '%@' from backup",fileURL);
return result == 0;
}
else if (&NSURLIsExcludedFromBackupKey) {
NSError *error = nil;
BOOL result = [fileURL setResourceValue:[NSNumber numberWithBool:YES] forKey:NSURLIsExcludedFromBackupKey error:&error];
if (result == NO) {
NSLog(@"Error excluding '%@' from backup. Error: %@",fileURL, error);
return NO;
}
else { // Succeeded
NSLog(@"Excluded '%@' from backup",fileURL);
return YES;
}
} else {
// iOS version is below 5.0, no need to do anything
return YES;
}
}
If your app must support 5.0, then unfortunately your only option is to save those photos in the Caches directory, which means they won't be backed up (this not causing an App Store rejection for that reason), but whenever the storage watchdog decides it's time to clean the Caches folder, you'll lose those photos. Not an ideal implementation at all, but such is the nature of the beast in 5.0, where Apple added in Backup exclusion as an afterthought.
如果您的应用程序必须支持 5.0,那么不幸的是,您唯一的选择是将这些照片保存在 Caches 目录中,这意味着它们将不会被备份(这不会导致 App Store 因该原因被拒绝),但只要存储看门狗决定是时候清理 Caches 文件夹了,你会丢失那些照片。根本不是一个理想的实现,但这就是 5.0 中野兽的本质,Apple 事后添加了备份排除。
EDIT:Forgot to answer the 'how to save to the tmp/cache directory' part of the question. If you do decide to go down that path:
编辑:忘记回答问题的“如何保存到 tmp/cache 目录”部分。如果你决定走这条路:
Saving to
tmp
:NSString *tempDir = NSTemporaryDirectory(); NSString *savedImagePath = [tempDir stringByAppendingPathComponent:[NSString stringWithFormat:@"Images%d.png", i]];
保存到
tmp
:NSString *tempDir = NSTemporaryDirectory(); NSString *savedImagePath = [tempDir stringByAppendingPathComponent:[NSString stringWithFormat:@"Images%d.png", i]];
(note that this won't appear to have any effect in the simulator, but it works as expected on device)
(请注意,这在模拟器中似乎没有任何影响,但在设备上按预期工作)
Saving to
Cache
:NSString *cacheDir = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory,NSUserDomainMask,YES)lastObject]; NSString *savedImagePath = [cacheDir stringByAppendingPathComponent:[NSString stringWithFormat:@"Images%d.png", i]];
保存到
Cache
:NSString *cacheDir = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory,NSUserDomainMask,YES)lastObject]; NSString *savedImagePath = [cacheDir stringByAppendingPathComponent:[NSString stringWithFormat:@"Images%d.png", i]];
回答by Christopher Matsumoto
If you want the user to be able to use the images in other apps or view them along with their photos, use the photo album as Mike D suggest. If the files are something you generate locally for use with your app only, then you should probably use the documents directory. You can expose the documents directory to iTunes with the info.plist option "Application supports iTunes file sharing" which will allow the user to add or delete files through iTunes, but the files will not be exposed to other apps
如果您希望用户能够在其他应用程序中使用图像或查看它们以及他们的照片,请按照 Mike D 的建议使用相册。如果这些文件是您在本地生成的仅用于您的应用程序,那么您可能应该使用文档目录。您可以使用 info.plist 选项“应用程序支持 iTunes 文件共享”将文档目录公开给 iTunes,这将允许用户通过 iTunes 添加或删除文件,但文件不会公开给其他应用程序
回答by spring
You are saving scaled images so they are really only useful for your game. They are not going to be very large and will not take up much space. You could save them in the Library directory for the app and avoid the whole iCloud thing, as it doesn't sound like there is any reason to back them up. Also, saving the the Library avoid the possibility of the user deleting them, if for some other reason you have iTunes sharing turned on.
您正在保存缩放图像,因此它们实际上只对您的游戏有用。它们不会很大,也不会占用太多空间。您可以将它们保存在应用程序的库目录中,并避免整个 iCloud 事情,因为听起来没有任何理由备份它们。此外,如果由于某些其他原因您打开了 iTunes 共享,保存库可避免用户删除它们的可能性。
Update:code for saving to the app Library directory
更新:保存到应用程序库目录的代码
- (void)saveSequences:(NSMutableDictionary*)sequences
{
NSArray *path = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);
NSString *libDirectory = [path objectAtIndex:0];
NSString *settingsPath = [libDirectory stringByAppendingPathComponent:@"userSequences.plist"];
NSLog(@"settingsPath %@", settingsPath);
[sequences writeToFile:settingsPath atomically:YES];
}
// The code below gets the path to a named directory in the 'Documents' folder - and if it doesn't exist, creates it. Adjust it to use the Library path, if you decide to go that route.
// 下面的代码获取“文档”文件夹中命名目录的路径 - 如果它不存在,则创建它。如果您决定走那条路,请调整它以使用库路径。
- (NSString *)getDirectoryBySequenceName:(NSString *)sequenceName
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString * documentDirectory = [paths objectAtIndex:0];
NSString * sequenceDirectory = [documentDirectory stringByAppendingPathComponent:sequenceName];
NSError *error;
BOOL success = [[NSFileManager defaultManager] createDirectoryAtPath:sequenceDirectory
withIntermediateDirectories:YES
attributes:nil error:&error];
if (!success) {
NSLog(@"Error creating data path: %@", [error localizedDescription]);
}
return sequenceDirectory;
}
回答by Mike D
Depending on the purpose of your app, you could save it to the photos app (UIImageWriteToSavedPhotosAlbum(image, self, nil, nil)
I think, Apple reference). Saving here, or in the documents directory (or any sub folder), will allow the user backup those images to iCloud or iTunes, if the user chooses too and/or if they have set up iCloud.
根据您的应用程序的用途,您可以将其保存到照片应用程序(UIImageWriteToSavedPhotosAlbum(image, self, nil, nil)
我认为,Apple 参考)。保存在此处或文档目录(或任何子文件夹)中,将允许用户将这些图像备份到 iCloud 或 iTunes,如果用户也选择和/或如果他们已经设置了 iCloud。
Since you state the images need to persist between launches, the temp or cache directory get emptied when the application is removed from memory, maybe sooner (the O/S decides).
由于您声明图像需要在启动之间保持不变,因此当应用程序从内存中删除时,临时或缓存目录会被清空,可能会更快(操作系统决定)。