ImageManager

The imageManager simplifies the process of accessing thumbnails for nodes as well as user's avatars. While the imageManager is built on top of the diskManager, its API is simplified and specialized for UIImage and OSImage objects.


User Avatars

ZeroDarkCloud user accounts have an avatar image associated with them. This avatar originates from the social media or Storm4 account they use to login to ZeroDarkCloud. There is no guaranteed that a copy of the avatar will always be on the device, so we created imageManager APIs to access the avatar. The fetchUserAvatar is what most applications will need to use. This API will first check if there is a copy in the in memory cache and return it if possible, else it attempt to asynchronously load it from disk, as a last resort it will attempt to downloaded from the cloud or the social media site whichever is appropriate and cache the copy for later use.

Since these operations can occur asynchronously, we return the results with blocks or swift closures. In the case of fetchUserAvatar there is a preFetchBlock and a postFetchBlock. The preFetchBlock is always invoked, synchronously before the function returns. It only returns an image if there's a match in the cache that can immediately be used. The preFetchBlock also provides a willFetch Boolean parameter that will be FALSE if the the postFetchBlock will NOT be invoked. In the case that a an image can be provided, the postFetchBlock will be invoked after the image has been read from disk or downloaded from the cloud.

The imageManager also provides a defaultUserAvatar function to simply the cases where no avatar was available.

The following code snippet demonstrates fetching an avatar for ZDCLocalUser or ZDCUser object.

@IBOutlet public var userAvatar : UIImageView!
// assume user is ZDCLocalUser or ZDCUser object.

// fallback to default if no image found.
    let defaultImage = {
            return ZDCManager.imageManager().defaultUserAvatar()
    }

// handle image found in cache
    let preFetch = {(image: UIImage?, willFetch: Bool) in
             userAvatar.image = image ?? defaultImage()
    }

// image fetched from disk or cloud
    let postFetch = {(image: UIImage?, error: Error?) in
         userAvatar.image = image ?? defaultImage()
    }

    ZDCManager.imageManager().fetchUserAvatar(user,
                                                preFetch: preFetch, 
                                                postFetch: postFetch)
Preprocessing a user image

There might be times when you want to do some preprocessing of the user image. For example you might want to scale the image to a certain size, round the corners, give it tint, etc. . In this case there is variant of the fetchUserAvatar api that will take a processingBlock parameter. Note that the processingBlock will be invoked on a background thread.

The API also takes a processingID parameter which is a unique identifier that distinguishes the results of this imageProcessingBlock from other imageProcessingBlocks that you may be using in other parts of your application. For example, if your block resizes the image to 64x64, then you might pass the string "64*64". If you pass a nil processingID, then the image won't be cached in memory.

@IBOutlet public var userAvatar : UIImageView!
// assume user is ZDCLocalUser or ZDCUser object.

// fallback to default if no image found.
    let defaultImage = {
            return ZDCManager.imageManager().defaultUserAvatar()
    }

// process image for cache 
    let processing = {(image: UIImage) in
        return image.scaled(to: size, scalingMode: .aspectFit)
    }

// handle image found in cache
    let preFetch = {[weak self](image: UIImage?, willFetch: Bool) -> Void in
        userAvatar.image = image ?? defaultImage()
    }

// image fetched from disk or cloud
        let postFetch = {[weak self](image: UIImage?, error: Error?) -> Void in
            userAvatar.image = image ?? defaultImage()
    }

    ZDCManager.imageManager().fetchUserAvatar(user,
                                              withProcessingID: "64*64",
                                              processingBlock: processing,
                                              preFetch: preFetch,
                                              postFetch: postFetch)
Tidying up after yourself

When you are done with this particular kind of avatar you might consider invoking the flushUserAvatarsCacheWithProcessingID to remove it from the cache.

        ZDCManager.imageManager().flushUserAvatarsCache(withProcessingID: "64*64")

Or assuming you are done with a particular user, you can remove that avatar's associated with that userID from the cache by calling flushUserAvatarsCache

        ZDCManager.imageManager().flushUserAvatarsCache(userID)

Node Thumbnails

A ZDCNode object can have thumbnail images associated with them. Similarly the imageManager has the fetchNodeThumbnail API and a variant with for a processingBlock for accessing these images. These APIs function the same way as the avatar APIs.

    @IBOutlet public var nodeImage : UIImageView!
// assume objectID is the nodeID associated with your object 

    var imageNode: ZDCNode? = nil
    // get a copy of the ZDCNode assciated with the objectID's thumbnail
    databaseConnection.read { (transaction) in
        imageNode = zdc.nodeManager.findNode(withName: "thumbnail", 
                                            parentID: objectID, 
                                            transaction: transaction)
    }

    // fetch and display the image
    if let imageNode = imageNode {

    // handle image found in cache
        let preFetch = {(image: UIImage?, willInvoke: Bool) in
            nodeImage.image = image ?? self.defaultImage
        }

    // image fetched from disk or cloud
        let postFetch = {(image: UIImage?, error: Error?) in
            if (image != nil) {
                nodeImage.image = image
            } else {
                // Network request failed.
                // You may want to display an error image ?
            }
        }

        ZDCManager.imageManager().fetchNodeThumbnail(imageNode, 
                                            preFetch: preFetch, 
                                            postFetch: postFetch)
    }

In addition there is are the flushNodeThumbnailCache and flushNodeThumbnailCacheWithProcessingID API's for explicitly flushing these thumbnails from he cache.