16

I am using

self.imageView.image = UIImage(named: "foo.png")

to select and load images in an UIIMageView. I have the images in my app under the images.xcassets. The problem is that this particular init caches the image for reuse as per the official Apple documentation:

If you have an image file that will only be displayed once and wish to ensure that it does not get added to the system’s cache, you should instead create your image using imageWithContentsOfFile:. This will keep your single-use image out of the system image cache, potentially improving the memory use characteristics of your app.

My view allows cycling through images before selecting one, and so the memory footprint goes on increasing as I cycle through and never goes down even when I navigate back from that view.

So I am trying to use UIIMage(contentsOfFile: "path to the file") which does not cache the image. Here I am having trouble programatically getting the path of the images which I have stored under images.xcassets.

I have tried using:

NSBundle.mainBundle().resourcePath
and
NSBundle.mainBundle().pathForResource("foo", ofType: "png")

without luck. For the first one I get the resourcePath, but on accessing that through the terminal I do not see any image assets under it, and the second one I get nil when I use it. Is there an easy way to to do this?

Also looked at several SO questions (like this, this and this) with no luck. Do I have to put my images somewhere else to be able to use the pathForResource()? What is the right way to go about this?

It is hard to imagine that no one has encountered this scenario before :) !

Community
  • 1
  • 1
rgamber
  • 5,749
  • 10
  • 55
  • 99
  • Why it is so necessary to store images in images.xcassets? Seems like in your case there are more disadvantages than advantages. I would rather move images to normal folder and use pathForResource("foo", ofType: "png") method. – Kateryna Gridina Mar 31 '15 at 20:54
  • So I can just create a separate folder in the file-system inside the app directory to use `pathForResource()`? Or do I have to create a group in XCode? – rgamber Mar 31 '15 at 20:56
  • You can create group, and add image there. Be sure, that image is copied to Copy Bundle Resources. Afterwards just write: var bundlePath = NSBundle.mainBundle().pathForResource("imageName", ofType: "jpg") var image = UIImage(contentsOfFile: bundlePath!) – Kateryna Gridina Mar 31 '15 at 21:46
  • Thanks. If you put your comment as an answer, then I can accept it! – rgamber Apr 01 '15 at 18:13
  • "Why it is so necessary to store images in images.xcassets?" Because the .xcassets benefits from app thinning whereas the bundle solution doesn't. – Daniel T. Feb 13 '19 at 18:23

3 Answers3

38

If you need to use pathForResource() for avoiding image caching, it is not possible to work with images.xcassets. In that case you need to create group in XCode, and add image there (be sure, that image is copied to Copy Bundle Resources). Afterwards just write:

Swift 5:

let bundlePath = Bundle.main.path(forResource: "imageName", ofType: "jpg")
let image = UIImage(contentsOfFile: bundlePath!)

Older Swift:

let bundlePath = NSBundle.mainBundle().pathForResource("imageName", ofType: "jpg") 
let image = UIImage(contentsOfFile: bundlePath!) 
Linus Unnebäck
  • 23,234
  • 15
  • 74
  • 89
Kateryna Gridina
  • 834
  • 9
  • 13
  • Before using this version, the app starts with less memory (35mb) and increases over time (up to 150mb until all images were loaded). Now it starts instantly with 80mb but stays at the level. Any ideas for this behaviour? – Lucas Sep 08 '18 at 18:48
1
import Foundation
import UIKit

enum UIImageType: String {
    case PNG = "png"
    case JPG = "jpg"
    case JPEG = "jpeg"
}

extension UIImage {

    convenience init?(contentsOfFile name: String, ofType: UIImageType) {
        guard let bundlePath = Bundle.main.path(forResource: name, ofType: ofType.rawValue) else {
            return nil
        }
        self.init(contentsOfFile: bundlePath)!
    }

}

Use:

let imageView.image = UIImage(contentsOfFile: "Background", ofType: .JPG)
Mohammad Razipour
  • 3,643
  • 3
  • 29
  • 49
  • `self.init(contentsOfFile: bundlePath)!` unwrapping has no effect since it's a failable initializer – inokey Feb 11 '19 at 08:40
0

When you implement array of images from the images group resource,you can load each images(lets say b1,b2,b3,b4,b5) as

var imageIndex = 0
lazy var imageList = ["b1","b2","b3","b4","b5"]
let imagePath = Bundle.main.path(forResource: imageList[imageIndex], ofType: "jpg")
imageview.image = UIImage(contentsOfFile: imagePath!)
Haileapp
  • 755
  • 7
  • 20