Objective-C代码生成给定文件和目录的相对path

给定一个文件path和一个目录path为NSString s,没有人有Objective-C的代码来生成一个文件的path,相对于目录?

例如,给定目录/tmp/foo和文件/tmp/bar/test.txt ,代码应该生成../bar/test.txt

我知道Python,至less,有一个方法来做到这一点: os.path.relpath

我决定只写和分享,而不是继续捍卫我为什么需要这个。 我基于Python的os.path.relpath的实现基于http://mail.python.org/pipermail/python-list/2009-August/1215220.html

 @implementation NSString (Paths) - (NSString*)stringWithPathRelativeTo:(NSString*)anchorPath { NSArray *pathComponents = [self pathComponents]; NSArray *anchorComponents = [anchorPath pathComponents]; NSInteger componentsInCommon = MIN([pathComponents count], [anchorComponents count]); for (NSInteger i = 0, n = componentsInCommon; i < n; i++) { if (![[pathComponents objectAtIndex:i] isEqualToString:[anchorComponents objectAtIndex:i]]) { componentsInCommon = i; break; } } NSUInteger numberOfParentComponents = [anchorComponents count] - componentsInCommon; NSUInteger numberOfPathComponents = [pathComponents count] - componentsInCommon; NSMutableArray *relativeComponents = [NSMutableArray arrayWithCapacity: numberOfParentComponents + numberOfPathComponents]; for (NSInteger i = 0; i < numberOfParentComponents; i++) { [relativeComponents addObject:@".."]; } [relativeComponents addObjectsFromArray: [pathComponents subarrayWithRange:NSMakeRange(componentsInCommon, numberOfPathComponents)]]; return [NSString pathWithComponents:relativeComponents]; } @end 

请注意,有些情况下将无法正确处理。 它正好处理我需要的所有情况。 这里是我用来validation正确性的简单unit testing:

 @implementation NSStringPathsTests - (void)testRelativePaths { STAssertEqualObjects([@"/a" stringWithPathRelativeTo:@"/"], @"a", @""); STAssertEqualObjects([@"a/b" stringWithPathRelativeTo:@"a"], @"b", @""); STAssertEqualObjects([@"a/b/c" stringWithPathRelativeTo:@"a"], @"b/c", @""); STAssertEqualObjects([@"a/b/c" stringWithPathRelativeTo:@"a/b"], @"c", @""); STAssertEqualObjects([@"a/b/c" stringWithPathRelativeTo:@"a/d"], @"../b/c", @""); STAssertEqualObjects([@"a/b/c" stringWithPathRelativeTo:@"a/d/e"], @"../../b/c", @""); STAssertEqualObjects([@"/a/b/c" stringWithPathRelativeTo:@"/d/e/f"], @"../../../a/b/c", @""); } @end 

有没有理由不能使用完整的path? imageNamed:完全支持。 根是您应用程序的主包。

 myImageView.image = [UIImage imageNamed:@"/Path/To/Some/File.png"]; 

这里是希尔顿代码的Swift版本

 extension String { var pathComponents: [String] { return (self as NSString).pathComponents } static func pathWithComponents(components: [String]) -> String { return NSString.pathWithComponents(components) } func stringWithPathRelativeTo(anchorPath: String) -> String { let pathComponents = self.pathComponents let anchorComponents = anchorPath.pathComponents var componentsInCommon = 0 for (c1, c2) in zip(pathComponents, anchorComponents) { if c1 != c2 { break } componentsInCommon += 1 } let numberOfParentComponents = anchorComponents.count - componentsInCommon let numberOfPathComponents = pathComponents.count - componentsInCommon var relativeComponents = [String]() relativeComponents.reserveCapacity(numberOfParentComponents + numberOfPathComponents) for _ in 0..<numberOfParentComponents { relativeComponents.append("..") } relativeComponents.appendContentsOf(pathComponents[componentsInCommon..<pathComponents.count]) return String.pathWithComponents(relativeComponents) } }