Many mobile applications show the user content from the server, and this content can be shown online and offline. Working online is trivial - at a specific UI event, the application reads data from the network and shows it to the user. Work offline can be much more interesting - the ability to work with documents in the subway and so on. But work outside the network brings problems: it is now necessary to synchronize data and this process should not block the user interface.
Items in source code
- access to network resources
- xml processing
- access to the file system
- work with threads
Application Requirements
The application should show text files from the server in offline mode. At each start, synchronization occurs. At the same time, the update process should not block the work of the user with the interface. The update process itself consists of two steps:
1. Reading the list of files from the server
2. Download missing files
Code design
To manage the entire process, we will create an UpdateManager class that will manage the “Updaters” objects. At the moment we need two “Updaters”: one to read the list of files and the second to work with files. For them, we define a single facade that will expand the system in the future. This facade will have at least one method - start - which will be called by UpdateManager for each Updater in turn.
')
We know in advance that we will use an asynchronous connection to access the network. This forces us to clearly continue the work of UpdateManager after each Updater has completed.
We declare two protocols:
@protocol UpdateManagerProtocol - (void) next;
end@protocol UpdaterProtocol - (void) startUpdate: (id) manager;
endUpdateManagerProtocol declares one method that is called by each Updater upon completion of work.
Our classes look like this:

All Updaters work the same way:

XMLListUpdater performs the steps:
1. Reads xml file from server to clipboard
2. Parses xml
3. Add each file to the queue
FileUpdater performs the steps:
1. Get the next file from the queue
2. Checks if the file already exists on disk
3. Download file
4. Repeats the process if the queue is not empty.
Source
First, let's write the code, without mentioning the threads.
UpdateManager.h declares one static method to start the whole process. In the constructor (init) of the instance, all Updaters are created, added to the queue and called one after the other.
Since each Updater reads data from the network, the common code can be put into a separate class - NetworkClient. It implements the UpdaterProtocol along with a method to start an asynchronous connection (startNetworkCall).
First Updater - XMLFileUpdater. When starting, it reads xml into memory from a previously known address. Upon completion, XMLListUpdater creates an xml parser for data processing. Each file in the list is added to the queue for processing by the following Updater.
The second step is to update the FilesUpdater content - it must read the queue and download each missing file.
Now we can start the UpdateManager process, when the main view is loaded, the application synchronizes the content.
View contains only one button, without any action. When updating the content, the interface will be blocked and clicking on the button will reveal it. Later we get rid of the lock by adding a new thread.
Add a separate thread
Since we already have all the code for working with data, we need only to launch a separate stream and perform the update in it.
Add a new method to UpdateManager - startInThread. With simple steps:
1. Create NSAutoReleasePool
2. Start the update process
3. Run RunLoop
4. Release the pool
NSAutoRelease must be created in each new thread for automatic memory management. Otherwise, you will get a lot of errors in the console.
RunLoop is a more interesting thing. If you comment out RunLoop and start the application, you will see a message about the beginning of the network connection, but the rest of the events - like receiving data from the network, ending the connection - will not occur. The problem is in the early termination of the thread - which ends when exiting the “startInThread” method. Therefore, we run RunLoop to keep the thread active.
Now the initialization of UpdateManager can be moved to main.m.
Source Code Notes
UpdateManager.h contains compilation directives - WORK_IN_SEPARATE_THREAD. If it is set to zero, then a new thread will not be created and the UI will be blocked. At one, the update will occur in a separate thread.
Project Source:
SF.netAndrew Romanenco
andrew@romanenco.com
April 2010