Can I get a NSURL from an XCAssets bundle?

If you're targeting iOS 7+, Xcode 5 now puts the assets into a new file format. 1 file for all of the assets. This means you can not get access to the file directly.

If you need to access the file directly, you can include it as an normal image outside of an asset catalog.


I wanted to access some vector assets for creating UNNotificationAttachment with local resources so I came up with this helper class. It basically just gets image from assets, saves its data to disk and return file URL. I hope that helps someone.

import UIKit

class AssetExtractor {

    static func createLocalUrl(forImageNamed name: String) -> URL? {

        let fileManager = FileManager.default
        let cacheDirectory = fileManager.urls(for: .cachesDirectory, in: .userDomainMask)[0]
        let url = cacheDirectory.appendingPathComponent("\(name).png")

        guard fileManager.fileExists(atPath: url.path) else {
            guard
                let image = UIImage(named: name),
                let data = UIImagePNGRepresentation(image)
            else { return nil }

            fileManager.createFile(atPath: url.path, contents: data, attributes: nil)
            return url
        }

        return url
    }

}

Swift 5

And it made a bit more sense to me as a URL extension.

extension URL {
    static func localURLForXCAsset(name: String) -> URL? {
        let fileManager = FileManager.default
        guard let cacheDirectory = fileManager.urls(for: .cachesDirectory, in: .userDomainMask).first else {return nil}
        let url = cacheDirectory.appendingPathComponent("\(name).png")
        let path = url.path
        if !fileManager.fileExists(atPath: path) {
            guard let image = UIImage(named: name), let data = image.pngData() else {return nil}
            fileManager.createFile(atPath: path, contents: data, attributes: nil)
        }
        return url
    }
}

Usage:

if let url = URL.localURLForXCAsset(name: "MyIcon") {
  // code
}