Managing data always was and will be the main concept behind any application for any platform and at any time. But how we can do this? How to manage data between different sessions of app usage?
One of the simplest and still perfect ways to do this is by using files.
“A computer file is a computer resource for recording data in a computer storage device.” - according to wiki.
On the iOS platform luckily for us there is a bunch of ways how can perform various manipulations within the file (different CRUD operations):
Foundations framework way
FileManager
FileHandle
Files
DispathIO
Stream
C++ API
CRUD - Create Read Update Delete
Foundations framework way
Foundation is a base framework that we use in every app. If we check API from it, we will find a lot of methods/functions that allow us to perform various manipulations within a file. The most known types are: String, Dictionary, Data, Array, etc.
In most cases concrete Type supports only basic functionality:
read
write
I will show examples only for Data type, all other has something similar or specific for concrete type.
Data
The Data type - is a basic type that can represent information. It represents a byte buffer in memory.
For basic operations like save/read here are a few code snippets.
To save data into file we can:
To read data from the file:
FileManager
FileManager is one of the simplest ways to work within a file. Using FileManager we can do all most common operations:
create
read
update
move
delete
we can also use this class for work with directories, not just for files.
To demonstrate all possibilities related to files, we first should obtain an instance of FileManager. To do this, we can use either shared instance either create or own:
This method always represents the same file manager object. If you plan to use a delegate with the file manager to receive notifications about the completion of file-based operations, you should create a new instance of FileManager (using the init method) rather than using the shared object. [source].
Create
To create file we can use simple snipet:
Read
Reading is also trivial operation - all u need, its just a path:
Update
Update operation is a bit tricky - using any approach, its require at least 2 operations - find what to update and perform update.
I will asume in my samples, that we would like simply append some information to the end of the file (in real-world scenarious, u probably needs to find concrete postion for replacement or appending content):
Update is not supported by FileManager, that why we can use a workaround - recreate the file instead.
From the official documentation - “You use it to locate, create, copy, and move files and directories. You also use it to get information about a file or directory or change some of its attributes.”
Move
To change position of a file, we can simply calling only one method:
Delete
To remove unnecessary element fom file system:
FileHandle
FileHandle is a less known, but yet powerful class for working with files. The list of operations is quite different from that one used in FileManager, but usage is much simpler.
Also, this class provides additional possibilities - it allows us to work not only within files, but with sockets, pipes, and devices.
As we are talking about a files, we can:
read
write
seek
update
truncate
It’s good to know, that FileHandle can create asynchronous background I/O operations, so u can use it in systems, where u would like to save some resources for I/O operations.
To use the possibilities of FileHandle, we should create an instance of this class by using one of the existing initializers. The key-point here - we should use init based on our needs. I will show u different initializations of this object below in each examples.
Read
Read is essential part of data management, and FileHandle has a perfect method for this:
Write
To write something in a file we can use next snipet:
With FileHandle we can’t write data to file if the file does not exist.
Seek
Update
Truncate
Remove is not available as an option for FileHandle.
We can, instead, truncate the content:
Files
“The Files app brings all of your files together in iOS 11 or later. You can easily browse, search, and organize all your files in one place. Not just the ones on the device you’re using, but also those in apps, on your other iOS devices, in iCloud Drive, and across other cloud services.”more.
We also can use UIDocument that also can represent data from files. Using this class we can create and read information from files in our apps. To do this, we should describe this feature in metadata of the app - using plist:
Then, define UIDocument subclass that will represent the content of a file and provide some UI for manipulating with files on our file system.
The simplest code for doing this can be as next:
Document description:
Document preview:
Document picker:
Off cause document representation and preview is non-real-world and used just for simplification of the approach presentation.
DispathIO
DispatchIO - An object that manages operations on a file descriptor using either stream-based or random-access semantics. source.
DispatchIO can perform only a few operations within the file descriptor:
read
write
U should use this class when u have a large file and u need to efficiently work within it.
Read
usage:
off_t - This is a data type defined in the sys/types.h header file (of fundamental type unsigned long) and is used to measure the file offset in bytes from the beginning of the file. It is defined as a signed, 32-bit integer, but if the programming environment enables large files off_t is defined to be a signed, 64-bit integer.
Dispatch framework is very powerful, but most of the developers didn’t use its power - instead, only Dispatch.main.async was used. If u would like to find more - u can start by checking Bruno Rocha’s article about DispatchSouce.
Stream
Stream - it’s and abstractions, that allow us to manipulate the data over. In Foundation framework we have InputStream and OutputStreamfor reading and writing.
In the context of a file, using streams, we can:
read
write
Read
output:
Write
output:
There is a lot of discussions about Stream usage, for example this one.
C++ API
Another option for file manipulation use C++ API like fopen and support functions.
We can perform all basic operations within files like:
write/create
read
seek
update
delete
We can use different variants of accessMode and perform various operations, for example - “rb”, “wb”, “ab”, “r+b”, “w+b”, “a+b”, etc.