added iOS source code
[wl-app.git] / iOS / Pods / RealmSwift / RealmSwift / Object.swift
1 ////////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright 2014 Realm Inc.
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 // http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17 ////////////////////////////////////////////////////////////////////////////
18
19 import Foundation
20 import Realm
21 import Realm.Private
22
23 /**
24  `Object` is a class used to define Realm model objects.
25
26  In Realm you define your model classes by subclassing `Object` and adding properties to be managed.
27  You then instantiate and use your custom subclasses instead of using the `Object` class directly.
28
29  ```swift
30  class Dog: Object {
31      @objc dynamic var name: String = ""
32      @objc dynamic var adopted: Bool = false
33      let siblings = List<Dog>()
34  }
35  ```
36
37  ### Supported property types
38
39  - `String`, `NSString`
40  - `Int`
41  - `Int8`, `Int16`, `Int32`, `Int64`
42  - `Float`
43  - `Double`
44  - `Bool`
45  - `Date`, `NSDate`
46  - `Data`, `NSData`
47  - `RealmOptional<Value>` for optional numeric properties
48  - `Object` subclasses, to model many-to-one relationships
49  - `List<Element>`, to model many-to-many relationships
50
51  `String`, `NSString`, `Date`, `NSDate`, `Data`, `NSData` and `Object` subclass properties can be declared as optional.
52  `Int`, `Int8`, `Int16`, `Int32`, `Int64`, `Float`, `Double`, `Bool`, and `List` properties cannot. To store an optional
53  number, use `RealmOptional<Int>`, `RealmOptional<Float>`, `RealmOptional<Double>`, or `RealmOptional<Bool>` instead,
54  which wraps an optional numeric value.
55
56  All property types except for `List` and `RealmOptional` *must* be declared as `@objc dynamic var`. `List` and
57  `RealmOptional` properties must be declared as non-dynamic `let` properties. Swift `lazy` properties are not allowed.
58
59  Note that none of the restrictions listed above apply to properties that are configured to be ignored by Realm.
60
61  ### Querying
62
63  You can retrieve all objects of a given type from a Realm by calling the `objects(_:)` instance method.
64
65  ### Relationships
66
67  See our [Cocoa guide](http://realm.io/docs/cocoa) for more details.
68  */
69 @objc(RealmSwiftObject)
70 open class Object: RLMObjectBase, ThreadConfined, RealmCollectionValue {
71     /// :nodoc:
72     // swiftlint:disable:next identifier_name
73     public static func _rlmArray() -> RLMArray<AnyObject> {
74         return RLMArray(objectClassName: className())
75     }
76
77     // MARK: Initializers
78
79     /**
80      Creates an unmanaged instance of a Realm object.
81
82      Call `add(_:)` on a `Realm` instance to add an unmanaged object into that Realm.
83
84      - see: `Realm().add(_:)`
85      */
86     public override required init() {
87         super.init()
88     }
89
90     /**
91      Creates an unmanaged instance of a Realm object.
92
93      The `value` argument is used to populate the object. It can be a key-value coding compliant object, an array or
94      dictionary returned from the methods in `NSJSONSerialization`, or an `Array` containing one element for each
95      managed property. An exception will be thrown if any required properties are not present and those properties were
96      not defined with default values.
97
98      When passing in an `Array` as the `value` argument, all properties must be present, valid and in the same order as
99      the properties defined in the model.
100
101      Call `add(_:)` on a `Realm` instance to add an unmanaged object into that Realm.
102
103      - parameter value:  The value used to populate the object.
104      */
105     public init(value: Any) {
106         super.init(value: value, schema: .partialPrivateShared())
107     }
108
109
110     // MARK: Properties
111
112     /// The Realm which manages the object, or `nil` if the object is unmanaged.
113     public var realm: Realm? {
114         if let rlmReam = RLMObjectBaseRealm(self) {
115             return Realm(rlmReam)
116         }
117         return nil
118     }
119
120     /// The object schema which lists the managed properties for the object.
121     public var objectSchema: ObjectSchema {
122         return ObjectSchema(RLMObjectBaseObjectSchema(self)!)
123     }
124
125     /// Indicates if the object can no longer be accessed because it is now invalid.
126     ///
127     /// An object can no longer be accessed if the object has been deleted from the Realm that manages it, or if
128     /// `invalidate()` is called on that Realm.
129     public override final var isInvalidated: Bool { return super.isInvalidated }
130
131     /// A human-readable description of the object.
132     open override var description: String { return super.description }
133
134     /**
135      WARNING: This is an internal helper method not intended for public use.
136      It is not considered part of the public API.
137      :nodoc:
138      */
139     public override final class func objectUtilClass(_ isSwift: Bool) -> AnyClass {
140         return ObjectUtil.self
141     }
142
143
144     // MARK: Object Customization
145
146     /**
147      Override this method to specify the name of a property to be used as the primary key.
148
149      Only properties of types `String` and `Int` can be designated as the primary key. Primary key properties enforce
150      uniqueness for each value whenever the property is set, which incurs minor overhead. Indexes are created
151      automatically for primary key properties.
152
153      - returns: The name of the property designated as the primary key, or `nil` if the model has no primary key.
154      */
155     @objc open class func primaryKey() -> String? { return nil }
156
157     /**
158      Override this method to specify the names of properties to ignore. These properties will not be managed by
159      the Realm that manages the object.
160
161      - returns: An array of property names to ignore.
162      */
163     @objc open class func ignoredProperties() -> [String] { return [] }
164
165     /**
166      Returns an array of property names for properties which should be indexed.
167
168      Only string, integer, boolean, `Date`, and `NSDate` properties are supported.
169
170      - returns: An array of property names.
171      */
172     @objc open class func indexedProperties() -> [String] { return [] }
173
174     // MARK: Key-Value Coding & Subscripting
175
176     /// Returns or sets the value of the property with the given name.
177     @objc open subscript(key: String) -> Any? {
178         get {
179             if realm == nil {
180                 return value(forKey: key)
181             }
182             return RLMDynamicGetByName(self, key, true)
183         }
184         set(value) {
185             if realm == nil {
186                 setValue(value, forKey: key)
187             } else {
188                 RLMDynamicValidatedSet(self, key, value)
189             }
190         }
191     }
192
193     // MARK: Notifications
194
195     /**
196      Registers a block to be called each time the object changes.
197
198      The block will be asynchronously called after each write transaction which
199      deletes the object or modifies any of the managed properties of the object,
200      including self-assignments that set a property to its existing value.
201
202      For write transactions performed on different threads or in different
203      processes, the block will be called when the managing Realm is
204      (auto)refreshed to a version including the changes, while for local write
205      transactions it will be called at some point in the future after the write
206      transaction is committed.
207
208      Notifications are delivered via the standard run loop, and so can't be
209      delivered while the run loop is blocked by other activity. When
210      notifications can't be delivered instantly, multiple notifications may be
211      coalesced into a single notification.
212
213      Unlike with `List` and `Results`, there is no "initial" callback made after
214      you add a new notification block.
215
216      Only objects which are managed by a Realm can be observed in this way. You
217      must retain the returned token for as long as you want updates to be sent
218      to the block. To stop receiving updates, call `invalidate()` on the token.
219
220      It is safe to capture a strong reference to the observed object within the
221      callback block. There is no retain cycle due to that the callback is
222      retained by the returned token and not by the object itself.
223
224      - warning: This method cannot be called during a write transaction, or when
225                 the containing Realm is read-only.
226
227      - parameter block: The block to call with information about changes to the object.
228      - returns: A token which must be held for as long as you want updates to be delivered.
229      */
230     public func observe(_ block: @escaping (ObjectChange) -> Void) -> NotificationToken {
231         return RLMObjectAddNotificationBlock(self, { names, oldValues, newValues, error in
232             if let error = error {
233                 block(.error(error as NSError))
234                 return
235             }
236             guard let names = names, let newValues = newValues else {
237                 block(.deleted)
238                 return
239             }
240
241             block(.change((0..<newValues.count).map { i in
242                 PropertyChange(name: names[i], oldValue: oldValues?[i], newValue: newValues[i])
243             }))
244         })
245     }
246
247     // MARK: Dynamic list
248
249     /**
250      Returns a list of `DynamicObject`s for a given property name.
251
252      - warning:  This method is useful only in specialized circumstances, for example, when building
253      components that integrate with Realm. If you are simply building an app on Realm, it is
254      recommended to use instance variables or cast the values returned from key-value coding.
255
256      - parameter propertyName: The name of the property.
257
258      - returns: A list of `DynamicObject`s.
259
260      :nodoc:
261      */
262     public func dynamicList(_ propertyName: String) -> List<DynamicObject> {
263         return noWarnUnsafeBitCast(RLMDynamicGetByName(self, propertyName, true) as! RLMListBase,
264                                    to: List<DynamicObject>.self)
265     }
266
267     // MARK: Comparison
268     /**
269      Returns whether two Realm objects are the same.
270
271      Objects are considered the same if and only if they are both managed by the same
272      Realm and point to the same underlying object in the database.
273      
274      - note: Equality comparison is implemented by `isEqual(_:)`. If the object type
275              is defined with a primary key, `isEqual(_:)` behaves identically to this
276              method. If the object type is not defined with a primary key,
277              `isEqual(_:)` uses the `NSObject` behavior of comparing object identity.
278              This method can be used to compare two objects for database equality
279              whether or not their object type defines a primary key.
280
281      - parameter object: The object to compare the receiver to.
282      */
283     public func isSameObject(as object: Object?) -> Bool {
284         return RLMObjectBaseAreEqual(self, object)
285     }
286
287     // MARK: Private functions
288
289     // FIXME: None of these functions should be exposed in the public interface.
290
291     /**
292     WARNING: This is an internal initializer not intended for public use.
293     :nodoc:
294     */
295     public override required init(realm: RLMRealm, schema: RLMObjectSchema) {
296         super.init(realm: realm, schema: schema)
297     }
298
299     /**
300     WARNING: This is an internal initializer not intended for public use.
301     :nodoc:
302     */
303     public override required init(value: Any, schema: RLMSchema) {
304         super.init(value: value, schema: schema)
305     }
306 }
307
308 /**
309  Information about a specific property which changed in an `Object` change notification.
310  */
311 public struct PropertyChange {
312     /**
313      The name of the property which changed.
314     */
315     public let name: String
316
317     /**
318      Value of the property before the change occurred. This is not supplied if
319      the change happened on the same thread as the notification and for `List`
320      properties.
321
322      For object properties this will give the object which was previously
323      linked to, but that object will have its new values and not the values it
324      had before the changes. This means that `previousValue` may be a deleted
325      object, and you will need to check `isInvalidated` before accessing any
326      of its properties.
327     */
328     public let oldValue: Any?
329
330     /**
331      The value of the property after the change occurred. This is not supplied
332      for `List` properties and will always be nil.
333     */
334     public let newValue: Any?
335 }
336
337 /**
338  Information about the changes made to an object which is passed to `Object`'s
339  notification blocks.
340  */
341 public enum ObjectChange {
342     /**
343      If an error occurs, notification blocks are called one time with a `.error`
344      result and an `NSError` containing details about the error. Currently the
345      only errors which can occur are when opening the Realm on a background
346      worker thread to calculate the change set. The callback will never be
347      called again after `.error` is delivered.
348      */
349     case error(_: NSError)
350     /**
351      One or more of the properties of the object have been changed.
352      */
353     case change(_: [PropertyChange])
354     /// The object has been deleted from the Realm.
355     case deleted
356 }
357
358 /// Object interface which allows untyped getters and setters for Objects.
359 /// :nodoc:
360 public final class DynamicObject: Object {
361     public override subscript(key: String) -> Any? {
362         get {
363             let value = RLMDynamicGetByName(self, key, false)
364             if let array = value as? RLMArray<AnyObject> {
365                 return List<DynamicObject>(rlmArray: array)
366             }
367             return value
368         }
369         set(value) {
370             RLMDynamicValidatedSet(self, key, value)
371         }
372     }
373
374     /// :nodoc:
375     public override func value(forUndefinedKey key: String) -> Any? {
376         return self[key]
377     }
378
379     /// :nodoc:
380     public override func setValue(_ value: Any?, forUndefinedKey key: String) {
381         self[key] = value
382     }
383
384     /// :nodoc:
385     public override class func shouldIncludeInDefaultSchema() -> Bool {
386         return false
387     }
388 }
389
390 /// :nodoc:
391 /// Internal class. Do not use directly.
392 @objc(RealmSwiftObjectUtil)
393 public class ObjectUtil: NSObject {
394     @objc private class func swiftVersion() -> NSString {
395         return swiftLanguageVersion as NSString
396     }
397
398     @objc private class func ignoredPropertiesForClass(_ type: AnyClass) -> NSArray? {
399         if let type = type as? Object.Type {
400             return type.ignoredProperties() as NSArray?
401         }
402         return nil
403     }
404
405     @objc private class func indexedPropertiesForClass(_ type: AnyClass) -> NSArray? {
406         if let type = type as? Object.Type {
407             return type.indexedProperties() as NSArray?
408         }
409         return nil
410     }
411
412     @objc private class func linkingObjectsPropertiesForClass(_ type: AnyClass) -> NSDictionary? {
413         // Not used for Swift. getLinkingObjectsProperties(_:) is used instead.
414         return nil
415     }
416
417     // If the property is a storage property for a lazy Swift property, return
418     // the base property name (e.g. `foo.storage` becomes `foo`). Otherwise, nil.
419     private static func baseName(forLazySwiftProperty name: String) -> String? {
420         // A Swift lazy var shows up as two separate children on the reflection tree:
421         // one named 'x', and another that is optional and is named 'x.storage'. Note
422         // that '.' is illegal in either a Swift or Objective-C property name.
423         if let storageRange = name.range(of: ".storage", options: [.anchored, .backwards]) {
424             #if swift(>=4.0)
425                 return String(name[..<storageRange.lowerBound])
426             #else
427                 return name.substring(to: storageRange.lowerBound)
428             #endif
429         }
430         return nil
431     }
432
433     // Reflect an object, returning only children representing managed Realm properties.
434     private static func getNonIgnoredMirrorChildren(for object: Any) -> [Mirror.Child] {
435         let ignoredPropNames: Set<String>
436         if let realmObject = object as? Object {
437             ignoredPropNames = Set(type(of: realmObject).ignoredProperties())
438         } else {
439             ignoredPropNames = Set()
440         }
441         // No HKT in Swift, unfortunately
442         return Mirror(reflecting: object).children.filter { (prop: Mirror.Child) -> Bool in
443             guard let label = prop.label else {
444                 return false
445             }
446             if ignoredPropNames.contains(label) {
447                 // Ignored property.
448                 return false
449             }
450             if let lazyBaseName = baseName(forLazySwiftProperty: label) {
451                 if ignoredPropNames.contains(lazyBaseName) {
452                     // Ignored lazy property.
453                     return false
454                 }
455                 // Managed lazy property; not currently supported.
456                 // FIXME: revisit this once Swift gets property behaviors/property macros.
457                 throwRealmException("Lazy managed property '\(lazyBaseName)' is not allowed on a Realm Swift object"
458                     + " class. Either add the property to the ignored properties list or make it non-lazy.")
459             }
460             return true
461         }
462     }
463
464     // Build optional property metadata for a given property.
465     // swiftlint:disable:next cyclomatic_complexity
466     private static func getOptionalPropertyMetadata(for child: Mirror.Child, at index: Int) -> RLMSwiftPropertyMetadata? {
467         guard let name = child.label else {
468             return nil
469         }
470         let mirror = Mirror(reflecting: child.value)
471         let type = mirror.subjectType
472         let code: PropertyType
473         if type is Optional<String>.Type || type is Optional<NSString>.Type {
474             code = .string
475         } else if type is Optional<Date>.Type {
476             code = .date
477         } else if type is Optional<Data>.Type {
478             code = .data
479         } else if type is Optional<Object>.Type {
480             code = .object
481         } else if type is RealmOptional<Int>.Type ||
482             type is RealmOptional<Int8>.Type ||
483             type is RealmOptional<Int16>.Type ||
484             type is RealmOptional<Int32>.Type ||
485             type is RealmOptional<Int64>.Type {
486             code = .int
487         } else if type is RealmOptional<Float>.Type {
488             code = .float
489         } else if type is RealmOptional<Double>.Type {
490             code = .double
491         } else if type is RealmOptional<Bool>.Type {
492             code = .bool
493         } else if child.value is RLMOptionalBase {
494             throwRealmException("'\(type)' is not a valid RealmOptional type.")
495             code = .int // ignored
496         } else if mirror.displayStyle == .optional || type is ExpressibleByNilLiteral.Type {
497             return RLMSwiftPropertyMetadata(forNilLiteralOptionalProperty: name)
498         } else {
499             return nil
500         }
501         return RLMSwiftPropertyMetadata(forOptionalProperty: name, type: code)
502     }
503
504     @objc private class func getSwiftProperties(_ object: Any) -> [RLMSwiftPropertyMetadata] {
505         return getNonIgnoredMirrorChildren(for: object).enumerated().flatMap { idx, prop in
506             if let value = prop.value as? LinkingObjectsBase {
507                 return RLMSwiftPropertyMetadata(forLinkingObjectsProperty: prop.label!,
508                                                 className: value.objectClassName,
509                                                 linkedPropertyName: value.propertyName)
510             } else if prop.value is RLMListBase {
511                 return RLMSwiftPropertyMetadata(forListProperty: prop.label!)
512             } else if let optional = getOptionalPropertyMetadata(for: prop, at: idx) {
513                 return optional
514             } else {
515                 return RLMSwiftPropertyMetadata(forOtherProperty: prop.label!)
516             }
517         }
518     }
519
520     @objc private class func requiredPropertiesForClass(_: Any) -> [String] {
521         return []
522     }
523 }
524
525 // MARK: AssistedObjectiveCBridgeable
526
527 // FIXME: Remove when `as! Self` can be written
528 private func forceCastToInferred<T, V>(_ x: T) -> V {
529     return x as! V
530 }
531
532 extension Object: AssistedObjectiveCBridgeable {
533     static func bridging(from objectiveCValue: Any, with metadata: Any?) -> Self {
534         return forceCastToInferred(objectiveCValue)
535     }
536
537     var bridged: (objectiveCValue: Any, metadata: Any?) {
538         return (objectiveCValue: unsafeCastToRLMObject(), metadata: nil)
539     }
540 }
541
542 // MARK: - Migration assistance
543
544 extension Object {
545     /// :nodoc:
546     @available(*, unavailable, renamed: "observe()")
547     public func addNotificationBlock(_ block: @escaping (ObjectChange) -> Void) -> NotificationToken {
548         fatalError()
549     }
550
551 #if os(OSX)
552 #else
553     /// :nodoc:
554     @available(*, unavailable, renamed: "isSameObject(as:)") public func isEqual(to object: Any?) -> Bool {
555         fatalError()
556     }
557 #endif
558 }