Categorizing and Downloading Assets to Get Smaller Binaries - Swift 2.0, Xcode 7 and Interface Builder - iOS 9 Swift Programming Cookbook (2015)

iOS 9 Swift Programming Cookbook (2015)

Chapter 1. Swift 2.0, Xcode 7 and Interface Builder

1.5 Categorizing and Downloading Assets to Get Smaller Binaries

Problem

You have many assets in your app for various circumstances, and want to save storage space and network usage on each user’s device by shipping the app without the optional assets. Instead, you would want to dynamically download them and use them whenever needed.

Solution

Use Xcode to tag your assets and then use the NSBundleResourceRequest class to download them.

Discussion

For this recipe, I will create 3 packs of assets, each with three images in them. One pack may run for x3 screen scales, another for iPhone 6, and the last for iPhone 6+, for instance. I am taking very tiny clips of screenshots of my desktop to create these images--nothing special. The first pack will be called “level1”, the second “level2”, and the third “level3”.

NOTE

Use the GitHub repo of this book for a quick download of the said resources. Also, for the sake of simplicity, I am assuming that we are going to run this only on x3 scale screens such as iPhone 6+.

Place all nine images (three packs of three images) inside your Assets.xcassets file and name them as shown in Figure 1-1. Then select all the images in your first asset pack and open the attribute inspector. In the “On Demand Resource Tags” section of the inspector, enter “level1” and do the same thing for other levels--but of course bump the number up for each pack.

Figure 1-1. Name your assets as shown

Now, in your UI, place three buttons and three image views, hook the buttons’ actions to the code, and hook the image view references to the code.

@IBOutlet var img1: UIImageView!

@IBOutlet var img2: UIImageView!

@IBOutlet var img3: UIImageView!

var imageViews: [UIImageView]{

return [self.img1, self.img2, self.img3]

}

In order to find out whether the resource pack that you need has already been downloaded, call the conditionallyBeginAccessingResourcesWithCompletionHandler function on your resource request. Don’t blame me! I didn’t name this function. This will return a Boolean oftrue or false to tell you whether you have or don’t have access to the resource. If you don’t have access, you can simply download the resources with a call to the beginAccessingResourcesWithCompletionHandler function. This will return an error if one happens, or nil if everything goes well.

NOTE

We keep a reference to the request that we send for our asset pack so that the next time our buttons are tapped, we don’t have to check their availability again, but release the previously downloaded resources using the endAccessingResources function.

var currentResourcePack: NSBundleResourceRequest?

func displayImagesForResourceTag(tag: String){

NSOperationQueue.mainQueue().addOperationWithBlock{

for n in 0..<self.imageViews.count{

self.imageViews[n].image = UIImage(named: tag + "-\(n+1)")

}

}

}

func useLevel(lvl: UInt32){

let imageViews = [img1, img2, img3]

for img in imageViews{

img.image = nil

}

let tag = "level\(lvl)"

if let req = currentResourcePack{

req.endAccessingResources()

}

currentResourcePack = NSBundleResourceRequest(tags: [tag])

guard let req = currentResourcePack else {

return

}

req.conditionallyBeginAccessingResourcesWithCompletionHandler{available in

if available{

self.displayImagesForResourceTag(tag)

} else {

req.beginAccessingResourcesWithCompletionHandler{error in

guard error == nil else{

//TODO: you can handle the error here

return

}

self.displayImagesForResourceTag(tag)

}

}

}

}

@IBAction func useLevel3(sender: AnyObject) {

useLevel(3)

}

@IBAction func useLevel2(sender: AnyObject) {

useLevel(2)

}

@IBAction func useLevel1(sender: AnyObject) {

useLevel(1)

}

Run the code now in your simulator. When Xcode opens, go to the Debug Navigator (Command+6 key) and then click on the Disk section. You will see something like that shown in Figure .

Note how none of the asset packs are in use. Now in your UI, press the first button to get the first asset pack and watch how the first asset pack’s status will change to “In Use”. Once you switch from that pack to another, the previously chosen pack will be set to “Downloaded” and ready to be purged.

See Also