Adobe
Products

Top destinations

  • Adobe Creative Cloud
  • Creative Suite 6
  • Adobe Marketing Cloud
  • Acrobat
  • Photoshop
  • SiteCatalyst
  • Students
  • Elements family

Adobe Creative Cloud

  • What is Adobe Creative Cloud?
  • Design
  • Web
  • Photography
  • Video
  • Students
  • Teams
  • Enterprise
  • Educational institutions
  • Government

Design and photography

  • Photoshop
  • Illustrator
  • InDesign
  • Adobe Muse
  • Lightroom

Video

  • Adobe Premiere
  • After Effects

Web development and HTML5

  • Edge Tools & Services [opens in a new window]
  • Dreamweaver
  • Gaming [opens in a new window]

Adobe Marketing Cloud

  • What is Adobe Marketing Cloud?
  • Digital analytics
  • Social marketing
  • Web experience management
  • Testing and targeting
  • Media optimization

Analytics

  • SiteCatalyst
  • Adobe Discover
  • Insight

Social

  • Adobe Social

Experience Manager

  • CQ
  • Scene7

Target

  • Test&Target
  • Recommendations
  • Search&Promote

Media Optimizer

  • AdLens
  • AudienceManager
  • AudienceResearch

Document services

  • Acrobat
  • EchoSign [opens in a new window]
  • FormsCentral [opens in a new window]
  • SendNow [opens in a new window]
  • Acrobat.com [opens in a new window]

Publishing

  • Digital Publishing Suite

  • See all products
Business solutions

By business need

  • Digital analytics
  • Digital publishing
  • Document management
  • Media optimization
  • Social marketing
  • Testing and targeting
  • Video editing and serving
  • Web development [opens in a new window]
  • Web experience management
  • See all business needs

By industry

  • Broadcast
  • Education
  • Financial services
  • Government
  • Publishing
  • Retail
  • See all industries
Support & Learning

I need help

  • Products
  • Adobe Creative Cloud
  • Adobe Marketing Cloud
  • Forums [opens in a new window]

I want to learn

  • Training and tutorials
  • Certification [opens in a new window]
  • Adobe Developer Connection
  • Adobe Design Center
  • Adobe TV [opens in a new window]
  • Adobe Marketing Center
  • Adobe Labs [opens in a new window]
Download
  • Product trials
  • Adobe Flash Player
  • Adobe Reader
  • Adobe AIR
  • See all downloads
Company
  • Careers at Adobe
  • Investor Relations
  • Newsroom
  • Privacy
  • Corporate Social Responsibility
  • Customer Showcase
  • Contact us
  • More company info
Buy
  • For personal and professional use
  • For students, educators, and staff
  • For small and medium businesses
  • Volume Licensing
  • Special offers
  • Adobe Marketing Cloud sales [opens in a new window]
Search
 
Info Sign in
Why sign in? Sign in to manage your account and access trial downloads, product extensions, community areas, and more.
Welcome,
My Adobe
My orders
My information
My preferences
My products and services
Sign out
My cart
Privacy My Adobe
Adobe
Products Sections Buy   Search  
Solutions Company
Help Learning
Sign in Sign out Privacy My Adobe
Preorder Estimated Availability Date. Your credit card will not be charged until the product is shipped. Estimated availability date is subject to change. Preorder Estimated Availability Date. Your credit card will not be charged until the product is ready to download. Estimated availability date is subject to change.
Qty:
Purchase requires verification of academic eligibility
Subtotal
Promotions
Estimated shipping
Tax
Calculated at checkout
Total
Review and Checkout
Adobe Developer Connection / Gaming /

Saving state in AIR applications for iOS devices

by Ben Garney

Ben Garney
  • CoderHump

Content

  • Considering state issues
  • Saving state on iOS devices
  • Methods for saving
  • State management architecture
  • Where to go from here

Modified

12 May 2011

Page tools

Share on Facebook
Share on Twitter
Share on LinkedIn
Bookmark
Print
ActionScriptAdobe AIRFlash Professional CCgame developmentgamingiOSmobilestates
Was this helpful?
Yes   No

By clicking Submit, you accept the Adobe Terms of Use.

 
Thanks for your feedback.

Requirements

Prerequisite knowledge

Familiarity with ActionScript 3 and its object-oriented features as well as familiarity with Flash application development.

User level

Intermediate

Required products

  • Flash Professional CC (Download trial)
  • Adobe AIR

A big part of what makes Apple iOS such a great mobile platform is its user interface. Whether you are developing natively or with Adobe Flash Professional CS5.5, users of iOS devices expect you—the application developer—to make your application fit in with the existing iOS experience. An essential part of that experience is interruptibility: your Adobe AIR application needs to save its state frequently and automatically so that it can be switched automatically as users expect—and as Apple specifies in its iPhone Human Interface Guidelines.

This article presents some strategies for saving your application state on iOS devices. The basic capabilities of iOS devices are covered, as well as application design techniques to help give a seamless user experience. I also provide code that demonstrates different techniques for saving state.

Considering state issues

The Apple iOS runs only a single user application at a time to keep the device responsive. Whenever the user launches another application, or an outside event like a phone call occurs, your application can be terminated. This can lead to frustrations for the user: imagine if you were writing a text message or e-mail and a phone call came in and you lost your work! Because of this, it is essential that your application save its state regularly and automatically.

My colleagues and I at PushButton Labs developed a game called Trading Stuff in Outer Space for the iPhone last year using the Flash Professional CS5 (see Figure 1). It is a simple space-based trading game that was developed in eight days to explore the technology. One of the goals of the project was to provide an experience indistinguishable from any other iPhone game. As a result, we had to figure out how to make saving state work.

Trading Stuff in Outer Space game screen
Figure 1. Trading Stuff in Outer Space game screen

Saving state on iOS devices

We envisioned the scenario of applications that lose data when they are interrupted. Of course, the built-in iOS apps don't do that—when you go back to your text messages after that interrupting phone call, you pick up right where you left off. This is done by the simple expedient of saving state when the application is ordered to quit by the OS. In the Objective-C world, you will have to implement this yourself (see the appropriate section of the iOS Application Programming Guide), and it is no different when you are developing with Flash.

Saving on exit

How do you know when to save in Flash? Since AIR applications for iOS share the same API as AIR apps for Adobe AIR, you can listen for the NativeApplication.EXITING event to know when to save your state:

package { import flash.desktop.NativeApplication; import flash.display.Sprite; import flash.events.Event; public class Save1 extends Sprite { public function Save1() { // Listen for exiting event. NativeApplication.nativeApplication.addEventListener(Event.EXITING, onExit); // Load data. load(); } private function onExit(e:Event):void { trace("Save here."); } private function load():void { trace("Load here."); } } }

Saving on important events

However, you should also save after crucial events or after a certain interval has passed. For Trading Stuff in Outer Space, crucial events include whenever the player trades (since it is an action that takes a lot of thought and has major effects on gameplay), when the player arrives at a planet, and whenever the player starts or ends a game. For an interval, we chose a period of 30–60 seconds, so that the user would never lose more than a minute's playtime. We chose that threshold because we felt that it was high enough to allow responsive play but low enough to avoid infuriating a user if something causes saving-on-exit to fail.

Unfortunately, the EXITING event isn't 100% reliable. It doesn't always get fired—sometimes due to time limits in the OS, sometimes due to other causes. Your application may crash (although it's unlikely), in which case the normal exiting behavior won't happen. So what we did was to save after every major operation the user performed, as well as approximately once a minute. That way even if users did manage to quit without the application saving state, it was unlikely they would lose more than few seconds of work:

package { import flash.desktop.NativeApplication; import flash.display.Sprite; import flash.events.Event; import flash.utils.setInterval; public class Save2 extends Sprite { public function Save2() { // Listen for exiting event. NativeApplication.nativeApplication.addEventListener(Event.EXITING, onExit); // Also save every 30 seconds. setInterval(save, 30*1000); // Load data. load(); } private function onExit(e:Event):void { save(); } private function save():void { trace("Save here."); } private function load():void { trace("Load here."); } } }

General applicability

The issues facing an AIR app on iOS devices are not that different from those facing SWF content in the browser. Users' browsers might crash or users might (accidentally or on purpose) navigate away from the page. Even desktop users may want their applications to always be stateful. You can use the same saving code to enhance the user experience on the web, devices, and the desktop.

Methods for saving

You can save your state in two main ways with AIR applications on iOS devices. One is with an LSO (local SharedObject). As you know, SharedObject.getLocal() (see the documentation) can be used to store data locally. This is convenient for a variety of reasons, not least of which is that you can use AMF to store object graphs:

private function save():void { // Get the shared object. var so:SharedObject = SharedObject.getLocal("myApp"); // Update the age variable. so.data['age'] = int(so.data['age']) + 1; // And flush our changes. so.flush(); // Also, indicate the value for debugging. trace("Saved generation " + so.data['age']); } private function load():void { // Get the shared object. var so:SharedObject = SharedObject.getLocal("myApp"); // And indicate the value for debugging. trace("Loaded generation " + so.data['age']); }

In the end, serializing objects directly worked against us in this game application. Depending on your application, using SharedObject might be a perfect fit. For Trading Stuff, I had a lot of complex interrelated data to store, and I also wanted to segregate game state into frequently changed and infrequently changed elements, so using LSOs wasn't a good fit. More on that next.

Saving using file objects

The other approach is to use File objects directly. You can write asynchronously in order to avoid disrupting the frame rate. If different parts of the game state change at different frequencies, you can store them in separate files so that only what actually changes is touched. You have to do your own serialization, but this isn't as bad as it sounds. (You can even use readObject() and writeObject() to store a whole object at once, although this can cause problems in some cases.)

public var age:int = 0; /** * Get a FileStream for reading or writing the save file. * @param write If true, we will write to the file. If false, we will read. * @param sync If true, we do synchronous writes. If false, asynchronous. * @return A FileStream instance we can read or write with. Don't forget to close it! */ private function getSaveStream(write:Boolean, sync:Boolean = true):FileStream { // The data file lives in the app storage directory, per iPhone guidelines. var f:File = File.applicationStorageDirectory.resolvePath("myApp.dat"); if(f.exists == false) return null; // Try creating and opening the stream. var fs:FileStream = new FileStream(); try { // If we are writing asynchronously, openAsync. if(write && !sync) fs.openAsync(f, FileMode.WRITE); else { // For synchronous write, or all reads, open synchronously. fs.open(f, write ? FileMode.WRITE : FileMode.READ); } } catch(e:Error) { // On error, simply return null. return null; } return fs; } private function load():void { // Get the stream and read from it. var fs:FileStream = getSaveStream(false); if(fs) { try { age = fs.readInt(); fs.close(); } catch(e:Error) { trace("Couldn't load due to error: " + e.toString()); } } trace("Loaded age = " + age); } private function save():void { // Update age. age++; // Get stream and write to it – asynchronously, to avoid hitching. var fs:FileStream = getSaveStream(true, false); fs.writeInt(age); fs.close(); trace("Saved age = " + age); }

Both of these should be straightforward to understand. If you've done Flash or AIR development, you've almost certainly dealt with either SharedObject or File. If not, you might want to refer to their documentation for details and examples.

You can also use readObject() and writeObject() to store or retrieve an object from a File object. This is powerful and saves you from a lot of repetitive serialization code. However, if you aren't careful, it can introduce problems: for instance, saving a DisplayObject won't work due to the various helper objects and complex relationships involved. Even saving pure data classes can be risky because they may have references to other objects that you don't want to serialize.

Saving the state of your whole application is, of course, more involved. I discuss this issue next.

State management architecture

The larger issue I ran into was serializing all my application data. Figuring out where to write is easy, but figuring out what to write is a little trickier. Naturally, because I am a programmer, I wanted to do it with as little work as possible.

The first thing I tried was directly serializing parts of my DisplayObject hierarchy and game state via AMF in a SharedObject. This was attractive initially because I figured I could throw references to a few key parts of my application into the SharedObject and be done. However, this didn't work: DisplayObjects have lots of helper objects with strange construction restrictions that are not AMF-friendly. It also led to uncontrolled serialization, where the object I was serializing contained a reference to other objects that ended up bringing in most of my application—and I didn't want to waste time debugging issues from strange dangling objects being serialized.

So, instead, I switched to use the File save() method. This meant I had to write some code to load and save objects that made up the state of my application. Up front, this involved more lines of code, but since they were direct and simple—and I did not plan on modifying the application much past launch—this approach ended up being much quicker to write and debug than the fewer lines of code that would be required for a more automatic solution.

The following code snippet shows what saving and loading looks like for the user's current waypoint:

// Serialize current waypoint. gfs.writeInt(currentWaypointIndex); gfs.writeBoolean(wayPoint != null); if(wayPoint != null) { gfs.writeFloat(wayPoint.x); gfs.writeFloat(wayPoint.y); } // Load waypoint state. currentWaypointIndex = gfs.readInt(); if(gfs.readBoolean()) { wayPoint = new Point(); wayPoint.x = gfs.readFloat(); wayPoint.y = gfs.readFloat(); } else { wayPoint = null }

As you can see, the serialization code has to allocate objects when appropriate; it has to detect if variables are null, and note that in the file; and it has to write each field with the right type. This can be a little overwhelming at first, but with a little practice you'll quickly realize that you are reusing a small set of common idioms for nearly every task.

I also made a singleton to manage all my game state. It kept track of the player's inventory, the locations of everything in the universe, the status of enemies, progress with missions, and so forth. From this singleton, I had methods to reset the game's state, to write it, and to read it back again. In some cases (such as inventory or missions) the state was owned by the singleton. In other cases (such as positions of game objects like the player and planets) the state is managed elsewhere, by other objects, but the singleton can get to it for saving purposes. On top of this foundation, it was easy to implement various saving strategies, as mentioned previously.

Where to go from here

Saving state is a key part of making your content fit smoothly into the iOS experience. Since only one application at a time can currently run on iOS devices, it's important to store not only the user's data, but the state of your application's UI. It's not a difficult detail, but it is an important one. I hope this article has helped you understand the key pieces involved in implementing this important functionality in your own application.

Saving state is a broad topic; there's no one-size-fits-all solution. A quick overview of the many different options for serialization can be found in the Serialization entry on Wikipedia. Flash natively supports XML (see Colin Moock's book, Essential ActionScript 3, for several great chapters on XML and E4X) and AMF, which are good building blocks for your serialization needs. There are also libraries like as3corelib that add support for JSON and other serialization formats. Of course, when you're saving application state between runs, what matters most is that the technology you choose is simple, easy to work with, and reliable.

From here, you might want to take the sample code included with this article and try to integrate it with your own content. There are a few decision points, such as using local SharedObjects or File objects, or saving frequently vs. infrequently. Make sure to run a few tests before deciding one way or the other; informed decisions are always best, and the information you need will depend on your specific application. Once you have a solution, test it by frequently quitting in the middle of your program's execution. It might not be possible to restore every piece of state exactly, but with surprisingly little work you will get close enough so that users accept your application as part of their positive iOS device experience.

Check out this series of articles to help you learn more about developing for iOS using Flash Professional:

  • Developing for iOS using Flash
  • Using screen orientation APIs for smartphone application development
  • Optimizing content for Apple iOS devices
  • Guide for Apple App Store submissions

Creative Commons License
This work is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License

More Like This

  • Flash glossary: Package
  • Flash glossary: Flash Player
  • Flash glossary: Document class
  • Flash glossary: Runtime shared library
  • Flash glossary: Output panel
  • Flash glossary: Preloader
  • Flash glossary: Transparency
  • Creating the Kuler panel for Flash CS3 Professional
  • Formatting text for localized Flash projects
  • Augmented reality using a webcam and Flash

Products

  • Adobe Creative Cloud
  • Creative Suite 6
  • Adobe Marketing Cloud
  • Acrobat
  • Photoshop
  • Digital Publishing Suite
  • Elements family
  • SiteCatalyst
  • For education

Download

  • Product trials
  • Adobe Reader
  • Adobe Flash Player
  • Adobe AIR

Support & Learning

  • Product help
  • Forums

Buy

  • For personal and professional use
  • For students, educators, and staff
  • For small and medium businesses
  • Volume Licensing
  • Special offers

Company

  • News room
  • Partner programs
  • Corporate social responsibility
  • Career opportunities
  • Investor Relations
  • Events
  • Legal
  • Security
  • Contact Adobe
Choose your region United States (Change)
Choose your region Close

North America

Europe, Middle East and Africa

Asia Pacific

  • Canada - English
  • Canada - Français
  • Latinoamérica
  • México
  • United States

South America

  • Brasil
  • Africa - English
  • Österreich - Deutsch
  • Belgium - English
  • Belgique - Français
  • België - Nederlands
  • България
  • Hrvatska
  • Česká republika
  • Danmark
  • Eastern Europe - English
  • Eesti
  • Suomi
  • France
  • Deutschland
  • Magyarország
  • Ireland
  • Israel - English
  • ישראל - עברית
  • Italia
  • Latvija
  • Lietuva
  • Luxembourg - Deutsch
  • Luxembourg - English
  • Luxembourg - Français
  • الشرق الأوسط وشمال أفريقيا - اللغة العربية
  • Middle East and North Africa - English
  • Moyen-Orient et Afrique du Nord - Français
  • Nederland
  • Norge
  • Polska
  • Portugal
  • România
  • Россия
  • Srbija
  • Slovensko
  • Slovenija
  • España
  • Sverige
  • Schweiz - Deutsch
  • Suisse - Français
  • Svizzera - Italiano
  • Türkiye
  • Україна
  • United Kingdom
  • Australia
  • 中国
  • 中國香港特別行政區
  • Hong Kong S.A.R. of China
  • India - English
  • 日本
  • 한국
  • New Zealand
  • 台灣

Southeast Asia

  • Includes Indonesia, Malaysia, Philippines, Singapore, Thailand, and Vietnam - English

Copyright © 2013 Adobe Systems Incorporated. All rights reserved.

Terms of Use | Privacy (Updated) | Cookies

Ad Choices