Can I get a NSURL from an XCAssets bundle?

I’m in a situation where I am listing attachments from a message. Each attachment has a NSURL associated with it that represents a path to the attachment data. In the case of non-image attachments I want to load pre-generated icon thumbnails in the place of a preview (i.e. excel documents, PDF, word, etc).

I currently have these images in my project, within an XCAssets bundle. I can get at them using [UIImage imageNamed:@"someName"]. I cannot seem to get at them via NSBundle’s various resource lookup methods. Does the XCAssets bundle somehow change the filenames of the icon images I’m looking for?

  • Re-authenticating User Credentials Swift
  • iOS 10 MapKit previous layer zoom issue
  • Apple Mach-O Linker & Ditto Error - Xcode 8
  • how to start to play music in locked screen in iPhone
  • IOS JSON get all values from a “JSON Dict”
  • How to disable iOS 11 dragging within the whole app?
  • Here’s the code I’m currently working with. Path is nil every time. Do I need to not use XCAssets in this case?

    + (NSURL *)mediaURLWithMessage:(SRMediaMessage*)message
    {
      NSURL *url = message.mediaURL;
    
      // if this is an image URL or non-existant, there is no work left to do, return it.
      if (!url || (message.secureFile.secureFileMimeType & SRSecureFileMimeTypeImage))
        return url;
    
      NSString *filename = @"unknown";
    
      switch (message.secureFile.secureFileMimeType)
      {
        case SRSecureFileMimeTypeDOC:
          filename = @"doc";
          break;
    
        case SRSecureFileMimeTypePPT:
          filename = @"ppt";
          break;
    
        case SRSecureFileMimeTypePDF:
          filename = @"pdf";
          break;
    
        case SRSecureFileMimeTypeXLS:
          filename = @"exl";
          break;
    
        case SRSecureFileMimeTypeCSV:
          filename = @"csv";
          break;
    
        case SRSecureFileMimeTypeTXT:
          filename = @"txt";
          break;
    
        case SRSecureFileMimeTypeRTX:
          filename = @"rtf";
          break;
    
        default:
        case SRSecureFileMimeTypeMP4:
          // unknown icon for now.
          break;
    
          // unused but available:
    //      @"ilife"
    
      }
    
      NSString *path = [[NSBundle mainBundle] pathForResource:filename ofType:nil];
      if (path)
        url = [NSURL fileURLWithPath:path];
    
      return url;
    }
    

    4 Solutions Collect From Internet About “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 3 and Swift 2.3 versions of the answer by @tadija:

    Swift 3:

    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")
            let path = url.path
    
            guard fileManager.fileExists(atPath: path) else {
                guard
                    let image = UIImage(named: name),
                    let data = UIImagePNGRepresentation(image)
                    else { return nil }
    
                fileManager.createFile(atPath: path, contents: data, attributes: nil)
                return url
            }
    
            return url
        }
    
    }
    

    Swift 2.3:

    import UIKit
    
    class AssetExtractor {
    
        static func createLocalUrl(forImageNamed name: String) -> NSURL? {
    
            let fileManager = NSFileManager.defaultManager()
            let cacheDirectory = fileManager.URLsForDirectory(.CachesDirectory, inDomains: .UserDomainMask)[0]
            guard
                let url = cacheDirectory.URLByAppendingPathComponent("\(name).png"),
                let path = url.path
                else { return nil }
    
            guard fileManager.fileExistsAtPath(path) else {
                guard
                    let image = UIImage(named: name),
                    let data = UIImagePNGRepresentation(image)
                    else { return nil }
    
                fileManager.createFileAtPath(path, contents: data, attributes: nil)
                return url
            }
    
            return url
        }
    
    }
    

    Swift 3.x

    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")
        let path = url.path
    
        guard fileManager.fileExists(atPath: path) else {
            guard
                let image = UIImage(named: name),
                let data = UIImagePNGRepresentation(image)
                else { return nil }
    
            fileManager.createFile(atPath: path, contents: data, attributes: nil)
            return url
        }
    
        return url
    }