1 ////////////////////////////////////////////////////////////////////////////
3 // Copyright 2014 Realm Inc.
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
9 // http://www.apache.org/licenses/LICENSE-2.0
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.
17 ////////////////////////////////////////////////////////////////////////////
23 An iterator for a `RealmCollection` instance.
25 public struct RLMIterator<Element: RealmCollectionValue>: IteratorProtocol {
26 private var generatorBase: NSFastEnumerationIterator
28 init(collection: RLMCollection) {
29 generatorBase = NSFastEnumerationIterator(collection)
32 /// Advance to the next element and return it, or `nil` if no next element exists.
33 public mutating func next() -> Element? {
34 let next = generatorBase.next()
35 if let next = next as? Object? {
37 return nil as Element?
39 return unsafeBitCast(next, to: Optional<Element>.self)
41 return next as! Element?
46 A `RealmCollectionChange` value encapsulates information about changes to collections
47 that are reported by Realm notifications.
49 The change information is available in two formats: a simple array of row
50 indices in the collection for each type of change, and an array of index paths
51 in a requested section suitable for passing directly to `UITableView`'s batch
54 The arrays of indices in the `.update` case follow `UITableView`'s batching
55 conventions, and can be passed as-is to a table view's batch update functions after being converted to index paths.
56 For example, for a simple one-section table view, you can do the following:
59 self.notificationToken = results.observe { changes in
62 // Results are now populated and can be accessed without blocking the UI
63 self.tableView.reloadData()
65 case .update(_, let deletions, let insertions, let modifications):
66 // Query results have changed, so apply them to the TableView
67 self.tableView.beginUpdates()
68 self.tableView.insertRows(at: insertions.map { IndexPath(row: $0, section: 0) },
70 self.tableView.deleteRows(at: deletions.map { IndexPath(row: $0, section: 0) },
72 self.tableView.reloadRows(at: modifications.map { IndexPath(row: $0, section: 0) },
74 self.tableView.endUpdates()
77 // An error occurred while opening the Realm file on the background worker thread
84 public enum RealmCollectionChange<CollectionType> {
86 `.initial` indicates that the initial run of the query has completed (if
87 applicable), and the collection can now be used without performing any
90 case initial(CollectionType)
93 `.update` indicates that a write transaction has been committed which
94 either changed which objects are in the collection, and/or modified one
95 or more of the objects in the collection.
97 All three of the change arrays are always sorted in ascending order.
99 - parameter deletions: The indices in the previous version of the collection which were removed from this one.
100 - parameter insertions: The indices in the new collection which were added in this version.
101 - parameter modifications: The indices of the objects in the new collection which were modified in this version.
103 case update(CollectionType, deletions: [Int], insertions: [Int], modifications: [Int])
106 If an error occurs, notification blocks are called one time with a `.error`
107 result and an `NSError` containing details about the error. This can only
108 currently happen if opening the Realm on a background thread to calcuate
109 the change set fails. The callback will never be called again after it is
110 invoked with a .error value.
114 static func fromObjc(value: CollectionType, change: RLMCollectionChange?, error: Error?) -> RealmCollectionChange {
115 if let error = error {
118 if let change = change {
119 return .update(value,
120 deletions: forceCast(change.deletions, to: [Int].self),
121 insertions: forceCast(change.insertions, to: [Int].self),
122 modifications: forceCast(change.modifications, to: [Int].self))
124 return .initial(value)
128 private func forceCast<A, U>(_ from: A, to type: U.Type) -> U {
132 /// A type which can be stored in a Realm List or Results
133 public protocol RealmCollectionValue {
135 // swiftlint:disable:next identifier_name
136 static func _rlmArray() -> RLMArray<AnyObject>
139 extension RealmCollectionValue {
141 // swiftlint:disable:next identifier_name
142 public static func _rlmArray() -> RLMArray<AnyObject> {
143 return RLMArray(objectType: .int, optional: false)
147 extension Optional: RealmCollectionValue {
149 // swiftlint:disable:next identifier_name
150 public static func _rlmArray() -> RLMArray<AnyObject> {
151 switch Wrapped.self {
152 case is Int.Type, is Int8.Type, is Int16.Type, is Int32.Type, is Int64.Type:
153 return RLMArray(objectType: .int, optional: true)
154 case is Bool.Type: return RLMArray(objectType: .bool, optional: true)
155 case is Float.Type: return RLMArray(objectType: .float, optional: true)
156 case is Double.Type: return RLMArray(objectType: .double, optional: true)
157 case is String.Type: return RLMArray(objectType: .string, optional: true)
158 case is Data.Type: return RLMArray(objectType: .data, optional: true)
159 case is Date.Type: return RLMArray(objectType: .date, optional: true)
160 default: fatalError("Unsupported type for List: \(Wrapped.self)?")
165 extension Int: RealmCollectionValue {}
166 extension Int8: RealmCollectionValue {}
167 extension Int16: RealmCollectionValue {}
168 extension Int32: RealmCollectionValue {}
169 extension Int64: RealmCollectionValue {}
170 extension Float: RealmCollectionValue {
172 // swiftlint:disable:next identifier_name
173 public static func _rlmArray() -> RLMArray<AnyObject> {
174 return RLMArray(objectType: .float, optional: false)
177 extension Double: RealmCollectionValue {
179 // swiftlint:disable:next identifier_name
180 public static func _rlmArray() -> RLMArray<AnyObject> {
181 return RLMArray(objectType: .double, optional: false)
184 extension Bool: RealmCollectionValue {
186 // swiftlint:disable:next identifier_name
187 public static func _rlmArray() -> RLMArray<AnyObject> {
188 return RLMArray(objectType: .bool, optional: false)
192 extension String: RealmCollectionValue {
194 // swiftlint:disable:next identifier_name
195 public static func _rlmArray() -> RLMArray<AnyObject> {
196 return RLMArray(objectType: .string, optional: false)
199 extension Date: RealmCollectionValue {
201 // swiftlint:disable:next identifier_name
202 public static func _rlmArray() -> RLMArray<AnyObject> {
203 return RLMArray(objectType: .date, optional: false)
206 extension Data: RealmCollectionValue {
208 // swiftlint:disable:next identifier_name
209 public static func _rlmArray() -> RLMArray<AnyObject> {
210 return RLMArray(objectType: .data, optional: false)
215 // FIXME: When we drop support for Swift 3.1, change ElementType to Element
216 // throughout the project (this is a non-breaking change). We use ElementType
217 // only because of limitations in Swift 3.1's compiler.
219 public protocol RealmCollectionBase: RandomAccessCollection, LazyCollectionProtocol, CustomStringConvertible, ThreadConfined where Element: RealmCollectionValue {
220 typealias ElementType = Element
224 public protocol RealmCollectionBase: RandomAccessCollection, LazyCollectionProtocol, CustomStringConvertible, ThreadConfined {
225 /// The type of the objects contained in the collection.
226 associatedtype ElementType: RealmCollectionValue
231 A homogenous collection of `Object`s which can be retrieved, filtered, sorted, and operated upon.
233 public protocol RealmCollection: RealmCollectionBase {
234 // Must also conform to `AssistedObjectiveCBridgeable`
238 /// The Realm which manages the collection, or `nil` for unmanaged collections.
239 var realm: Realm? { get }
242 Indicates if the collection can no longer be accessed.
244 The collection can no longer be accessed if `invalidate()` is called on the `Realm` that manages the collection.
246 var isInvalidated: Bool { get }
248 /// The number of objects in the collection.
249 var count: Int { get }
251 /// A human-readable description of the objects contained in the collection.
252 var description: String { get }
255 // MARK: Index Retrieval
258 Returns the index of an object in the collection, or `nil` if the object is not present.
260 - parameter object: An object.
262 func index(of object: ElementType) -> Int?
265 Returns the index of the first object matching the predicate, or `nil` if no objects match.
267 - parameter predicate: The predicate to use to filter the objects.
269 func index(matching predicate: NSPredicate) -> Int?
272 Returns the index of the first object matching the predicate, or `nil` if no objects match.
274 - parameter predicateFormat: A predicate format string, optionally followed by a variable number of arguments.
276 func index(matching predicateFormat: String, _ args: Any...) -> Int?
282 Returns a `Results` containing all objects matching the given predicate in the collection.
284 - parameter predicateFormat: A predicate format string, optionally followed by a variable number of arguments.
286 func filter(_ predicateFormat: String, _ args: Any...) -> Results<ElementType>
289 Returns a `Results` containing all objects matching the given predicate in the collection.
291 - parameter predicate: The predicate to use to filter the objects.
293 func filter(_ predicate: NSPredicate) -> Results<ElementType>
299 Returns a `Results` containing the objects in the collection, but sorted.
301 Objects are sorted based on the values of the given key path. For example, to sort a collection of `Student`s from
302 youngest to oldest based on their `age` property, you might call
303 `students.sorted(byKeyPath: "age", ascending: true)`.
305 - warning: Collections may only be sorted by properties of boolean, `Date`, `NSDate`, single and double-precision
306 floating point, integer, and string types.
308 - parameter keyPath: The key path to sort by.
309 - parameter ascending: The direction to sort in.
311 func sorted(byKeyPath keyPath: String, ascending: Bool) -> Results<ElementType>
314 Returns a `Results` containing the objects in the collection, but sorted.
316 - warning: Collections may only be sorted by properties of boolean, `Date`, `NSDate`, single and double-precision
317 floating point, integer, and string types.
319 - see: `sorted(byKeyPath:ascending:)`
321 - parameter sortDescriptors: A sequence of `SortDescriptor`s to sort by.
323 func sorted<S: Sequence>(by sortDescriptors: S) -> Results<ElementType> where S.Iterator.Element == SortDescriptor
325 // MARK: Aggregate Operations
328 Returns the minimum (lowest) value of the given property among all the objects in the collection, or `nil` if the
331 - warning: Only a property whose type conforms to the `MinMaxType` protocol can be specified.
333 - parameter property: The name of a property whose minimum value is desired.
335 func min<T: MinMaxType>(ofProperty property: String) -> T?
338 Returns the maximum (highest) value of the given property among all the objects in the collection, or `nil` if the
341 - warning: Only a property whose type conforms to the `MinMaxType` protocol can be specified.
343 - parameter property: The name of a property whose minimum value is desired.
345 func max<T: MinMaxType>(ofProperty property: String) -> T?
348 Returns the sum of the given property for objects in the collection, or `nil` if the collection is empty.
350 - warning: Only names of properties of a type conforming to the `AddableType` protocol can be used.
352 - parameter property: The name of a property conforming to `AddableType` to calculate sum on.
354 func sum<T: AddableType>(ofProperty property: String) -> T
357 Returns the average value of a given property over all the objects in the collection, or `nil` if
358 the collection is empty.
360 - warning: Only a property whose type conforms to the `AddableType` protocol can be specified.
362 - parameter property: The name of a property whose values should be summed.
364 func average(ofProperty property: String) -> Double?
367 // MARK: Key-Value Coding
370 Returns an `Array` containing the results of invoking `valueForKey(_:)` with `key` on each of the collection's
373 - parameter key: The name of the property whose values are desired.
375 func value(forKey key: String) -> Any?
378 Returns an `Array` containing the results of invoking `valueForKeyPath(_:)` with `keyPath` on each of the
379 collection's objects.
381 - parameter keyPath: The key path to the property whose values are desired.
383 func value(forKeyPath keyPath: String) -> Any?
386 Invokes `setValue(_:forKey:)` on each of the collection's objects using the specified `value` and `key`.
388 - warning: This method may only be called during a write transaction.
390 - parameter value: The object value.
391 - parameter key: The name of the property whose value should be set on each object.
393 func setValue(_ value: Any?, forKey key: String)
395 // MARK: Notifications
398 Registers a block to be called each time the collection changes.
400 The block will be asynchronously called with the initial results, and then called again after each write
401 transaction which changes either any of the objects in the collection, or which objects are in the collection.
403 The `change` parameter that is passed to the block reports, in the form of indices within the collection, which of
404 the objects were added, removed, or modified during each write transaction. See the `RealmCollectionChange`
405 documentation for more information on the change information supplied and an example of how to use it to update a
408 At the time when the block is called, the collection will be fully evaluated and up-to-date, and as long as you do
409 not perform a write transaction on the same thread or explicitly call `realm.refresh()`, accessing it will never
410 perform blocking work.
412 Notifications are delivered via the standard run loop, and so can't be delivered while the run loop is blocked by
413 other activity. When notifications can't be delivered instantly, multiple notifications may be coalesced into a
414 single notification. This can include the notification with the initial collection.
416 For example, the following code performs a write transaction immediately after adding the notification block, so
417 there is no opportunity for the initial notification to be delivered first. As a result, the initial notification
418 will reflect the state of the Realm after the write transaction.
421 let results = realm.objects(Dog.self)
422 print("dogs.count: \(dogs?.count)") // => 0
423 let token = dogs.observe { changes in
425 case .initial(let dogs):
426 // Will print "dogs.count: 1"
427 print("dogs.count: \(dogs.count)")
430 // Will not be hit in this example
439 person.dogs.append(dog)
441 // end of run loop execution context
444 You must retain the returned token for as long as you want updates to be sent to the block. To stop receiving
445 updates, call `invalidate()` on the token.
447 - warning: This method cannot be called during a write transaction, or when the containing Realm is read-only.
449 - parameter block: The block to be called whenever a change occurs.
450 - returns: A token which must be held for as long as you want updates to be delivered.
452 func observe(_ block: @escaping (RealmCollectionChange<Self>) -> Void) -> NotificationToken
455 func _observe(_ block: @escaping (RealmCollectionChange<AnyRealmCollection<ElementType>>) -> Void) -> NotificationToken
459 public protocol OptionalProtocol {
460 associatedtype Wrapped
462 // swiftlint:disable:next identifier_name
463 func _rlmInferWrappedType() -> Wrapped
466 extension Optional: OptionalProtocol {
468 // swiftlint:disable:next identifier_name
469 public func _rlmInferWrappedType() -> Wrapped { return self! }
473 // FIXME: See the declaration of RealmCollectionBase for why this `#if` is required.
475 public extension RealmCollection where Element: MinMaxType {
477 Returns the minimum (lowest) value of the collection, or `nil` if the collection is empty.
479 public func min() -> Element? {
480 return min(ofProperty: "self")
483 Returns the maximum (highest) value of the collection, or `nil` if the collection is empty.
485 public func max() -> Element? {
486 return max(ofProperty: "self")
490 public extension RealmCollection where Element: OptionalProtocol, Element.Wrapped: MinMaxType {
492 Returns the minimum (lowest) value of the collection, or `nil` if the collection is empty.
494 public func min() -> Element.Wrapped? {
495 return min(ofProperty: "self")
498 Returns the maximum (highest) value of the collection, or `nil` if the collection is empty.
500 public func max() -> Element.Wrapped? {
501 return max(ofProperty: "self")
505 public extension RealmCollection where Element: AddableType {
507 Returns the sum of the values in the collection, or `nil` if the collection is empty.
509 public func sum() -> Element {
510 return sum(ofProperty: "self")
513 Returns the average of all of the values in the collection.
515 public func average() -> Double? {
516 return average(ofProperty: "self")
520 public extension RealmCollection where Element: OptionalProtocol, Element.Wrapped: AddableType {
522 Returns the sum of the values in the collection, or `nil` if the collection is empty.
524 public func sum() -> Element.Wrapped {
525 return sum(ofProperty: "self")
528 Returns the average of all of the values in the collection.
530 public func average() -> Double? {
531 return average(ofProperty: "self")
535 public extension RealmCollection where Element: Comparable {
537 Returns a `Results` containing the objects in the collection, but sorted.
539 Objects are sorted based on their values. For example, to sort a collection of `Date`s from
540 neweset to oldest based, you might call `dates.sorted(ascending: true)`.
542 - parameter ascending: The direction to sort in.
544 public func sorted(ascending: Bool = true) -> Results<Element> {
545 return sorted(byKeyPath: "self", ascending: ascending)
549 public extension RealmCollection where Element: OptionalProtocol, Element.Wrapped: Comparable {
551 Returns a `Results` containing the objects in the collection, but sorted.
553 Objects are sorted based on their values. For example, to sort a collection of `Date`s from
554 neweset to oldest based, you might call `dates.sorted(ascending: true)`.
556 - parameter ascending: The direction to sort in.
558 public func sorted(ascending: Bool = true) -> Results<Element> {
559 return sorted(byKeyPath: "self", ascending: ascending)
563 public extension RealmCollection where ElementType: MinMaxType {
565 Returns the minimum (lowest) value of the collection, or `nil` if the collection is empty.
567 public func min() -> ElementType? {
568 return min(ofProperty: "self")
571 Returns the maximum (highest) value of the collection, or `nil` if the collection is empty.
573 public func max() -> ElementType? {
574 return max(ofProperty: "self")
578 public extension RealmCollection where ElementType: OptionalProtocol, ElementType.Wrapped: MinMaxType {
580 Returns the minimum (lowest) value of the collection, or `nil` if the collection is empty.
582 public func min() -> ElementType.Wrapped? {
583 return min(ofProperty: "self")
586 Returns the maximum (highest) value of the collection, or `nil` if the collection is empty.
588 public func max() -> ElementType.Wrapped? {
589 return max(ofProperty: "self")
593 public extension RealmCollection where ElementType: AddableType {
595 Returns the sum of the values in the collection, or `nil` if the collection is empty.
597 public func sum() -> ElementType {
598 return sum(ofProperty: "self")
601 Returns the average of all of the values in the collection.
603 public func average() -> Double? {
604 return average(ofProperty: "self")
608 public extension RealmCollection where ElementType: OptionalProtocol, ElementType.Wrapped: AddableType {
610 Returns the sum of the values in the collection, or `nil` if the collection is empty.
612 public func sum() -> ElementType.Wrapped {
613 return sum(ofProperty: "self")
616 Returns the average of all of the values in the collection.
618 public func average() -> Double? {
619 return average(ofProperty: "self")
623 public extension RealmCollection where ElementType: Comparable {
625 Returns a `Results` containing the objects in the collection, but sorted.
627 Objects are sorted based on their values. For example, to sort a collection of `Date`s from
628 neweset to oldest based, you might call `dates.sorted(ascending: true)`.
630 - parameter ascending: The direction to sort in.
632 public func sorted(ascending: Bool = true) -> Results<ElementType> {
633 return sorted(byKeyPath: "self", ascending: ascending)
637 public extension RealmCollection where ElementType: OptionalProtocol, ElementType.Wrapped: Comparable {
639 Returns a `Results` containing the objects in the collection, but sorted.
641 Objects are sorted based on their values. For example, to sort a collection of `Date`s from
642 neweset to oldest based, you might call `dates.sorted(ascending: true)`.
644 - parameter ascending: The direction to sort in.
646 public func sorted(ascending: Bool = true) -> Results<ElementType> {
647 return sorted(byKeyPath: "self", ascending: ascending)
652 private class _AnyRealmCollectionBase<T: RealmCollectionValue>: AssistedObjectiveCBridgeable {
653 typealias Wrapper = AnyRealmCollection<Element>
654 typealias Element = T
655 var realm: Realm? { fatalError() }
656 var isInvalidated: Bool { fatalError() }
657 var count: Int { fatalError() }
658 var description: String { fatalError() }
659 func index(of object: Element) -> Int? { fatalError() }
660 func index(matching predicate: NSPredicate) -> Int? { fatalError() }
661 func index(matching predicateFormat: String, _ args: Any...) -> Int? { fatalError() }
662 func filter(_ predicateFormat: String, _ args: Any...) -> Results<Element> { fatalError() }
663 func filter(_ predicate: NSPredicate) -> Results<Element> { fatalError() }
664 func sorted(byKeyPath keyPath: String, ascending: Bool) -> Results<Element> { fatalError() }
665 func sorted<S: Sequence>(by sortDescriptors: S) -> Results<Element> where S.Iterator.Element == SortDescriptor {
668 func min<T: MinMaxType>(ofProperty property: String) -> T? { fatalError() }
669 func max<T: MinMaxType>(ofProperty property: String) -> T? { fatalError() }
670 func sum<T: AddableType>(ofProperty property: String) -> T { fatalError() }
671 func average(ofProperty property: String) -> Double? { fatalError() }
672 subscript(position: Int) -> Element { fatalError() }
673 func makeIterator() -> RLMIterator<T> { fatalError() }
674 var startIndex: Int { fatalError() }
675 var endIndex: Int { fatalError() }
676 func value(forKey key: String) -> Any? { fatalError() }
677 func value(forKeyPath keyPath: String) -> Any? { fatalError() }
678 func setValue(_ value: Any?, forKey key: String) { fatalError() }
679 func _observe(_ block: @escaping (RealmCollectionChange<Wrapper>) -> Void)
680 -> NotificationToken { fatalError() }
681 class func bridging(from objectiveCValue: Any, with metadata: Any?) -> Self { fatalError() }
682 var bridged: (objectiveCValue: Any, metadata: Any?) { fatalError() }
685 private final class _AnyRealmCollection<C: RealmCollection>: _AnyRealmCollectionBase<C.ElementType> {
693 override var realm: Realm? { return base.realm }
694 override var isInvalidated: Bool { return base.isInvalidated }
695 override var count: Int { return base.count }
696 override var description: String { return base.description }
699 // MARK: Index Retrieval
701 override func index(of object: C.ElementType) -> Int? { return base.index(of: object) }
703 override func index(matching predicate: NSPredicate) -> Int? { return base.index(matching: predicate) }
705 override func index(matching predicateFormat: String, _ args: Any...) -> Int? {
706 return base.index(matching: NSPredicate(format: predicateFormat, argumentArray: unwrapOptionals(in: args)))
711 override func filter(_ predicateFormat: String, _ args: Any...) -> Results<C.ElementType> {
712 return base.filter(NSPredicate(format: predicateFormat, argumentArray: unwrapOptionals(in: args)))
715 override func filter(_ predicate: NSPredicate) -> Results<C.ElementType> { return base.filter(predicate) }
719 override func sorted(byKeyPath keyPath: String, ascending: Bool) -> Results<C.ElementType> {
720 return base.sorted(byKeyPath: keyPath, ascending: ascending)
723 override func sorted<S: Sequence>
724 (by sortDescriptors: S) -> Results<C.ElementType> where S.Iterator.Element == SortDescriptor {
725 return base.sorted(by: sortDescriptors)
729 // MARK: Aggregate Operations
731 override func min<T: MinMaxType>(ofProperty property: String) -> T? {
732 return base.min(ofProperty: property)
735 override func max<T: MinMaxType>(ofProperty property: String) -> T? {
736 return base.max(ofProperty: property)
739 override func sum<T: AddableType>(ofProperty property: String) -> T {
740 return base.sum(ofProperty: property)
743 override func average(ofProperty property: String) -> Double? {
744 return base.average(ofProperty: property)
748 // MARK: Sequence Support
750 override subscript(position: Int) -> C.ElementType {
752 return base[position as! C.Index]
754 return base[position as! C.Index] as! C.ElementType
758 override func makeIterator() -> RLMIterator<Element> {
759 // FIXME: it should be possible to avoid this force-casting
760 return base.makeIterator() as! RLMIterator<Element>
764 // MARK: Collection Support
766 override var startIndex: Int {
767 // FIXME: it should be possible to avoid this force-casting
768 return base.startIndex as! Int
771 override var endIndex: Int {
772 // FIXME: it should be possible to avoid this force-casting
773 return base.endIndex as! Int
777 // MARK: Key-Value Coding
779 override func value(forKey key: String) -> Any? { return base.value(forKey: key) }
781 override func value(forKeyPath keyPath: String) -> Any? { return base.value(forKeyPath: keyPath) }
783 override func setValue(_ value: Any?, forKey key: String) { base.setValue(value, forKey: key) }
785 // MARK: Notifications
788 override func _observe(_ block: @escaping (RealmCollectionChange<Wrapper>) -> Void)
789 -> NotificationToken { return base._observe(block) }
791 // MARK: AssistedObjectiveCBridgeable
793 override class func bridging(from objectiveCValue: Any, with metadata: Any?) -> _AnyRealmCollection {
794 return _AnyRealmCollection(
795 base: (C.self as! AssistedObjectiveCBridgeable.Type).bridging(from: objectiveCValue, with: metadata) as! C)
798 override var bridged: (objectiveCValue: Any, metadata: Any?) {
799 return (base as! AssistedObjectiveCBridgeable).bridged
804 A type-erased `RealmCollection`.
806 Instances of `RealmCollection` forward operations to an opaque underlying collection having the same `Element` type.
808 public final class AnyRealmCollection<Element: RealmCollectionValue>: RealmCollection {
810 /// The type of the objects contained within the collection.
811 public typealias ElementType = Element
813 public func index(after i: Int) -> Int { return i + 1 }
814 public func index(before i: Int) -> Int { return i - 1 }
816 /// The type of the objects contained in the collection.
817 fileprivate let base: _AnyRealmCollectionBase<Element>
819 fileprivate init(base: _AnyRealmCollectionBase<Element>) {
823 /// Creates an `AnyRealmCollection` wrapping `base`.
824 public init<C: RealmCollection>(_ base: C) where C.ElementType == Element {
825 self.base = _AnyRealmCollection(base: base)
830 /// The Realm which manages the collection, or `nil` if the collection is unmanaged.
831 public var realm: Realm? { return base.realm }
834 Indicates if the collection can no longer be accessed.
836 The collection can no longer be accessed if `invalidate()` is called on the containing `realm`.
838 public var isInvalidated: Bool { return base.isInvalidated }
840 /// The number of objects in the collection.
841 public var count: Int { return base.count }
843 /// A human-readable description of the objects contained in the collection.
844 public var description: String { return base.description }
847 // MARK: Index Retrieval
850 Returns the index of the given object, or `nil` if the object is not in the collection.
852 - parameter object: An object.
854 public func index(of object: Element) -> Int? { return base.index(of: object) }
857 Returns the index of the first object matching the given predicate, or `nil` if no objects match.
859 - parameter predicate: The predicate with which to filter the objects.
861 public func index(matching predicate: NSPredicate) -> Int? { return base.index(matching: predicate) }
864 Returns the index of the first object matching the given predicate, or `nil` if no objects match.
866 - parameter predicateFormat: A predicate format string, optionally followed by a variable number of arguments.
868 public func index(matching predicateFormat: String, _ args: Any...) -> Int? {
869 return base.index(matching: NSPredicate(format: predicateFormat, argumentArray: unwrapOptionals(in: args)))
875 Returns a `Results` containing all objects matching the given predicate in the collection.
877 - parameter predicateFormat: A predicate format string, optionally followed by a variable number of arguments.
879 public func filter(_ predicateFormat: String, _ args: Any...) -> Results<Element> {
880 return base.filter(NSPredicate(format: predicateFormat, argumentArray: unwrapOptionals(in: args)))
884 Returns a `Results` containing all objects matching the given predicate in the collection.
886 - parameter predicate: The predicate with which to filter the objects.
888 - returns: A `Results` containing objects that match the given predicate.
890 public func filter(_ predicate: NSPredicate) -> Results<Element> { return base.filter(predicate) }
896 Returns a `Results` containing the objects in the collection, but sorted.
898 Objects are sorted based on the values of the given key path. For example, to sort a collection of `Student`s from
899 youngest to oldest based on their `age` property, you might call
900 `students.sorted(byKeyPath: "age", ascending: true)`.
902 - warning: Collections may only be sorted by properties of boolean, `Date`, `NSDate`, single and double-precision
903 floating point, integer, and string types.
905 - parameter keyPath: The key path to sort by.
906 - parameter ascending: The direction to sort in.
908 public func sorted(byKeyPath keyPath: String, ascending: Bool) -> Results<Element> {
909 return base.sorted(byKeyPath: keyPath, ascending: ascending)
913 Returns a `Results` containing the objects in the collection, but sorted.
915 - warning: Collections may only be sorted by properties of boolean, `Date`, `NSDate`, single and double-precision
916 floating point, integer, and string types.
918 - see: `sorted(byKeyPath:ascending:)`
920 - parameter sortDescriptors: A sequence of `SortDescriptor`s to sort by.
922 public func sorted<S: Sequence>(by sortDescriptors: S) -> Results<Element>
923 where S.Iterator.Element == SortDescriptor {
924 return base.sorted(by: sortDescriptors)
928 // MARK: Aggregate Operations
931 Returns the minimum (lowest) value of the given property among all the objects in the collection, or `nil` if the
934 - warning: Only a property whose type conforms to the `MinMaxType` protocol can be specified.
936 - parameter property: The name of a property whose minimum value is desired.
938 public func min<T: MinMaxType>(ofProperty property: String) -> T? {
939 return base.min(ofProperty: property)
943 Returns the maximum (highest) value of the given property among all the objects in the collection, or `nil` if the
946 - warning: Only a property whose type conforms to the `MinMaxType` protocol can be specified.
948 - parameter property: The name of a property whose minimum value is desired.
950 public func max<T: MinMaxType>(ofProperty property: String) -> T? {
951 return base.max(ofProperty: property)
955 Returns the sum of the values of a given property over all the objects in the collection.
957 - warning: Only a property whose type conforms to the `AddableType` protocol can be specified.
959 - parameter property: The name of a property whose values should be summed.
961 public func sum<T: AddableType>(ofProperty property: String) -> T { return base.sum(ofProperty: property) }
964 Returns the average value of a given property over all the objects in the collection, or `nil` if the collection is
967 - warning: Only the name of a property whose type conforms to the `AddableType` protocol can be specified.
969 - parameter property: The name of a property whose average value should be calculated.
971 public func average(ofProperty property: String) -> Double? { return base.average(ofProperty: property) }
974 // MARK: Sequence Support
977 Returns the object at the given `index`.
979 - parameter index: The index.
981 public subscript(position: Int) -> Element { return base[position] }
983 /// Returns a `RLMIterator` that yields successive elements in the collection.
984 public func makeIterator() -> RLMIterator<Element> { return base.makeIterator() }
987 // MARK: Collection Support
989 /// The position of the first element in a non-empty collection.
990 /// Identical to endIndex in an empty collection.
991 public var startIndex: Int { return base.startIndex }
993 /// The collection's "past the end" position.
994 /// endIndex is not a valid argument to subscript, and is always reachable from startIndex by
995 /// zero or more applications of successor().
996 public var endIndex: Int { return base.endIndex }
999 // MARK: Key-Value Coding
1002 Returns an `Array` containing the results of invoking `valueForKey(_:)` with `key` on each of the collection's
1005 - parameter key: The name of the property whose values are desired.
1007 public func value(forKey key: String) -> Any? { return base.value(forKey: key) }
1010 Returns an `Array` containing the results of invoking `valueForKeyPath(_:)` with `keyPath` on each of the
1011 collection's objects.
1013 - parameter keyPath: The key path to the property whose values are desired.
1015 public func value(forKeyPath keyPath: String) -> Any? { return base.value(forKeyPath: keyPath) }
1018 Invokes `setValue(_:forKey:)` on each of the collection's objects using the specified `value` and `key`.
1020 - warning: This method may only be called during a write transaction.
1022 - parameter value: The value to set the property to.
1023 - parameter key: The name of the property whose value should be set on each object.
1025 public func setValue(_ value: Any?, forKey key: String) { base.setValue(value, forKey: key) }
1027 // MARK: Notifications
1030 Registers a block to be called each time the collection changes.
1032 The block will be asynchronously called with the initial results, and then called again after each write
1033 transaction which changes either any of the objects in the collection, or which objects are in the collection.
1035 The `change` parameter that is passed to the block reports, in the form of indices within the collection, which of
1036 the objects were added, removed, or modified during each write transaction. See the `RealmCollectionChange`
1037 documentation for more information on the change information supplied and an example of how to use it to update a
1040 At the time when the block is called, the collection will be fully evaluated and up-to-date, and as long as you do
1041 not perform a write transaction on the same thread or explicitly call `realm.refresh()`, accessing it will never
1042 perform blocking work.
1044 Notifications are delivered via the standard run loop, and so can't be delivered while the run loop is blocked by
1045 other activity. When notifications can't be delivered instantly, multiple notifications may be coalesced into a
1046 single notification. This can include the notification with the initial collection.
1048 For example, the following code performs a write transaction immediately after adding the notification block, so
1049 there is no opportunity for the initial notification to be delivered first. As a result, the initial notification
1050 will reflect the state of the Realm after the write transaction.
1053 let results = realm.objects(Dog.self)
1054 print("dogs.count: \(dogs?.count)") // => 0
1055 let token = dogs.observe { changes in
1057 case .initial(let dogs):
1058 // Will print "dogs.count: 1"
1059 print("dogs.count: \(dogs.count)")
1062 // Will not be hit in this example
1071 person.dogs.append(dog)
1073 // end of run loop execution context
1076 You must retain the returned token for as long as you want updates to be sent to the block. To stop receiving
1077 updates, call `invalidate()` on the token.
1079 - warning: This method cannot be called during a write transaction, or when the containing Realm is read-only.
1081 - parameter block: The block to be called whenever a change occurs.
1082 - returns: A token which must be held for as long as you want updates to be delivered.
1084 public func observe(_ block: @escaping (RealmCollectionChange<AnyRealmCollection>) -> Void)
1085 -> NotificationToken { return base._observe(block) }
1088 public func _observe(_ block: @escaping (RealmCollectionChange<AnyRealmCollection>) -> Void)
1089 -> NotificationToken { return base._observe(block) }
1092 // MARK: AssistedObjectiveCBridgeable
1094 private struct AnyRealmCollectionBridgingMetadata<T: RealmCollectionValue> {
1095 var baseMetadata: Any?
1096 var baseType: _AnyRealmCollectionBase<T>.Type
1099 extension AnyRealmCollection: AssistedObjectiveCBridgeable {
1100 static func bridging(from objectiveCValue: Any, with metadata: Any?) -> AnyRealmCollection {
1101 guard let metadata = metadata as? AnyRealmCollectionBridgingMetadata<Element> else { preconditionFailure() }
1102 return AnyRealmCollection(base: metadata.baseType.bridging(from: objectiveCValue, with: metadata.baseMetadata))
1105 var bridged: (objectiveCValue: Any, metadata: Any?) {
1107 objectiveCValue: base.bridged.objectiveCValue,
1108 metadata: AnyRealmCollectionBridgingMetadata(baseMetadata: base.bridged.metadata, baseType: type(of: base))
1113 // MARK: Unavailable
1115 extension RealmCollection {
1116 @available(*, unavailable, renamed: "sorted(byKeyPath:ascending:)")
1117 func sorted(byProperty property: String, ascending: Bool) -> Results<ElementType> { fatalError() }
1119 @available(*, unavailable, renamed: "observe(_:)")
1120 public func addNotificationBlock(_ block: @escaping (RealmCollectionChange<Self>) -> Void) -> NotificationToken {