Sandboxing in iOS is a foundational security mechanism that isolates each app in its own secure environment. This isolation prevents unauthorized access to system resources and user data, ensuring that apps cannot interfere with one another.

For developers, understanding how to manage files and directories within this sandbox is crucial. It determines how and where persistent data, user-generated content, and temporary files are stored—directly affecting app functionality, user privacy, and compliance with App Store requirements.

The goal of this post is to demystify these concepts. By doing so, it empowers developers to build secure, reliable, and user-friendly applications that align with iOS’s strict security model while effectively leveraging the available file system APIs.

The Sandbox

In iOS, a sandbox is a security mechanism that restricts apps to their own designated area, preventing them from accessing files, resources, or data belonging to other apps or the system without explicit permission. This isolation ensures stability, security, and privacy for users.

Key Features of iOS Sandbox:

  1. App Isolation

    • Each app runs in its own sandboxed environment with its own directory for files.

    • Apps cannot directly read or modify files from other apps.

  2. Controlled Access to System Resources

    • Apps must request permissions (via entitlements or user consent) to access sensitive data like:

      • Contacts (Contacts.framework)

      • Photos (PHPhotoLibrary)

      • Location (CoreLocation)

      • Camera & Microphone (AVFoundation)

  3. File System Restrictions

    • Apps can only write files in their own sandbox directories, such as:

      • Documents/ (user-generated content, backed up by iTunes/iCloud)

      • Library/ (app support files, some backed up)

      • Caches/ (temporary files, can be purged by the system)

      • tmp/ (short-lived files, not backed up)

  4. No Direct Hardware or Kernel Access

    • Apps interact with hardware (e.g., GPU, sensors) only through Apple’s frameworks.

    • No root-level system modifications are allowed (unlike jailbroken devices).

  5. Inter-App Communication (Limited & Controlled)

    • Apps can share data only via:

      • URL Schemes (custom deep links like myapp://)

      • App Groups (shared containers for related apps)

      • UIActivityViewController (share sheets)

      • Universal Clipboard (limited-time data sharing)

Why Does iOS Use a Sandbox?

  • Security: Prevents malware from spreading or tampering with other apps.

  • Privacy: Ensures apps access only permitted user data.

  • Stability: Crashes or bugs in one app don’t affect others.

Example: Accessing the Sandbox in Code

To get an app’s sandbox directory in Swift:

struct PeopleView: View {
    @StateObject var viewModel = PeopleViewModel()
    
    var body: some View {
        NavigationView {
            ...
        }.onAppear {
            if let documentsPath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first {
                print("📂 Document Directory: \(documentsPath.path)")
            }
        }
    }
}

The snippet is used to retrieve and print the path to the app’s Documents directory on an iOS or macOS device. Its parent folder is the sandbox root folder for your current app.

Exceptions to the Sandbox:

  • System apps (e.g., Messages, Mail) have broader privileges.

  • Jailbroken devices bypass sandbox restrictions (but violate Apple’s policies).

The sandbox is a core reason iOS is considered more secure than open platforms. Developers must work within its constraints while using Apple’s APIs for permitted interactions.

Our privacy is compromised the moment a malicious app can access another app’s sandbox. Theoretically, this kind of sandbox breach hasn’t been documented on iOS—at least not to my knowledge. However, the video Broken Isolation – Draining Your Credentials from Popular macOS Password Managers by Wojciech Reguła (NSSpain 2024) demonstrates how, on macOS, a malicious app can gain access to the sandboxes of other apps that store user passwords—such as NordPass, KeePass, Proton Pass, and even 1Password.

Sandbox data container folders

Each iOS app has its own container directory with several subdirectories. Here’s a breakdown of the key folders and their purposes:

1. Documents

  • Path: .../Documents/

  • Purpose: Stores user-generated content or data that should persist and be backed up to iCloud.

  • Example: Saved notes, PDFs, exported data.

  • Backup: ✅ Included in iCloud/iTunes backups.

  • Access: Read/Write.

2. Library

  • Path: .../Library/

  • Purpose: Stores app-specific files and configuration data.

    It has two main subfolders:

    • Preferences

      • .../Library/Preferences/

      • Stores user settings (e.g., using UserDefaults).

      • Managed automatically by the system.

    • Caches

      • .../Library/Caches/

      • Used for data that can be regenerated (e.g., image cache).

      • Not backed up, and iOS may delete files here when space is low.

      • ⚠️ Don’t store critical data here.

4. tmp

  • Path: .../tmp/

  • Purpose: Temporary files your app doesn’t need to persist between launches.

  • Backup: ❌ Not backed up.

  • Auto-clean: iOS may clean this directory at any time.

  • Access: Read/Write.

Summary Table

FolderPurposePersistentBacked UpiOS May Delete
App BundleApp code and resources
DocumentsUser data/files
Library/PreferencesApp settings (UserDefaults)
Library/CachesCached data (non-critical)
tmpTemporary files

 

 

Files operations

For this section, we have developed a sample iOS application that performs storage operations using files. The app displays an empty list with an “Add” button in the navigation bar. Each time the button is pressed, a new person is added to the list. The list of people serves as the model and is persisted as a .json file.

When we deploy on simulator (or real device):

The component that handles files operations:

class FileManagerHelper {
    static let shared = FileManagerHelper()
    
    private let fileName = "people.json"
    
    private var fileURL: URL {
        let documents = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
        return documents.appendingPathComponent(fileName)
    }

    func save(_ people: [Person]) {
        do {
            let data = try JSONEncoder().encode(people)
            try data.write(to: fileURL)
        } catch {
            print("Error saving file: \(error)")
        }
    }
    
    func load() -> [Person] {
        do {
            let data = try Data(contentsOf: fileURL)
            let people = try JSONDecoder().decode([Person].self, from: data)
            return people
        } catch {
            print("Error reading file: \(error)")
            return []
        }
    }
    
    func deleteFile() {
        do {
            try FileManager.default.removeItem(at: fileURL)
        } catch {
            print("Error deleting file: \(error)")
        }
    }
}

FileManagerHelper is a singleton utility that manages saving, loading, and deleting a JSON file named people.json in the app’s documents directory. It provides methods to encode an array of Person objects into JSON and save it to disk (save), decode and return the array from the saved file (load), and remove the file entirely (deleteFile). It handles errors gracefully by catching exceptions and printing error messages without crashing the app.

Conclusions

With that post, I just intended to give you an overview and demonstrate how easy it is to deal with file persistence as well.

You can find source code used for writing this post in following repository

References

Copyright © 2024-2025 JaviOS. All rights reserved