FileStorageKey

A type defining a file persistence strategy

FileStorageKey.swift:72FileStorageKey.md
final class FileStorageKey<Value> where Value : Sendable

Use fileStorage(_:decoder:encoder:) to create values of this type.

A SharedKey conformance that persists complex pieces of data to the file system. It works with any kind of type that can be serialized to bytes, including all Codable types. It can be used with Shared by providing the fileStorage(_:decoder:encoder:) value and specifying a default:

extension URL {
  static let users = URL(/* ... */)
}
@Shared(.fileStorage(.users)) var users: [User] = []

Any changes made to this value will be automatically synchronized to the URL on disk provided. Further, any change made to the file stored at the URL will also be immediately played back to the @Shared value, as this test proves:

@Test(.dependency(\.defaultFileStorage, .fileSystem))
func externalWrite() throws {
  let url = URL.temporaryDirectory.appending(component: "is-on.json")
  try? FileManager.default.removeItem(at: url)

  @Shared(.fileStorage(url)) var isOn = true
  #expect(isOn == true)
  try Data("false".utf8).write(to: url)
  #expect(isOn == false)
}

Default file storage

When running your app in a simulator or device, fileStorage will use the actual file system for saving and loading data. However, in tests and previews fileStorage uses an in-memory, virtual file system. This makes it possible for previews and tests to operate in their own sandboxed environment so that changes made to files do not spill over to other previews or tests, or the simulator. It also allows your tests to pass deterministically and for tests to be run in parallel.

If you really do want to use the live file system in your previews, you can use prepareDependencies:

#Preview {
  let _ = prepareDependencies { $0.defaultFileStorage = .fileSystem }
  // ...
}

And if you want to use the live file system in your tests you can use the dependency test trait:

@Test(.dependency(\.defaultFileStorage, .fileSystem))
func basics() {
  // ...
}

Storing a value

Overriding storage

Identifying storage