Skip to content

Basic data storage (Swift)


Prepared and tested with Xcode 9.2 and Swift 4 (2018-04-24)

In this tutorial we cover the following topics


General information

There are many different methods we can use to save our data in iOS devices. Here we will examine the most basic, adequate to save small amount of data.


Sandbox

Every application has its own, independent and restricted, area in file system space, called sandbox. Generaly speaking, no other applications are allowed to get an access to this area. When working with simulator and Xcode, we can find this sandbox in

[YOUR_HOME_DIRECTORY]/Library/Developer/CoreSimulator/Devices/

Let's test it. Open a Finder window and navigate to your home directory. If you can't see your Library folder, hold down the Alt key and select Go | Library from top main menu. Having Library displayed, select Developer/CoreSimulator/Devices/.

Within that directory, there is one subdirectory for each simulator in Xcode installation. The subdirectory names are GUIDs (globally unique identifiers) generated automatically by Xcode, so it’s impossible to know just by looking at them which directory corresponds to which simulator. To find out we should examine a file called device.plist in any of the simulator directories and open it.

We can also examine device_set.plist located in Devices


pc18:Devices fulmanp$ pwd
/Users/fulmanp/Library/Developer/CoreSimulator/Devices
pc18:Devices fulmanp$ ls
017F1FAA-A538-4B05-99DD-56005B2A781E 8DE4F1A7-E3C2-473E-81A4-522DD7A07CC0
033BC02B-C984-44A5-BAF6-858E8521B879 8DFEAA23-D012-4FAB-A7F4-B5D000F2078B
[... cut to save some space ...]
89EF7B1E-0902-4CA6-8FE9-19EB5B99D1E0 FF38963D-624D-423E-8B93-6989F334A20A
8C70AEA1-A42A-42CB-A513-93EF80591E5D device_set.plist
8D3575AE-DBDC-474E-8652-4E2420833DBB
pc18:Devices fulmanp$


[USER_HOME_DIRECTORY]/Library/Developer/CoreSimulator/Devices/device_set.plist

Every application sandbox contains three directories

  • Documents Our application can store data in Documents directory. Use this directory to store user-generated content. If iTunes file sharing is enabled for our application, the user can see the contents of this directory and its subdirectories in iTunes and can also upload files to it.
  • Library This directory is used to store files that we do not want to share with others. This is the top-level directory for any files that are not user data files.
  • tmp This directory is a place where an application can store temporary files. Files written into it will not be backed up by iTunes.


Getting the right path

As we have seen, path to the applicaton folder is somehow random. To get the right one, we have to use one of the function prepared for this occasion.

The same in more Swifty way


General app

  1. Step 1: create a new project
    Create a new project

    1. Select File | New | Project...
    2. Select Single View Application on the template selection sheet.
    3. As the product name enter Swift iOS Basic Data Storage
    4. Set the Language to Swift. Because we will not use tests in this tutorial, you can leave both test check boxes unchecked as well as make sure the check box labeled Use Core Data is also unchecked.
  2. Step 2: add components
    1. Select Main.storyboard and from the Object library drag
      • one Text field
      • two Buttons
      • one Text view

    2. Set all the constraints required for a correc layout.
      • Set Title for a left button as Save.
      • Set Title for a right button as Load.
    3. Create outlets for all components so we can use them in the future
      • for Text field creat textField outlet
      • for left (Save) Button creat buttonSave outlet
      • for right (Load) Button creat buttonLoad outlet
      • for Text view creat textView outlet
    4. Create actions for button
      • for left (Save) Button creat buttonPressSave action
      • for right (Load) Button creat buttonPressLoad action

    Now our code should look like below


Property list with deprecated NSArray write(to:atomically:)

In case we want to use property lists to persist our data, we have to use either an NSArray or an NSDictionary as a main data structure to hold the data that needs to be saved. In addition to this we can build our data model from the following objects

  • NSArray, NSMutableArray
  • NSDictionary, NSMutableDictionary
  • NSData, NSMutableData
  • NSString, NSMutableString
  • NSNumber
  • NSDate

Main drawback of this approach is that custom objects cannot be serialized into property lists.

Assuming that all the objects that we put into the NSArray or an NSDictionary are serializable objects from this list, we can write and read a property list, like so

  1. Step 1: add/modify ViewController's code to get path
  2. Step 2: add/modify code
  3. Step 3: run app
    Executed an application and press Save button. A path smilar to the following should be printed as an output in the Text view

    file:///Users/fulmanp/Library/Developer/CoreSimulator/Devices/7CF76BA3-51AB-461C-8AE5-B890E6971352/
    data/Containers/Data/Application/6D3282F2-343B-40BC-A0DB-C12FF847F1AC/Documents/test.plist

    We can check its contents

    When Load is pressed, the following text should be printed as an output in the Debug area

    (
    {
    0 = 1;
    items = 1;
    name = "List 1";
    },
    {
    0 = 2;
    1 = test2;
    items = 2;
    name = "List 2";
    },
    {
    0 = 2;
    2 = test3;
    3 = "3.21";
    items = 3;
    name = "List 3";
    }
    )


Property list with Codable protocol

NSArray write(to:atomically:) is deprecated and the Codable protocol which is new to Swift in iOS 11 should be used instead. In some sense Code is a logical consequence of preceding NSCoding protocol.
Some good materials are

  1. Step 1: add/modify code
  2. Step 2: run app
    Executed an application and press Save button. A path smilar to the following should be printed as an output in the Text view

    file:///Users/fulmanp/Library/Developer/CoreSimulator/Devices/7CF76BA3-51AB-461C-8AE5-B890E6971352/
    data/Containers/Data/Application/2A5CB84C-D982-4FE0-AACD-E69813E905E4/Documents/test.plist

    We can check its contents

    When Load is pressed, the following text should be printed as an output in the Debug area

    [["items": "1", "0": "1", "name": "List 1"], ["items": "2", "name": "List 2", "1": "test2",
    "0": "2"], ["items": "3", "name": "List 3", "2": "test3", "0": "2", "3": "3.21"]]
    List 2


Bundle property list with Codable protocol

Codable and bundle property list works exactly the same way as property lists. The only true diference is how we get the path to a bundle propert list.

  1. Step 1: cerate bundle property list
    • In the Project Navigator, right-click the Swift iOS Basic Data Storage group and select New File....
    • Choose Property List from the iOS | Resources section in the template dialog and then press Next
    • Name the property list Settings.plist and press Create. We should see a blank property list
  2. Step 2: add property list items
    • When hover over the root entry we will find a + button to add an entry
    • When the + button is clicked a new entry appears, with a default type of String
    • By analogy, add some items
  3. Step 3: add/modify code
  4. Step 4: run app
    • Executed an application and press Load button. The following text should be printed as an output in the Debug area

      ["Setting 1": "Value 1"]
      Value 1
    • Press Save button. A path smilar to the following should be printed as an output in the Text view

      file:///Users/fulmanp/Library/Developer/CoreSimulator/Devices/7CF76BA3-51AB-461C-8AE5-B890E6971352/
      data/Containers/Bundle/Application/689888CB-3540-457C-952B-4A2D8E29B941/Swift%20iOS%20Basic%20Data%
      20Storage.app/Settings.plist

      We can check its contents
    • Press Load button. The following text should be printed as an output in the Debug area

      ["items": "3", "name": "List 3", "2": "test3", "0": "2", "3": "3.21"]


Encode and decode with a custom type

As we have seen Codable protocols simplify saving our data to propert list. If we want to operate this way with more complex object than for example [String: String] dictionary, preferably something like [String: Any], we have to use custom types. Having custom type, we can save/read our data to/from a property list as well as JSON. Some good materials we can read about this were mentioned in Property list with Codable protocol section. In short, to encode and decode a custom type, we need to make it Codable. The simplest way to make a type codable is to declare its properties using types that are already Codable

  • Built-in Codable types: String, Int, Double, Data, URL.
  • Array, Dictionary, Optional are Codable if they contain Codable types.

We will show how it works with JSON files, but the same apprach is used for property list - simply use ideas from the previous sections: Property list with Codable protocol or Bundle property list with Codable protocol.

  1. Step 1: change path generating code to make it more Swifty
  2. Step 2: add custom types to be saved
  3. Step 3: add/modify code
  4. Step 4: run app
    Executed an application and press Save button. A path smilar to the following should be printed as an output in the Debug area

    {"count":3,"lists":[{"itemBool":true,"itemString":"String 1","name":"List 1","itemInt":1,"itemFloat":1.23},
    {"itemBool":false,"itemString":"String 2","name":"List 2","itemInt":2,"itemFloat":2.3399999999999999},{"ite
    mBool":true,"itemString":"String 3","name":"List 3","itemInt":3,"itemFloat":3.4500000000000002}]}

    At the same time a path smilar to the following should be printed as an output in the Text view

    file:///Users/fulmanp/Library/Developer/CoreSimulator/Devices/7CF76BA3-51AB-461C-8AE5-B890E6971352/data/
    Containers/Data/Application/3520AE20-2B0C-4737-80A2-9B5B0902C07D/Documents/test.json

    We can check its contents

    When Load is pressed, the following text should be printed as an output in the Debug area

    3
    List 1: 1 String 1 1.23 true
    List 2: 2 String 2 2.34 false
    List 3: 3 String 3 3.45 true


Sources