2013-02-21 9 views
25

Ich habe einen Fehler, wenn meine App auf dem iPhone läuft, aber nicht, wenn sie auf dem Simulator läuft. Ich habe die Länge des Ausgangsverzeichnispfads verwendet, um den relativen Pfad einer Datei in/Documents zu extrahieren. Leider funktioniert das auf dem iPhone nicht immer korrekt, da das Präfix "/ private" zum Home-Pfad hinzugefügt wird. Mit oder ohne Präfix wird dieselbe Datei jedoch mit ok referenziert. Der folgende Code demonstriert diese Inkonsistenz. Was ist der Zweck von "/ privat" und wann wird es von iOS bereitgestellt?Was bedeutet das Präfix/private auf einem iOS-Dateipfad?

- (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); 
} 

Folgendes wird in das Protokoll geschrieben, wenn es auf dem iPhone ausgeführt wird. I beabstandet manuell die Ausgabe die Differenz zwischen den Linien zu zeigen, 1 und 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) 

Die folgende in das Protokoll geschrieben wird, wenn auf dem Simulator (keine "/ private") ausgeführt wird:

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 
+4

Das Schlimmste, was Sie tun können, ist, irgendwelche Annahmen darüber zu treffen, was der Pfad zum Dokumentenverzeichnis Ihrer App ist oder sein wird. Eine bestimmte Länge für diesen Pfad zu erwarten, ist noch schlimmer. Ermitteln Sie einfach den Pfad Dokumente und entfernen Sie diesen aus dem vollständigen Pfad, um den relativen Pfad zu erhalten. – rmaddy

+0

@maddy, ich nahm nicht eine bestimmte Länge an, nur dass der Pfad zu/Documents sich nicht ändern würde, was durch IOS-Hinzufügen/privat verletzt wird, wie Kevin Ballard unten darauf hingewiesen hat, ist nur ein Symlink. Ich komme aus Windows, wo ich das noch nie gesehen habe. Jetzt finde ich den Teilstring von/NSHomeDirectory()/Documents in jedem Pfad, den IOS mir gibt, und rufe die Pfadzeichenfolge danach den relativen Pfad auf. Siehst du irgendein Problem damit oder weißt du einen besseren Weg, den relativen Pfad zu bekommen? – KenM

+1

Ihre Frage lautet: _Ich verwendete die Länge des Home-Verzeichnisses Pfad_. Sie sollten immer mit Pfaden arbeiten, die relativ zum Verzeichnis Documents sind. Sie dürfen niemals den vollständigen Pfad beibehalten. Wenn Sie nur relative Verzeichnisse haben, gibt es nichts zu verarbeiten. – rmaddy

Antwort

1

/var ist nur ein symbolischer Link zu /private/var. Der erste Pfad ist also der logische Pfad, auf den Sie zuzugreifen versucht haben. Der zweite ist der gleiche Pfad mit erweiterten Symlinks.

+0

Danke für den Hinweis, aber es scheint das Gegenteil zu sein. Siehe meine Antwort. – Skotch

+0

@Skotch: Es ist eigentlich nicht. Sehen Sie meinen Kommentar zu Ihrer Antwort. –

+0

/var war lange Zeit ein Symlink zu/private/var auf Mac OS X. Es war so, bevor es iOS gab. –

4

tatsächlich Um Ihre Frage zu beantworten:

Ich glaube /private ein Präfix wurde hinzugefügt, wenn sie OS X veröffentlicht (ich glaube nicht, dass in Nextstep war, aber es ist Jahrzehnte gewesen). Es scheint zu existieren etc zu beherbergen, var und tmp (und, seltsam, tftpboot, ich wusste nicht, mein PBG4 tun könnte), vielleicht, so dass Benutzer fragen sich nicht, was diese dummen Ordner namens etc sind und versuchen, es zu löschen .

Auf dem Gerät hat Apple beschlossen, Benutzerdaten in /private/var/mobile (der Benutzername ist "mobile") zu speichern. Ich bin mir nicht sicher, warum sie nicht /Users/mobile oder nur /mobile gewählt haben, aber es hat keine Bedeutung mehr als /var/mobile würde auf einem "normalen" Unix.

Im Simulator kann Ihr Benutzerkonto nicht in /var schreiben (aus gutem Grund). Benutzerdaten werden irgendwo in ~/Library/Application Support/iPhone Simulator gespeichert. An einem Punkt begannen sie, verschiedene Verzeichnisse für verschiedene Simulatorversionen zu verwenden.

23

Ich habe dies aus dem Debugger versucht und festgestellt, dass URLByResolvingSymlinksInPath "/private/" ergänzt.

(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/ 

wie Sie sehen können, ist file://localhost/var, was wir wollen hier wirklich.

Aus diesem Grund schien es offensichtlich, dass /private/var ist ein symbolischer Link auf /var. @ Kevin-Ballard weist jedoch darauf hin, dass das nicht stimmt. Ich bestätigte, dass er richtig ist, und /var ist die Symlink /private/var (seufz)

(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; 
} 

So URLByResolvingSymlinksInPath ist etwas komisch hier zu tun, aber jetzt wissen wir. Für dieses spezielle Problem klingt URLByResolvingSymlinksInPath nach wie vor eine gute Lösung, die sowohl für den Simulator als auch für das Gerät funktioniert und auch in Zukunft weiter funktionieren sollte, wenn sich etwas ändert.

+2

'/ var' ist eigentlich ein Symlink zu'/private/var' auf iOS. Es ist möglich, dass '-URLByResolvingSymlinksInPath' irgendwie speziell ist, um einen kanonischeren Pfad bereitzustellen. –

+0

Solide Diskussion; Ich stieß auf ein Problem beim Laden von Dateien in einem PDF-Viewer und es drehte sich alles um den Simlink. Sobald ich auf diese Erklärung stieß, sprang die Lösung heraus und das Problem wurde gelöst. –

+1

Apple dokumentiert, dass 'URLByResolvingSymlinksInPath' das führende'/private' entfernt. https://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSURL_Class/Reference/Reference.html#//apple_ref/doc/uid/20000301-SW32 –

2

In Swift 3 hat URL die standardizedFileUrl Eigenschaft, die alle Symlinks entfernen wird und die entsprechenden Teile in dem wie ./ Weg zu lösen.

Zum Schreiben der documentation ist ziemlich nutzlos, aber es sieht aus wie es ist NSURL's standardized Eigentum.