Skip to content

Commit 720a9de

Browse files
committed
Implement the bulk getters for NSBundle
1 parent 82597fd commit 720a9de

File tree

2 files changed

+106
-14
lines changed

2 files changed

+106
-14
lines changed

Foundation/NSBundle.swift

Lines changed: 58 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@ public class NSBundle : NSObject {
2828
public init?(path: String) {
2929
super.init()
3030

31-
let resolvedPath = path._nsObject.stringByResolvingSymlinksInPath
31+
// TODO: We do not yet resolve symlinks, but we must for compatibility
32+
// let resolvedPath = path._nsObject.stringByResolvingSymlinksInPath
33+
let resolvedPath = path
3234
guard resolvedPath.length > 0 else {
3335
return nil
3436
}
@@ -136,12 +138,24 @@ public class NSBundle : NSObject {
136138
}
137139

138140
// -----------------------------------------------------------------------------------
139-
// MARK: - URL and Path Resource Lookup
141+
// MARK: - URL Resource Lookup - Class
140142

141-
public class func URLForResource(name: String?, withExtension ext: String?, subdirectory subpath: String?, inBundleWithURL bundleURL: NSURL) -> NSURL? { NSUnimplemented() }
143+
public class func URLForResource(name: String?, withExtension ext: String?, subdirectory subpath: String?, inBundleWithURL bundleURL: NSURL) -> NSURL? {
144+
// If both name and ext are nil/zero-length, return nil
145+
if (name == nil || name!.isEmpty) && (ext == nil || ext!.isEmpty) {
146+
return nil
147+
}
148+
149+
return CFBundleCopyResourceURLInDirectory(bundleURL._cfObject, name?._cfObject, ext?._cfObject, subpath?._cfObject)._nsObject
150+
}
142151

143-
public class func URLsForResourcesWithExtension(ext: String?, subdirectory subpath: String?, inBundleWithURL bundleURL: NSURL) -> [NSURL]? { NSUnimplemented() }
152+
public class func URLsForResourcesWithExtension(ext: String?, subdirectory subpath: String?, inBundleWithURL bundleURL: NSURL) -> [NSURL]? {
153+
return CFBundleCopyResourceURLsOfTypeInDirectory(bundleURL._cfObject, ext?._cfObject, subpath?._cfObject)?._unsafeTypedBridge()
154+
}
144155

156+
// -----------------------------------------------------------------------------------
157+
// MARK: - URL Resource Lookup - Instance
158+
145159
public func URLForResource(name: String?, withExtension ext: String?) -> NSURL? {
146160
return self.URLForResource(name, withExtension: ext, subdirectory: nil)
147161
}
@@ -151,20 +165,41 @@ public class NSBundle : NSObject {
151165
if (name == nil || name!.isEmpty) && (ext == nil || ext!.isEmpty) {
152166
return nil
153167
}
154-
let resultURL = CFBundleCopyResourceURL(_bundle, name?._cfObject, ext?._cfObject, subpath?._cfObject)
155-
return unsafeBitCast(resultURL, NSURL.self)
168+
return CFBundleCopyResourceURL(_bundle, name?._cfObject, ext?._cfObject, subpath?._cfObject)?._nsObject
156169
}
157170

158-
public func URLForResource(name: String?, withExtension ext: String?, subdirectory subpath: String?, localization localizationName: String?) -> NSURL? { NSUnimplemented() }
171+
public func URLForResource(name: String?, withExtension ext: String?, subdirectory subpath: String?, localization localizationName: String?) -> NSURL? {
172+
// If both name and ext are nil/zero-length, return nil
173+
if (name == nil || name!.isEmpty) && (ext == nil || ext!.isEmpty) {
174+
return nil
175+
}
176+
177+
return CFBundleCopyResourceURLForLocalization(_bundle, name?._cfObject, ext?._cfObject, subpath?._cfObject, localizationName?._cfObject)?._nsObject
178+
}
159179

160-
public func URLsForResourcesWithExtension(ext: String?, subdirectory subpath: String?) -> [NSURL]? { NSUnimplemented() }
180+
public func URLsForResourcesWithExtension(ext: String?, subdirectory subpath: String?) -> [NSURL]? {
181+
return CFBundleCopyResourceURLsOfType(_bundle, ext?._cfObject, subpath?._cfObject)?._unsafeTypedBridge()
182+
}
161183

162-
public func URLsForResourcesWithExtension(ext: String?, subdirectory subpath: String?, localization localizationName: String?) -> [NSURL]? { NSUnimplemented() }
184+
public func URLsForResourcesWithExtension(ext: String?, subdirectory subpath: String?, localization localizationName: String?) -> [NSURL]? {
185+
return CFBundleCopyResourceURLsOfTypeForLocalization(_bundle, ext?._cfObject, subpath?._cfObject, localizationName?._cfObject)?._unsafeTypedBridge()
186+
}
163187

164-
public class func pathForResource(name: String?, ofType ext: String?, inDirectory bundlePath: String) -> String? { NSUnimplemented() }
188+
// -----------------------------------------------------------------------------------
189+
// MARK: - Path Resource Lookup - Class
190+
191+
public class func pathForResource(name: String?, ofType ext: String?, inDirectory bundlePath: String) -> String? {
192+
return NSBundle.URLForResource(name, withExtension: ext, subdirectory: bundlePath, inBundleWithURL: NSURL(fileURLWithPath: bundlePath))?.path ?? nil
193+
}
165194

166-
public class func pathsForResourcesOfType(ext: String?, inDirectory bundlePath: String) -> [String] { NSUnimplemented() }
195+
public class func pathsForResourcesOfType(ext: String?, inDirectory bundlePath: String) -> [String] {
196+
// Force-unwrap path, beacuse if the URL can't be turned into a path then something is wrong anyway
197+
return URLsForResourcesWithExtension(ext, subdirectory: bundlePath, inBundleWithURL: NSURL(fileURLWithPath: bundlePath))?.map { $0.path! } ?? []
198+
}
167199

200+
// -----------------------------------------------------------------------------------
201+
// MARK: - Path Resource Lookup - Instance
202+
168203
public func pathForResource(name: String?, ofType ext: String?) -> String? {
169204
return self.URLForResource(name, withExtension: ext, subdirectory: nil)?.path
170205
}
@@ -173,10 +208,19 @@ public class NSBundle : NSObject {
173208
return self.URLForResource(name, withExtension: ext, subdirectory: nil)?.path
174209
}
175210

176-
public func pathForResource(name: String?, ofType ext: String?, inDirectory subpath: String?, forLocalization localizationName: String?) -> String? { NSUnimplemented() }
211+
public func pathForResource(name: String?, ofType ext: String?, inDirectory subpath: String?, forLocalization localizationName: String?) -> String? {
212+
return self.URLForResource(name, withExtension: ext, subdirectory: subpath, localization: localizationName)?.path
213+
}
214+
215+
public func pathsForResourcesOfType(ext: String?, inDirectory subpath: String?) -> [String] {
216+
// Force-unwrap path, beacuse if the URL can't be turned into a path then something is wrong anyway
217+
return self.URLsForResourcesWithExtension(ext, subdirectory: subpath)?.map { $0.path! } ?? []
218+
}
177219

178-
public func pathsForResourcesOfType(ext: String?, inDirectory subpath: String?) -> [String] { NSUnimplemented() }
179-
public func pathsForResourcesOfType(ext: String?, inDirectory subpath: String?, forLocalization localizationName: String?) -> [String] { NSUnimplemented() }
220+
public func pathsForResourcesOfType(ext: String?, inDirectory subpath: String?, forLocalization localizationName: String?) -> [String] {
221+
// Force-unwrap path, beacuse if the URL can't be turned into a path then something is wrong anyway
222+
return self.URLsForResourcesWithExtension(ext, subdirectory: subpath, localization: localizationName)?.map { $0.path! } ?? []
223+
}
180224

181225
// -----------------------------------------------------------------------------------
182226
// MARK: - Localized Strings

TestFoundation/TestNSBundle.swift

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ class TestNSBundle : XCTestCase {
2727
("test_resources", test_resources),
2828
("test_infoPlist", test_infoPlist),
2929
("test_localizations", test_localizations),
30+
("test_URLsForResourcesWithExtension", test_URLsForResourcesWithExtension),
3031
]
3132
}
3233

@@ -94,4 +95,51 @@ class TestNSBundle : XCTestCase {
9495
XCTAssertEqual(["en"], bundle.preferredLocalizations)
9596
XCTAssertEqual(["en"], NSBundle.preferredLocalizationsFromArray(["en", "pl", "es"]))
9697
}
98+
99+
private let _bundleName = "MyBundle.bundle"
100+
private let _bundleResourceNames = ["hello.world", "goodbye.world", "swift.org"]
101+
102+
private func _setupPlayground() -> String? {
103+
// Make sure the directory is uniquely named
104+
let tempDir = "/tmp/TestFoundation_Playground_" + NSUUID().UUIDString + "/"
105+
106+
do {
107+
try NSFileManager.defaultManager().createDirectoryAtPath(tempDir, withIntermediateDirectories: false, attributes: nil)
108+
109+
// Make a flat bundle in the playground
110+
let bundlePath = tempDir + _bundleName
111+
try NSFileManager.defaultManager().createDirectoryAtPath(bundlePath, withIntermediateDirectories: false, attributes: nil)
112+
113+
// Put some resources in the bundle
114+
for n in _bundleResourceNames {
115+
NSFileManager.defaultManager().createFileAtPath(bundlePath + "/" + n, contents: nil, attributes: nil)
116+
}
117+
} catch _ {
118+
return nil
119+
}
120+
121+
122+
return tempDir
123+
}
124+
125+
private func _cleanupPlayground(location: String) {
126+
do {
127+
try NSFileManager.defaultManager().removeItemAtPath(location)
128+
} catch _ {
129+
// Oh well
130+
}
131+
}
132+
133+
func test_URLsForResourcesWithExtension() {
134+
guard let playground = _setupPlayground() else { XCTFail("Unable to create playground"); return }
135+
136+
let bundle = NSBundle(path: playground + _bundleName)
137+
XCTAssertNotNil(bundle)
138+
139+
let worldResources = bundle?.URLsForResourcesWithExtension("world", subdirectory: nil)
140+
XCTAssertNotNil(worldResources)
141+
XCTAssertEqual(worldResources?.count, 2)
142+
143+
_cleanupPlayground(playground)
144+
}
97145
}

0 commit comments

Comments
 (0)