Что указывает префикс /private на пути к файлу iOS?
У меня есть ошибка, когда мое приложение работает на iPhone, но не тогда, когда оно запускается на симуляторе. Я использовал длину пути к домашнему каталогу для извлечения относительного пути файла в /Documents. К сожалению, это не всегда корректно работает на iPhone, потому что префикс "/private" добавляется к домашнему пути. Однако с префиксом или без него на тот же файл ссылаются ok. Следующий код демонстрирует эту несогласованность. Какова цель "/private" и когда она предоставляется iOS?
- (IBAction)testHomepath:(id)sender {
NSFileManager *fmgr = [NSFileManager defaultManager];
NSString *homePath = [NSString stringWithFormat:@"%@/Documents",NSHomeDirectory()];
NSString *dirPath = [homePath stringByAppendingPathComponent:@"TempDir"];
NSURL *dirURL = [NSURL fileURLWithPath:dirPath];
NSString *filePath = [dirPath stringByAppendingPathComponent:@"test.jpg"];
[fmgr createDirectoryAtPath:dirPath withIntermediateDirectories:NO attributes:nil error:nil];
[fmgr createFileAtPath:filePath contents:nil attributes:nil];
NSArray *keys = [[NSArray alloc] initWithObjects:NSURLNameKey,nil];
NSArray *files = [fmgr contentsOfDirectoryAtURL:dirURL includingPropertiesForKeys:keys options:0 error:nil];
NSURL *f1 = (files.count>0)? [files objectAtIndex:0] : 0;
NSURL *f2 = (files.count>1)? [files objectAtIndex:1] : 0;
bool b0 = [fmgr fileExistsAtPath:filePath];
bool b1 = [fmgr fileExistsAtPath:f1.path];
bool b2 = [fmgr fileExistsAtPath:f2.path];
NSLog(@"File exists=%d at path:%@",b0,filePath);
NSLog(@"File exists=%d at path:%@",b1,f1.path);
NSLog(@"File exists=%d at path:%@",b2,f2.path);
}
При работе на iPhone записывается в журнал. Я вручную отделил вывод, чтобы показать разницу между строками 1 и 2.
2013-02-20 16:31:26.615 Test1[4059:907] File exists=1 at path: /var/mobile/Applications/558B5D82-ACEB-457D-8A70-E6E00DB3A484/Documents/TempDir/test.jpg
2013-02-20 16:31:26.622 Test1[4059:907] File exists=1 at path:/private/var/mobile/Applications/558B5D82-ACEB-457D-8A70-E6E00DB3A484/Documents/TempDir/test.jpg
2013-02-20 16:31:26.628 Test1[4059:907] File exists=0 at path:(null)
При работе на симуляторе записывается следующее сообщение (нет "/private" ):
2013-02-20 16:50:38.730 Test1[7224:c07] File exists=1 at path:/Users/kenm/Library/Application Support/iPhone Simulator/6.1/Applications/C6FDE177-958C-4BF5-8770-A4D3FBD281F1/Documents/TempDir/test.jpg
2013-02-20 16:50:38.732 Test1[7224:c07] File exists=1 at path:/Users/kenm/Library/Application Support/iPhone Simulator/6.1/Applications/C6FDE177-958C-4BF5-8770-A4D3FBD281F1/Documents/TempDir/.DS_Store
2013-02-20 16:50:38.733 Test1[7224:c07] File exists=1 at path:/Users/kenm/Library/Application Support/iPhone Simulator/6.1/Applications/C6FDE177-958C-4BF5-8770-A4D3FBD281F1/Documents/TempDir/test.jpg
Ответы
Ответ 1
Я попробовал это из отладчика и обнаружил, что URLByResolvingSymlinksInPath
"исправляет" дополнение /private/
.
(lldb) p (NSURL *)[NSURL fileURLWithPath:@"/private/var" isDirectory:YES]
(NSURL *) $1 = 0x1fd9fc20 @"file://localhost/private/var/"
(lldb) po [$1 URLByResolvingSymlinksInPath]
$2 = 0x1fda0190 file://localhost/var/
(lldb) p (NSURL *)[NSURL fileURLWithPath:@"/var" isDirectory:YES]
(NSURL *) $7 = 0x1fd9fee0 @"file://localhost/var/"
(lldb) po [$7 URLByResolvingSymlinksInPath]
$8 = 0x1fda2f50 file://localhost/var/
как вы можете видеть, file://localhost/var
- это то, что мы действительно хотим здесь.
Из-за этого казалось очевидным, что /private/var
является символической ссылкой на /var
.
Однако, Кевин-Баллард указывает, что это неверно. Я подтвердил, что он прав, и /var
является символической ссылкой на /private/var
(sigh)
(lldb) p (NSDictionary *)[[NSFileManager defaultManager] attributesOfItemAtPath:@"/var" error:nil]
(NSDictionary *) $3 = 0x1fda11b0 13 key/value pairs
(lldb) po $3
$3 = 0x1fda11b0 {
...
NSFileType = NSFileTypeSymbolicLink;
}
(lldb) p (NSDictionary *)[[NSFileManager defaultManager] attributesOfItemAtPath:@"/private/var" error:nil]
(NSDictionary *) $5 = 0x1fda4820 14 key/value pairs
(lldb) po $5
$5 = 0x1fda4820 {
...
NSFileType = NSFileTypeDirectory;
}
Итак, URLByResolvingSymlinksInPath
делает что-то смешное здесь, но теперь мы знаем. Для этой конкретной проблемы URLByResolvingSymlinksInPath
по-прежнему звучит как хорошее решение, которое работает как для симулятора, так и для устройства и должно продолжать работать в будущем, если что-то изменится.
Ответ 2
Чтобы ответить на ваш вопрос:
Я считаю, что /private
был добавлен префикс, когда они выпустили OS X (я не думаю, что он был там в NeXTStep, но это были десятилетия). Кажется, существует дом etc
, var
и tmp
(и, что странно, tftpboot
; я не знал, что мой PBG4 может это сделать), возможно, пользователи не задаются вопросом, что это за глупая папка называется etc
и пытается удалить его.
На устройстве Apple решила сохранить пользовательские данные в /private/var/mobile
(имя пользователя "mobile" ). Я не уверен, почему они не выбрали /Users/mobile
или просто /mobile
, но это не имеет никакого значения, чем /var/mobile
будет для "нормальной" Unix.
В симуляторе ваша учетная запись пользователя не может писать на /var
(по уважительной причине). Данные пользователя хранятся где-то в ~/Library/Application Support/iPhone Simulator
. В какой-то момент они начали использовать разные каталоги для разных версий симулятора.
Ответ 3
В Swift 3, URL
имеет свойство standardizedFileUrl
, которое удалит любые символические ссылки и разрешит относительные части в пути, например ./
.
Как пишет документация, довольно бесполезно, но похоже, что она эквивалентна NSURL
standardized
.
Ответ 4
/var
является просто символической ссылкой на /private/var
. Таким образом, первый путь - это логический путь, к которому вы пытались получить доступ. Второй - это тот же путь с расширением символических ссылок.