Simple UIImage Caching in Swift

This is a snippet of code that will cache images downloaded from an online source, and provide them when needed. I still have some work to do on it, but right now it works pretty fine.

//
//  ImageCache.swift
//
//  Created by Michael Adaixo on 16/07/15.
//

import UIKit

// TODO:
// - Implement LRU Algorithm ( Least-Recently-Used ) to clear unused images from memory
// - Try to make some sort of PriorityQueue out of this..
// - Be awesome. ( Check )

class ImageCache {
    static let sharedInstance = ImageCache()
    
    private var _cache: [String : UIImage]!
    
    init()  {
        _cache = [String : UIImage]()
    }
    
    func find( imageUrl: String ) -> UIImage? {
        if isCached( imageUrl ) {
            let key = stringToBase64( imageUrl )
            return _cache[key!]
        }
        return nil
    }
    
    func cacheImage( imageUrl: String ) {
        if !isCached(imageUrl) {
            UIImage().loadAsyncFromUrl(imageUrl, complete: { (resultingImage) -> Void in
                if let image = resultingImage {
                    self.addNewImage(imageUrl, image: image)
                }
            })
        }
    }
    
    func findOrLoadAsync( imageUrl: String, completionHandler: ( image: UIImage! ) -> Void ) {
        if let image = find( imageUrl ) {
            completionHandler( image: image )
        }
        else
        {
            UIImage().loadAsyncFromUrl(imageUrl, complete: { (resultingImage) -> Void in
                if let image = resultingImage {
                    self.addNewImage(imageUrl, image: image)
                    completionHandler( image: image )
                }
            })
        }
    }
    
    private func addNewImage( imageUrl: String, image: UIImage ) {
        if !isCached( imageUrl ) {
            let key = stringToBase64( imageUrl )
            _cache[key!] = image
        }
    }
    
    private func isCached( imageUrl: String ) -> Bool {
        if let key = stringToBase64( imageUrl ) {
            if _cache[key] != nil {
                return true
            }
        }
        return false
    }
    
    private func stringToBase64( string: String ) -> String? {
        let imageData = string.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)
        return imageData?.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.allZeros)
    }
}

I’m using a dictionary to keep track of the images, with their Base64 encoded urls as keys.

Example usage goes like:

ImageCache.sharedInstance.findOrLoadAsync(imageUrl, completionHandler: { (image) -> Void in
// do something with image (UIImage)
})

PS: Also, that UIImage().loadAsync is an UIImage Extension method I have lying around :)

// Will asynchronously download an image from the path(url)
// that you provide, and return you the UIImage on the main queue
func loadAsyncFromUrl( path: String, complete: (resultingImage: UIImage?) -> Void ) {
    // example fetch photo
   
    UIApplication.sharedApplication().networkActivityIndicatorVisible = true

    let url = NSURL(string: path)
    var request: NSURLRequest = NSURLRequest(URL: url!)

    NSURLConnection.sendAsynchronousRequest(request,
        queue: NSOperationQueue.mainQueue(),
        completionHandler: { (response: NSURLResponse!, data: NSData!, error: NSError!) -> Void in
            UIApplication.sharedApplication().networkActivityIndicatorVisible = false
            if error != nil {
                println("[UIImage.loadAsyncFromURL] Error: \(error)")
            }
            else
            {
                var image = UIImage(data: data)
                complete(resultingImage: image)
            }
    })
}

Change font weight by code in Swift

let currentFont = label.font
let fontName = currentFont.fontName.componentsSeparatedByString("-").first
let newFont = UIFont(name: "\(fontName!)-Light", size: currentFont.pointSize)
label.font = newFont

This snippet changes the current font of a label to a Light version of it ( in case it exists ). Font names are ( in this case, it was ‘.HelveticaNeue-Regular’ ) appended with their weight. So I get the font name, split it by ‘-‘, and take the first part of the split, ending with ‘.HelveticaNeue’. Now I just create a new font with the light appended to it, with the same size.

Lastly, I switch the font, and there you go.