ipadswiftmemory-managementuiimageios8.2

How can I use UIImage(contentsOfFile:String) with image data downloaded from the internet?


I have an app which is loading a lot of image data from a web server. The data is being saved onto the ipad via:

func saveParsedObject(objectToSave:AnyObject,dataCode:Int)
    {
        var path:String! = self.convertDataCodeToPath(dataCode)
        println( "saveParsedObject - object::\(objectToSave)")
        if NSKeyedArchiver.archiveRootObject(objectToSave, toFile: path)
        {
            println("Success writing parsed object to file!")
        }
        else
        {
            println("Unable to write parsed object to file!")
        }
    }

The data is later opened with :

func loadParsedObject(dataCode:Int) -> AnyObject?
    {
        var path:String! = self.convertDataCodeToPath(dataCode)
        println( " ****** path = \(path) ****** ")
        var dataFromDisk:AnyObject?
        dataFromDisk = NSKeyedUnarchiver.unarchiveObjectWithFile(path)
        println( " ****** dataFromDisk = \(dataFromDisk) ****** ")
        return dataFromDisk
    }

The image data is saved with this code:

if let imgURLString = imageURLString
        {
            println(" ////// Image is not nil /////// ")
            let imageURL = NSURL(string: imageURLString)
            let imageData = NSData(contentsOfURL: imageURL!)

            //println(imageData)
            if let imgData = imageData
            {
                self.productImage = UIImage(data: imageData!)
            }
            else
            {
                println("Image data = nil")
                //println(productName)
            }

        }

Since the data is not saved with UIImage(contentsOfFile:String) it is being cached when I later do this:

if let isProductImgNil = productModel.productImage?
        {
            println(" -- product image is not nil -- ")
// productView is my custom view for my productData which is in my productModel object
                productView.backgroundImage.image = productModel.productImage?
//productView.backgroundImage is a UIImageView
//productModel.productImage is a UIImage
        }

I found these links and tried to use them in order for the Images to not be cached. However, the problem is far greater. I need to download a Image, save it to the HDD and the load it with contentsOfFile which accepcts a string not NSData object and I have no clue how to do this correctly or even if this approach does make sense.

Here are the links:

(1) Swift + Save and Load Image From DocumentDirectory

(2) SO: basic UIImage memory managment

(3) SO: My error but with local images located in .xcassets

(4) SO: Answers says what I should do and I do, however UImage can not be loaded with NSData with caching disabled

Solution 1

Result: This is what I have done in the start (explained in (4)) Data is being cached but not loaded twice, app crashes after some time (explained in (3)

Code above

Solution 2

Result: Data is being cached and loaded again (even worse). Crashes much faster...

Code

Saving data when parsing it (used link (1)):

if let imgURLString = imageURLString
        {
            println(" ////// Image is not nil /////// ")
            let imageURL = NSURL(string: imageURLString)
            let imageData = NSData(contentsOfURL: imageURL!)

            var selectedImage = UIImage(data:imageData!)


            let fileManager = NSFileManager.defaultManager()

            var paths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as String

            var filePathToWrite = "\(paths)/\(imageURLString.lastPathComponent)"

            var imageData1: NSData = UIImagePNGRepresentation(selectedImage)

            fileManager.createFileAtPath(filePathToWrite, contents: imageData1, attributes: nil)

            var getImagePath = paths.stringByAppendingPathComponent(imageURLString.lastPathComponent)

            finalImagePath = getImagePath

            if (fileManager.fileExistsAtPath(getImagePath))
            {
                println(" --------------- ")
                println(" Model - FILE AVAILABLE");
                println(getImagePath)
                println(" --------------- ")
                //Pick Image and Use accordingly
                //var imageis: UIImage = UIImage(contentsOfFile: getImagePath)!

                //let data: NSData = UIImagePNGRepresentation(imageis)

            }
            else
            {
                println(" Model - FILE NOT AVAILABLE");

            }

        }

And loading data:

 let fileManager = NSFileManager.defaultManager()

    if (fileManager.fileExistsAtPath(productModel.finalImagePath!))
    {
        println("FILE AVAILABLE");
        productView.backgroundImage.image = UIImage(contentsOfFile:productModel.finalImagePath)!
    }
    else
    {
        println(" - - - - - ")
        println(productModel.finalImagePath!)
        println("FILE NOT AVAILABLE");

    }

Take note of:

productView.backgroundImage.image = UIImage(contentsOfFile:productModel.finalImagePath)!

which doesn't help with caching... but loads the image into the view.

Any suggestions are welcome. I am going to try some other stuff in a smaller project because maybe it is a project problem.

I will also try to implement the object pool DP, but somehow I think it is not going to help much since one category has 202 products and the memory jumps to about 250-300 MB. If I open anything else I recieve memory warnings. Few more memory spikes and the app crashes.

I might also try dynamic loading since the products are being loaded into a UIScrollView but that is going to be a lot of work since I don't have much time. And yes I know I should have gone with CoreData, but I didn't have the time to learn it. App has to be done in about 40 days (not much time left) and I am new to swift :). Thanks for your help :).


Solution

  • If you don't have much time, you should just use SDWebImage. It does all this for you, the right way.