On-Demand Resources in iOS Tutorial
On-demand resources are a technique to reduce the initial download size of applications which rely on large assets for use. This is especially useful to games developers with large assets only required during certain stages of the game. By James Goodwill.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
On-Demand Resources in iOS Tutorial
20 mins
- Getting Started
- Examining the App
- Game States
- Starting the Game
- Bundles
- Tag Types
- Assigning and Organizing Tags
- Introducing NSBundleResourceRequest
- Using NSBundleResourceRequest
- Downloading Resources
- Looking at the Device Disk
- Best Practices
- Error Handling
- Loading Priorities
- Purging Resources
- Where to Go From Here?
Best Practices
There’s several things you can do to improve a user’s experience. You can improve error reporting, set download priorities and purge resources no longer in use.
Error Handling
In the previous example, whenever you encountered an error the app would simply state “There was a problem.” There’s not a whole lot the user can do with this.
You can make this a much better experience. Open GameScene.swift, and inside touchesBegan(_:with:)
, replace onFailure
within the LevelOver
with the following:
onFailure: { (error) in
let controller = UIAlertController(
title: "Error",
message: "There was a problem.",
preferredStyle: .alert)
switch error.code {
case NSBundleOnDemandResourceOutOfSpaceError:
controller.message = "You don't have enough space available to download this resource."
case NSBundleOnDemandResourceExceededMaximumSizeError:
controller.message = "The bundle resource was too big."
case NSBundleOnDemandResourceInvalidTagError:
controller.message = "The requested tag does not exist."
default:
controller.message = error.description
}
controller.addAction(UIAlertAction(title: "Dismiss", style: .default, handler: nil))
guard let rootViewController = self.view?.window?.rootViewController else { return }
rootViewController.present(controller, animated: true)
})
Take a moment to look over this change. It is a fair amount of code, but the main change is the addition of the switch
statement. You’ll see that it’s testing the error code returned by the request object. Depending on which case the switch
hits, the app will change the error message. This is much nicer. Take a look at each one of these errors.
-
NSBundleOnDemandResourceOutOfSpaceError
is encountered when the user does not have enough space on their device to download the requested resources. This is useful since it gives your user a chance to clear up some space and try again. -
NSBundleOnDemandResourceExceededMaximumSizeError
is returned when this resource would exceed the maximum memory for in-use on-demand resources for this app. This would be a good time to purge some resources. -
NSBundleOnDemandResourceInvalidTagError
is returned when the resource tag being requested cannot be found. This would most likely be a bug on your part, and you may want to make sure you have the correct tag name.
Loading Priorities
The next improvement you can make is setting the loading priority of the request. This only requires a single line.
Open ODRManager.swift and add the following to requestSceneWith(tag:onSuccess:onFailure:)
immediately after guard let request = currentRequest else { return }
:
request.loadingPriority =
NSBundleResourceRequestLoadingPriorityUrgent
NSBundleResourceRequestLoadingPriorityUrgent
tells the operating system to download the content as soon as possible. In the case of downloading the next level of a game, it’s very urgent. You don’t want your users waiting. Remember, if you want to customize the loading priorities, you can use a Double
between 0 and 1.
Purging Resources
You can get rid of unneeded resources by calling the method endAccessingResources
on the current NSBundleResourceRequest
.
Still in ODRManager.swift, add the following line immediately after guard let request = currentRequest else { return }
:
// purge the resources associated with the current request
request.endAccessingResources()
Calling endAccessingResources
now cleans up after yourself and purges the any resources you no longer need. You’re now being a courteous iOS citizen and cleaning up after yourself.
Where to Go From Here?
You can find the completed project here.
I hope that knowing how to use on-demand resources helps you reduce the size of your initial app downloads and makes your users a little happier.
For more in-depth coverage of on-demand resources, check out this excellent 2016 WWDC Video on Optimizing On-Demand Resources.
If you have any questions or comments, please join the forum discussion below!