123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306 |
- ////////////////////////////////////////////////////////////////////////////
- //
- // Copyright 2015 Realm Inc.
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- //
- ////////////////////////////////////////////////////////////////////////////
- import Foundation
- import Realm
- import Realm.Private
- extension Realm {
- /**
- A `Configuration` instance describes the different options used to create an instance of a Realm.
- `Configuration` instances are just plain Swift structs. Unlike `Realm`s and `Object`s, they can be freely shared
- between threads as long as you do not mutate them.
- Creating configuration values for class subsets (by setting the `objectClasses` property) can be expensive. Because
- of this, you will normally want to cache and reuse a single configuration value for each distinct configuration
- rather than creating a new value each time you open a Realm.
- */
- public struct Configuration {
- // MARK: Default Configuration
- /**
- The default `Configuration` used to create Realms when no configuration is explicitly specified (i.e.
- `Realm()`)
- */
- public static var defaultConfiguration: Configuration {
- get {
- return fromRLMRealmConfiguration(RLMRealmConfiguration.default())
- }
- set {
- RLMRealmConfiguration.setDefault(newValue.rlmConfiguration)
- }
- }
- // MARK: Initialization
- /**
- Creates a `Configuration` which can be used to create new `Realm` instances.
- - note: The `fileURL`, `inMemoryIdentifier`, and `syncConfiguration` parameters are mutually exclusive. Only
- set one of them, or none if you wish to use the default file URL.
- - parameter fileURL: The local URL to the Realm file.
- - parameter inMemoryIdentifier: A string used to identify a particular in-memory Realm.
- - parameter syncConfiguration: For Realms intended to sync with the Realm Object Server, a sync configuration.
- - parameter encryptionKey: An optional 64-byte key to use to encrypt the data.
- - parameter readOnly: Whether the Realm is read-only (must be true for read-only files).
- - parameter schemaVersion: The current schema version.
- - parameter migrationBlock: The block which migrates the Realm to the current version.
- - parameter deleteRealmIfMigrationNeeded: If `true`, recreate the Realm file with the provided
- schema if a migration is required.
- - parameter shouldCompactOnLaunch: A block called when opening a Realm for the first time during the
- life of a process to determine if it should be compacted before being
- returned to the user. It is passed the total file size (data + free space)
- and the total bytes used by data in the file.
- Return `true ` to indicate that an attempt to compact the file should be made.
- The compaction will be skipped if another process is accessing it.
- - parameter objectTypes: The subset of `Object` subclasses persisted in the Realm.
- */
- public init(fileURL: URL? = URL(fileURLWithPath: RLMRealmPathForFile("default.realm"), isDirectory: false),
- inMemoryIdentifier: String? = nil,
- syncConfiguration: SyncConfiguration? = nil,
- encryptionKey: Data? = nil,
- readOnly: Bool = false,
- schemaVersion: UInt64 = 0,
- migrationBlock: MigrationBlock? = nil,
- deleteRealmIfMigrationNeeded: Bool = false,
- shouldCompactOnLaunch: ((Int, Int) -> Bool)? = nil,
- objectTypes: [Object.Type]? = nil) {
- self.fileURL = fileURL
- if let inMemoryIdentifier = inMemoryIdentifier {
- self.inMemoryIdentifier = inMemoryIdentifier
- }
- if let syncConfiguration = syncConfiguration {
- self.syncConfiguration = syncConfiguration
- }
- self.encryptionKey = encryptionKey
- self.readOnly = readOnly
- self.schemaVersion = schemaVersion
- self.migrationBlock = migrationBlock
- self.deleteRealmIfMigrationNeeded = deleteRealmIfMigrationNeeded
- self.shouldCompactOnLaunch = shouldCompactOnLaunch
- self.objectTypes = objectTypes
- }
- // MARK: Configuration Properties
- /**
- A configuration value used to configure a Realm for synchronization with the Realm Object Server. Mutually
- exclusive with `inMemoryIdentifier`.
- */
- public var syncConfiguration: SyncConfiguration? {
- get {
- return _syncConfiguration
- }
- set {
- _inMemoryIdentifier = nil
- _syncConfiguration = newValue
- }
- }
- private var _syncConfiguration: SyncConfiguration?
- /// The local URL of the Realm file. Mutually exclusive with `inMemoryIdentifier`.
- public var fileURL: URL? {
- get {
- return _path.map { URL(fileURLWithPath: $0) }
- }
- set {
- _inMemoryIdentifier = nil
- _path = newValue?.path
- }
- }
- private var _path: String?
- /// A string used to identify a particular in-memory Realm. Mutually exclusive with `fileURL` and
- /// `syncConfiguration`.
- public var inMemoryIdentifier: String? {
- get {
- return _inMemoryIdentifier
- }
- set {
- _path = nil
- _syncConfiguration = nil
- _inMemoryIdentifier = newValue
- }
- }
- private var _inMemoryIdentifier: String?
- /// A 64-byte key to use to encrypt the data, or `nil` if encryption is not enabled.
- public var encryptionKey: Data?
- /**
- Whether to open the Realm in read-only mode.
- For non-synchronized Realms, this is required to be able to open Realm files which are not
- writeable or are in a directory which is not writeable. This should only be used on files
- which will not be modified by anyone while they are open, and not just to get a read-only
- view of a file which may be written to by another thread or process. Opening in read-only
- mode requires disabling Realm's reader/writer coordination, so committing a write
- transaction from another process will result in crashes.
- Syncronized Realms must always be writeable (as otherwise no synchronization could happen),
- and this instead merely disallows performing write transactions on the Realm. In addition,
- it will skip some automatic writes made to the Realm, such as to initialize the Realm's
- schema. Setting `readOnly = YES` is not strictly required for Realms which the sync user
- does not have write access to, but is highly recommended as it will improve error reporting
- and catch some errors earlier.
- Realms using query-based sync cannot be opened in read-only mode.
- */
- public var readOnly: Bool = false
- /// The current schema version.
- public var schemaVersion: UInt64 = 0
- /// The block which migrates the Realm to the current version.
- public var migrationBlock: MigrationBlock?
- /**
- Whether to recreate the Realm file with the provided schema if a migration is required. This is the case when
- the stored schema differs from the provided schema or the stored schema version differs from the version on
- this configuration. Setting this property to `true` deletes the file if a migration would otherwise be required
- or executed.
- - note: Setting this property to `true` doesn't disable file format migrations.
- */
- public var deleteRealmIfMigrationNeeded: Bool = false
- /**
- A block called when opening a Realm for the first time during the
- life of a process to determine if it should be compacted before being
- returned to the user. It is passed the total file size (data + free space)
- and the total bytes used by data in the file.
- Return `true ` to indicate that an attempt to compact the file should be made.
- The compaction will be skipped if another process is accessing it.
- */
- public var shouldCompactOnLaunch: ((Int, Int) -> Bool)?
- /// The classes managed by the Realm.
- public var objectTypes: [Object.Type]? {
- get {
- return self.customSchema.map { $0.objectSchema.compactMap { $0.objectClass as? Object.Type } }
- }
- set {
- self.customSchema = newValue.map { RLMSchema(objectClasses: $0) }
- }
- }
- /**
- The maximum number of live versions in the Realm file before an exception will
- be thrown when attempting to start a write transaction.
- Realm provides MVCC snapshot isolation, meaning that writes on one thread do
- not overwrite data being read on another thread, and instead write a new copy
- of that data. When a Realm refreshes it updates to the latest version of the
- data and releases the old versions, allowing them to be overwritten by
- subsequent write transactions.
- Under normal circumstances this is not a problem, but if the number of active
- versions grow too large, it will have a negative effect on the filesize on
- disk. This can happen when performing writes on many different threads at
- once, when holding on to frozen objects for an extended time, or when
- performing long operations on background threads which do not allow the Realm
- to refresh.
- Setting this property to a non-zero value makes it so that exceeding the set
- number of versions will instead throw an exception. This can be used with a
- low value during development to help identify places that may be problematic,
- or in production use to cause the app to crash rather than produce a Realm
- file which is too large to be oened.
- */
- public var maximumNumberOfActiveVersions: UInt?
- /// A custom schema to use for the Realm.
- private var customSchema: RLMSchema?
- /// If `true`, disables automatic format upgrades when accessing the Realm.
- internal var disableFormatUpgrade: Bool = false
- // MARK: Private Methods
- internal var rlmConfiguration: RLMRealmConfiguration {
- let configuration = RLMRealmConfiguration()
- if let syncConfiguration = syncConfiguration {
- configuration.syncConfiguration = syncConfiguration.asConfig()
- }
- if let fileURL = fileURL {
- configuration.fileURL = fileURL
- } else if let inMemoryIdentifier = inMemoryIdentifier {
- configuration.inMemoryIdentifier = inMemoryIdentifier
- } else if syncConfiguration == nil {
- fatalError("A Realm Configuration must specify a path or an in-memory identifier.")
- }
- configuration.encryptionKey = self.encryptionKey
- configuration.readOnly = self.readOnly
- configuration.schemaVersion = self.schemaVersion
- configuration.migrationBlock = self.migrationBlock.map { accessorMigrationBlock($0) }
- configuration.deleteRealmIfMigrationNeeded = self.deleteRealmIfMigrationNeeded
- if let shouldCompactOnLaunch = self.shouldCompactOnLaunch {
- configuration.shouldCompactOnLaunch = ObjectiveCSupport.convert(object: shouldCompactOnLaunch)
- } else {
- configuration.shouldCompactOnLaunch = nil
- }
- configuration.setCustomSchemaWithoutCopying(self.customSchema)
- configuration.disableFormatUpgrade = self.disableFormatUpgrade
- configuration.maximumNumberOfActiveVersions = self.maximumNumberOfActiveVersions ?? 0
- return configuration
- }
- internal static func fromRLMRealmConfiguration(_ rlmConfiguration: RLMRealmConfiguration) -> Configuration {
- var configuration = Configuration()
- configuration._path = rlmConfiguration.fileURL?.path
- configuration._inMemoryIdentifier = rlmConfiguration.inMemoryIdentifier
- if let objcSyncConfig = rlmConfiguration.syncConfiguration {
- configuration._syncConfiguration = SyncConfiguration(config: objcSyncConfig)
- } else {
- configuration._syncConfiguration = nil
- }
- configuration.encryptionKey = rlmConfiguration.encryptionKey
- configuration.readOnly = rlmConfiguration.readOnly
- configuration.schemaVersion = rlmConfiguration.schemaVersion
- configuration.migrationBlock = rlmConfiguration.migrationBlock.map { rlmMigration in
- return { migration, schemaVersion in
- rlmMigration(migration.rlmMigration, schemaVersion)
- }
- }
- configuration.deleteRealmIfMigrationNeeded = rlmConfiguration.deleteRealmIfMigrationNeeded
- configuration.shouldCompactOnLaunch = rlmConfiguration.shouldCompactOnLaunch.map(ObjectiveCSupport.convert)
- configuration.customSchema = rlmConfiguration.customSchema
- configuration.disableFormatUpgrade = rlmConfiguration.disableFormatUpgrade
- configuration.maximumNumberOfActiveVersions = rlmConfiguration.maximumNumberOfActiveVersions
- return configuration
- }
- }
- }
- // MARK: CustomStringConvertible
- extension Realm.Configuration: CustomStringConvertible {
- /// A human-readable description of the configuration value.
- public var description: String {
- return gsub(pattern: "\\ARLMRealmConfiguration",
- template: "Realm.Configuration",
- string: rlmConfiguration.description) ?? ""
- }
- }
|