Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
// Based on https://twitter.com/ravibastola/status/1249555595285291008?s=20
extension Bundle {
// This is synchronous, which is bad if called on the main queue.
func decodeJSON<T: Decodable>(_ type: T.Type = T.self, from filename: String) throws -> T {
guard let path = self.url(forResource: filename, withExtension: nil) else {
throw NSError(domain: NSCocoaErrorDomain,
code: CocoaError.fileNoSuchFile.rawValue,
userInfo: [NSFilePathErrorKey: filename])
}
let data = try Data(contentsOf: path)
return try JSONDecoder().decode(T.self, from: data)
}
// An async version
func decodeJSON<T: Decodable>(_ type: T.Type = T.self,
from filename: String,
on queue: DispatchQueue = .global(),
completion: @escaping (Result<T, Error>) -> ()) {
queue.async {
completion(Result { try self.decodeJSON(type, from: filename) })
}
}
}
Bundle.main.decodeJSON(String.self, from: "x") { strResult in print(strResult) }
// If you *always* want this to be on Bundle.main, then I'd just push up to a free function. No
// need for an instance that has no state.
func decodeJSONFile<T: Decodable>(_ type: T.Type = T.self,
from filename: String,
on queue: DispatchQueue = .global(),
completion: @escaping (Result<T, Error>) -> ()) {
queue.async {
completion(Result { try Bundle.main.decodeJSON(type, from: filename) })
}
}
// Or if you want a namespace, we typically use an Enum for that:
enum Loader {
function json( ... )
}
let result = Loader.json(...) // etc.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment