RealmCollection.swift 43 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142
  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. import Foundation
  19. import Realm
  20. /**
  21. An iterator for a `RealmCollection` instance.
  22. */
  23. public struct RLMIterator<Element: RealmCollectionValue>: IteratorProtocol {
  24. private var generatorBase: NSFastEnumerationIterator
  25. init(collection: RLMCollection) {
  26. generatorBase = NSFastEnumerationIterator(collection)
  27. }
  28. /// Advance to the next element and return it, or `nil` if no next element exists.
  29. public mutating func next() -> Element? {
  30. let next = generatorBase.next()
  31. if next is NSNull {
  32. return Element._nilValue()
  33. }
  34. if let next = next as? Object? {
  35. if next == nil {
  36. return nil as Element?
  37. }
  38. return unsafeBitCast(next, to: Optional<Element>.self)
  39. }
  40. return dynamicBridgeCast(fromObjectiveC: next as Any)
  41. }
  42. }
  43. /**
  44. A `RealmCollectionChange` value encapsulates information about changes to collections
  45. that are reported by Realm notifications.
  46. The change information is available in two formats: a simple array of row
  47. indices in the collection for each type of change, and an array of index paths
  48. in a requested section suitable for passing directly to `UITableView`'s batch
  49. update methods.
  50. The arrays of indices in the `.update` case follow `UITableView`'s batching
  51. conventions, and can be passed as-is to a table view's batch update functions after being converted to index paths.
  52. For example, for a simple one-section table view, you can do the following:
  53. ```swift
  54. self.notificationToken = results.observe { changes in
  55. switch changes {
  56. case .initial:
  57. // Results are now populated and can be accessed without blocking the UI
  58. self.tableView.reloadData()
  59. break
  60. case .update(_, let deletions, let insertions, let modifications):
  61. // Query results have changed, so apply them to the TableView
  62. self.tableView.beginUpdates()
  63. self.tableView.insertRows(at: insertions.map { IndexPath(row: $0, section: 0) },
  64. with: .automatic)
  65. self.tableView.deleteRows(at: deletions.map { IndexPath(row: $0, section: 0) },
  66. with: .automatic)
  67. self.tableView.reloadRows(at: modifications.map { IndexPath(row: $0, section: 0) },
  68. with: .automatic)
  69. self.tableView.endUpdates()
  70. break
  71. case .error(let err):
  72. // An error occurred while opening the Realm file on the background worker thread
  73. fatalError("\(err)")
  74. break
  75. }
  76. }
  77. ```
  78. */
  79. public enum RealmCollectionChange<CollectionType> {
  80. /**
  81. `.initial` indicates that the initial run of the query has completed (if
  82. applicable), and the collection can now be used without performing any
  83. blocking work.
  84. */
  85. case initial(CollectionType)
  86. /**
  87. `.update` indicates that a write transaction has been committed which
  88. either changed which objects are in the collection, and/or modified one
  89. or more of the objects in the collection.
  90. All three of the change arrays are always sorted in ascending order.
  91. - parameter deletions: The indices in the previous version of the collection which were removed from this one.
  92. - parameter insertions: The indices in the new collection which were added in this version.
  93. - parameter modifications: The indices of the objects in the new collection which were modified in this version.
  94. */
  95. case update(CollectionType, deletions: [Int], insertions: [Int], modifications: [Int])
  96. /**
  97. If an error occurs, notification blocks are called one time with a `.error`
  98. result and an `NSError` containing details about the error. This can only
  99. currently happen if opening the Realm on a background thread to calcuate
  100. the change set fails. The callback will never be called again after it is
  101. invoked with a .error value.
  102. */
  103. case error(Error)
  104. static func fromObjc(value: CollectionType?, change: RLMCollectionChange?, error: Error?) -> RealmCollectionChange {
  105. if let error = error {
  106. return .error(error)
  107. }
  108. if let change = change {
  109. return .update(value!,
  110. deletions: forceCast(change.deletions, to: [Int].self),
  111. insertions: forceCast(change.insertions, to: [Int].self),
  112. modifications: forceCast(change.modifications, to: [Int].self))
  113. }
  114. return .initial(value!)
  115. }
  116. }
  117. private func forceCast<A, U>(_ from: A, to type: U.Type) -> U {
  118. return from as! U
  119. }
  120. /// A type which can be stored in a Realm List or Results.
  121. ///
  122. /// Declaring additional types as conforming to this protocol will not make them
  123. /// actually work. Most of the logic for how to store values in Realm is not
  124. /// implemented in Swift and there is currently no extension mechanism for
  125. /// supporting more types.
  126. public protocol RealmCollectionValue: Equatable {
  127. /// :nodoc:
  128. static func _rlmArray() -> RLMArray<AnyObject>
  129. /// :nodoc:
  130. static func _nilValue() -> Self
  131. }
  132. extension RealmCollectionValue {
  133. /// :nodoc:
  134. public static func _rlmArray() -> RLMArray<AnyObject> {
  135. return RLMArray(objectType: .int, optional: false)
  136. }
  137. /// :nodoc:
  138. public static func _nilValue() -> Self {
  139. fatalError("unexpected NSNull for non-Optional type")
  140. }
  141. }
  142. private func arrayType<T>(_ type: T.Type) -> RLMArray<AnyObject> {
  143. switch type {
  144. case is Int.Type, is Int8.Type, is Int16.Type, is Int32.Type, is Int64.Type:
  145. return RLMArray(objectType: .int, optional: true)
  146. case is Bool.Type: return RLMArray(objectType: .bool, optional: true)
  147. case is Float.Type: return RLMArray(objectType: .float, optional: true)
  148. case is Double.Type: return RLMArray(objectType: .double, optional: true)
  149. case is String.Type: return RLMArray(objectType: .string, optional: true)
  150. case is Data.Type: return RLMArray(objectType: .data, optional: true)
  151. case is Date.Type: return RLMArray(objectType: .date, optional: true)
  152. default: fatalError("Unsupported type for List: \(type)?")
  153. }
  154. }
  155. extension Optional: RealmCollectionValue where Wrapped: RealmCollectionValue {
  156. /// :nodoc:
  157. public static func _rlmArray() -> RLMArray<AnyObject> {
  158. return arrayType(Wrapped.self)
  159. }
  160. /// :nodoc:
  161. public static func _nilValue() -> Optional {
  162. return nil
  163. }
  164. }
  165. extension Int: RealmCollectionValue {}
  166. extension Int8: RealmCollectionValue {}
  167. extension Int16: RealmCollectionValue {}
  168. extension Int32: RealmCollectionValue {}
  169. extension Int64: RealmCollectionValue {}
  170. extension Float: RealmCollectionValue {
  171. /// :nodoc:
  172. public static func _rlmArray() -> RLMArray<AnyObject> {
  173. return RLMArray(objectType: .float, optional: false)
  174. }
  175. }
  176. extension Double: RealmCollectionValue {
  177. /// :nodoc:
  178. public static func _rlmArray() -> RLMArray<AnyObject> {
  179. return RLMArray(objectType: .double, optional: false)
  180. }
  181. }
  182. extension Bool: RealmCollectionValue {
  183. /// :nodoc:
  184. public static func _rlmArray() -> RLMArray<AnyObject> {
  185. return RLMArray(objectType: .bool, optional: false)
  186. }
  187. }
  188. extension String: RealmCollectionValue {
  189. /// :nodoc:
  190. public static func _rlmArray() -> RLMArray<AnyObject> {
  191. return RLMArray(objectType: .string, optional: false)
  192. }
  193. }
  194. extension Date: RealmCollectionValue {
  195. /// :nodoc:
  196. public static func _rlmArray() -> RLMArray<AnyObject> {
  197. return RLMArray(objectType: .date, optional: false)
  198. }
  199. }
  200. extension Data: RealmCollectionValue {
  201. /// :nodoc:
  202. public static func _rlmArray() -> RLMArray<AnyObject> {
  203. return RLMArray(objectType: .data, optional: false)
  204. }
  205. }
  206. /// :nodoc:
  207. public protocol _RealmCollectionEnumerator {
  208. // swiftlint:disable:next identifier_name
  209. func _asNSFastEnumerator() -> Any
  210. }
  211. /// :nodoc:
  212. public protocol RealmCollectionBase: RandomAccessCollection, LazyCollectionProtocol, CustomStringConvertible, ThreadConfined where Element: RealmCollectionValue {
  213. // This typealias was needed with Swift 3.1. It no longer is, but remains
  214. // just in case someone was depending on it
  215. typealias ElementType = Element
  216. }
  217. /**
  218. A homogenous collection of `Object`s which can be retrieved, filtered, sorted, and operated upon.
  219. */
  220. public protocol RealmCollection: RealmCollectionBase, _RealmCollectionEnumerator {
  221. // Must also conform to `AssistedObjectiveCBridgeable`
  222. // MARK: Properties
  223. /// The Realm which manages the collection, or `nil` for unmanaged collections.
  224. var realm: Realm? { get }
  225. /**
  226. Indicates if the collection can no longer be accessed.
  227. The collection can no longer be accessed if `invalidate()` is called on the `Realm` that manages the collection.
  228. */
  229. var isInvalidated: Bool { get }
  230. /// The number of objects in the collection.
  231. var count: Int { get }
  232. /// A human-readable description of the objects contained in the collection.
  233. var description: String { get }
  234. // MARK: Index Retrieval
  235. /**
  236. Returns the index of an object in the collection, or `nil` if the object is not present.
  237. - parameter object: An object.
  238. */
  239. func index(of object: Element) -> Int?
  240. /**
  241. Returns the index of the first object matching the predicate, or `nil` if no objects match.
  242. - parameter predicate: The predicate to use to filter the objects.
  243. */
  244. func index(matching predicate: NSPredicate) -> Int?
  245. /**
  246. Returns the index of the first object matching the predicate, or `nil` if no objects match.
  247. - parameter predicateFormat: A predicate format string, optionally followed by a variable number of arguments.
  248. */
  249. func index(matching predicateFormat: String, _ args: Any...) -> Int?
  250. // MARK: Filtering
  251. /**
  252. Returns a `Results` containing all objects matching the given predicate in the collection.
  253. - parameter predicateFormat: A predicate format string, optionally followed by a variable number of arguments.
  254. */
  255. func filter(_ predicateFormat: String, _ args: Any...) -> Results<Element>
  256. /**
  257. Returns a `Results` containing all objects matching the given predicate in the collection.
  258. - parameter predicate: The predicate to use to filter the objects.
  259. */
  260. func filter(_ predicate: NSPredicate) -> Results<Element>
  261. // MARK: Sorting
  262. /**
  263. Returns a `Results` containing the objects in the collection, but sorted.
  264. Objects are sorted based on the values of the given key path. For example, to sort a collection of `Student`s from
  265. youngest to oldest based on their `age` property, you might call
  266. `students.sorted(byKeyPath: "age", ascending: true)`.
  267. - warning: Collections may only be sorted by properties of boolean, `Date`, `NSDate`, single and double-precision
  268. floating point, integer, and string types.
  269. - parameter keyPath: The key path to sort by.
  270. - parameter ascending: The direction to sort in.
  271. */
  272. func sorted(byKeyPath keyPath: String, ascending: Bool) -> Results<Element>
  273. /**
  274. Returns a `Results` containing the objects in the collection, but sorted.
  275. - warning: Collections may only be sorted by properties of boolean, `Date`, `NSDate`, single and double-precision
  276. floating point, integer, and string types.
  277. - see: `sorted(byKeyPath:ascending:)`
  278. - parameter sortDescriptors: A sequence of `SortDescriptor`s to sort by.
  279. */
  280. func sorted<S: Sequence>(by sortDescriptors: S) -> Results<Element> where S.Iterator.Element == SortDescriptor
  281. // MARK: Aggregate Operations
  282. /**
  283. Returns the minimum (lowest) value of the given property among all the objects in the collection, or `nil` if the
  284. collection is empty.
  285. - warning: Only a property whose type conforms to the `MinMaxType` protocol can be specified.
  286. - parameter property: The name of a property whose minimum value is desired.
  287. */
  288. func min<T: MinMaxType>(ofProperty property: String) -> T?
  289. /**
  290. Returns the maximum (highest) value of the given property among all the objects in the collection, or `nil` if the
  291. collection is empty.
  292. - warning: Only a property whose type conforms to the `MinMaxType` protocol can be specified.
  293. - parameter property: The name of a property whose minimum value is desired.
  294. */
  295. func max<T: MinMaxType>(ofProperty property: String) -> T?
  296. /**
  297. Returns the sum of the given property for objects in the collection, or `nil` if the collection is empty.
  298. - warning: Only names of properties of a type conforming to the `AddableType` protocol can be used.
  299. - parameter property: The name of a property conforming to `AddableType` to calculate sum on.
  300. */
  301. func sum<T: AddableType>(ofProperty property: String) -> T
  302. /**
  303. Returns the average value of a given property over all the objects in the collection, or `nil` if
  304. the collection is empty.
  305. - warning: Only a property whose type conforms to the `AddableType` protocol can be specified.
  306. - parameter property: The name of a property whose values should be summed.
  307. */
  308. func average(ofProperty property: String) -> Double?
  309. // MARK: Key-Value Coding
  310. /**
  311. Returns an `Array` containing the results of invoking `valueForKey(_:)` with `key` on each of the collection's
  312. objects.
  313. - parameter key: The name of the property whose values are desired.
  314. */
  315. func value(forKey key: String) -> Any?
  316. /**
  317. Returns an `Array` containing the results of invoking `valueForKeyPath(_:)` with `keyPath` on each of the
  318. collection's objects.
  319. - parameter keyPath: The key path to the property whose values are desired.
  320. */
  321. func value(forKeyPath keyPath: String) -> Any?
  322. /**
  323. Invokes `setValue(_:forKey:)` on each of the collection's objects using the specified `value` and `key`.
  324. - warning: This method may only be called during a write transaction.
  325. - parameter value: The object value.
  326. - parameter key: The name of the property whose value should be set on each object.
  327. */
  328. func setValue(_ value: Any?, forKey key: String)
  329. // MARK: Notifications
  330. /**
  331. Registers a block to be called each time the collection changes.
  332. The block will be asynchronously called with the initial results, and then called again after each write
  333. transaction which changes either any of the objects in the collection, or which objects are in the collection.
  334. The `change` parameter that is passed to the block reports, in the form of indices within the collection, which of
  335. the objects were added, removed, or modified during each write transaction. See the `RealmCollectionChange`
  336. documentation for more information on the change information supplied and an example of how to use it to update a
  337. `UITableView`.
  338. At the time when the block is called, the collection will be fully evaluated and up-to-date, and as long as you do
  339. not perform a write transaction on the same thread or explicitly call `realm.refresh()`, accessing it will never
  340. perform blocking work.
  341. If no queue is given, notifications are delivered via the standard run loop, and so can't be delivered while the
  342. run loop is blocked by other activity. If a queue is given, notifications are delivered to that queue instead. When
  343. notifications can't be delivered instantly, multiple notifications may be coalesced into a single notification.
  344. This can include the notification with the initial collection.
  345. For example, the following code performs a write transaction immediately after adding the notification block, so
  346. there is no opportunity for the initial notification to be delivered first. As a result, the initial notification
  347. will reflect the state of the Realm after the write transaction.
  348. ```swift
  349. let results = realm.objects(Dog.self)
  350. print("dogs.count: \(dogs?.count)") // => 0
  351. let token = dogs.observe { changes in
  352. switch changes {
  353. case .initial(let dogs):
  354. // Will print "dogs.count: 1"
  355. print("dogs.count: \(dogs.count)")
  356. break
  357. case .update:
  358. // Will not be hit in this example
  359. break
  360. case .error:
  361. break
  362. }
  363. }
  364. try! realm.write {
  365. let dog = Dog()
  366. dog.name = "Rex"
  367. person.dogs.append(dog)
  368. }
  369. // end of run loop execution context
  370. ```
  371. You must retain the returned token for as long as you want updates to be sent to the block. To stop receiving
  372. updates, call `invalidate()` on the token.
  373. - warning: This method cannot be called during a write transaction, or when the containing Realm is read-only.
  374. - parameter queue: The serial dispatch queue to receive notification on. If
  375. `nil`, notifications are delivered to the current thread.
  376. - parameter block: The block to be called whenever a change occurs.
  377. - returns: A token which must be held for as long as you want updates to be delivered.
  378. */
  379. func observe(on queue: DispatchQueue?, _ block: @escaping (RealmCollectionChange<Self>) -> Void) -> NotificationToken
  380. /// :nodoc:
  381. // swiftlint:disable:next identifier_name
  382. func _observe(_ queue: DispatchQueue?, _ block: @escaping (RealmCollectionChange<AnyRealmCollection<Element>>) -> Void) -> NotificationToken
  383. // MARK: Frozen Objects
  384. /// Returns if this collection is frozen
  385. var isFrozen: Bool { get }
  386. /**
  387. Returns a frozen (immutable) snapshot of this collection.
  388. The frozen copy is an immutable collection which contains the same data as this collection
  389. currently contains, but will not update when writes are made to the containing Realm. Unlike
  390. live collections, frozen collections can be accessed from any thread.
  391. - warning: This method cannot be called during a write transaction, or when the containing
  392. Realm is read-only.
  393. - warning: Holding onto a frozen collection for an extended period while performing write
  394. transaction on the Realm may result in the Realm file growing to large sizes. See
  395. `Realm.Configuration.maximumNumberOfActiveVersions` for more information.
  396. */
  397. func freeze() -> Self
  398. }
  399. public extension RealmCollection {
  400. /**
  401. Returns the index of the first object matching the given predicate, or `nil` if no objects match.
  402. - parameter predicateFormat: A predicate format string, optionally followed by a variable number of arguments.
  403. */
  404. func index(matching predicateFormat: String, _ args: Any...) -> Int? {
  405. return index(matching: NSPredicate(format: predicateFormat, argumentArray: unwrapOptionals(in: args)))
  406. }
  407. /**
  408. Returns a `Results` containing all objects matching the given predicate in the collection.
  409. - parameter predicateFormat: A predicate format string, optionally followed by a variable number of arguments.
  410. */
  411. func filter(_ predicateFormat: String, _ args: Any...) -> Results<Element> {
  412. return filter(NSPredicate(format: predicateFormat, argumentArray: unwrapOptionals(in: args)))
  413. }
  414. }
  415. /// :nodoc:
  416. public protocol OptionalProtocol {
  417. associatedtype Wrapped
  418. /// :nodoc:
  419. // swiftlint:disable:next identifier_name
  420. func _rlmInferWrappedType() -> Wrapped
  421. }
  422. extension Optional: OptionalProtocol {
  423. /// :nodoc:
  424. // swiftlint:disable:next identifier_name
  425. public func _rlmInferWrappedType() -> Wrapped { return self! }
  426. }
  427. public extension RealmCollection where Element: MinMaxType {
  428. /**
  429. Returns the minimum (lowest) value of the collection, or `nil` if the collection is empty.
  430. */
  431. func min() -> Element? {
  432. return min(ofProperty: "self")
  433. }
  434. /**
  435. Returns the maximum (highest) value of the collection, or `nil` if the collection is empty.
  436. */
  437. func max() -> Element? {
  438. return max(ofProperty: "self")
  439. }
  440. }
  441. public extension RealmCollection where Element: OptionalProtocol, Element.Wrapped: MinMaxType {
  442. /**
  443. Returns the minimum (lowest) value of the collection, or `nil` if the collection is empty.
  444. */
  445. func min() -> Element.Wrapped? {
  446. return min(ofProperty: "self")
  447. }
  448. /**
  449. Returns the maximum (highest) value of the collection, or `nil` if the collection is empty.
  450. */
  451. func max() -> Element.Wrapped? {
  452. return max(ofProperty: "self")
  453. }
  454. }
  455. public extension RealmCollection where Element: AddableType {
  456. /**
  457. Returns the sum of the values in the collection, or `nil` if the collection is empty.
  458. */
  459. func sum() -> Element {
  460. return sum(ofProperty: "self")
  461. }
  462. /**
  463. Returns the average of all of the values in the collection.
  464. */
  465. func average() -> Double? {
  466. return average(ofProperty: "self")
  467. }
  468. }
  469. public extension RealmCollection where Element: OptionalProtocol, Element.Wrapped: AddableType {
  470. /**
  471. Returns the sum of the values in the collection, or `nil` if the collection is empty.
  472. */
  473. func sum() -> Element.Wrapped {
  474. return sum(ofProperty: "self")
  475. }
  476. /**
  477. Returns the average of all of the values in the collection.
  478. */
  479. func average() -> Double? {
  480. return average(ofProperty: "self")
  481. }
  482. }
  483. public extension RealmCollection where Element: Comparable {
  484. /**
  485. Returns a `Results` containing the objects in the collection, but sorted.
  486. Objects are sorted based on their values. For example, to sort a collection of `Date`s from
  487. neweset to oldest based, you might call `dates.sorted(ascending: true)`.
  488. - parameter ascending: The direction to sort in.
  489. */
  490. func sorted(ascending: Bool = true) -> Results<Element> {
  491. return sorted(byKeyPath: "self", ascending: ascending)
  492. }
  493. }
  494. public extension RealmCollection where Element: OptionalProtocol, Element.Wrapped: Comparable {
  495. /**
  496. Returns a `Results` containing the objects in the collection, but sorted.
  497. Objects are sorted based on their values. For example, to sort a collection of `Date`s from
  498. neweset to oldest based, you might call `dates.sorted(ascending: true)`.
  499. - parameter ascending: The direction to sort in.
  500. */
  501. func sorted(ascending: Bool = true) -> Results<Element> {
  502. return sorted(byKeyPath: "self", ascending: ascending)
  503. }
  504. }
  505. private class _AnyRealmCollectionBase<T: RealmCollectionValue>: AssistedObjectiveCBridgeable {
  506. typealias Wrapper = AnyRealmCollection<Element>
  507. typealias Element = T
  508. var realm: Realm? { fatalError() }
  509. var isInvalidated: Bool { fatalError() }
  510. var count: Int { fatalError() }
  511. var description: String { fatalError() }
  512. func index(of object: Element) -> Int? { fatalError() }
  513. func index(matching predicate: NSPredicate) -> Int? { fatalError() }
  514. func filter(_ predicate: NSPredicate) -> Results<Element> { fatalError() }
  515. func sorted(byKeyPath keyPath: String, ascending: Bool) -> Results<Element> { fatalError() }
  516. func sorted<S: Sequence>(by sortDescriptors: S) -> Results<Element> where S.Iterator.Element == SortDescriptor {
  517. fatalError()
  518. }
  519. func min<T: MinMaxType>(ofProperty property: String) -> T? { fatalError() }
  520. func max<T: MinMaxType>(ofProperty property: String) -> T? { fatalError() }
  521. func sum<T: AddableType>(ofProperty property: String) -> T { fatalError() }
  522. func average(ofProperty property: String) -> Double? { fatalError() }
  523. subscript(position: Int) -> Element { fatalError() }
  524. func makeIterator() -> RLMIterator<T> { fatalError() }
  525. var startIndex: Int { fatalError() }
  526. var endIndex: Int { fatalError() }
  527. func value(forKey key: String) -> Any? { fatalError() }
  528. func value(forKeyPath keyPath: String) -> Any? { fatalError() }
  529. func setValue(_ value: Any?, forKey key: String) { fatalError() }
  530. // swiftlint:disable:next identifier_name
  531. func _observe(_ queue: DispatchQueue?, _ block: @escaping (RealmCollectionChange<Wrapper>) -> Void)
  532. -> NotificationToken { fatalError() }
  533. class func bridging(from objectiveCValue: Any, with metadata: Any?) -> Self { fatalError() }
  534. var bridged: (objectiveCValue: Any, metadata: Any?) { fatalError() }
  535. // swiftlint:disable:next identifier_name
  536. func _asNSFastEnumerator() -> Any { fatalError() }
  537. var isFrozen: Bool { fatalError() }
  538. func freeze() -> AnyRealmCollection<T> { fatalError() }
  539. }
  540. private final class _AnyRealmCollection<C: RealmCollection>: _AnyRealmCollectionBase<C.Element> {
  541. let base: C
  542. init(base: C) {
  543. self.base = base
  544. }
  545. // MARK: Properties
  546. override var realm: Realm? { return base.realm }
  547. override var isInvalidated: Bool { return base.isInvalidated }
  548. override var count: Int { return base.count }
  549. override var description: String { return base.description }
  550. // MARK: Index Retrieval
  551. override func index(of object: C.Element) -> Int? { return base.index(of: object) }
  552. override func index(matching predicate: NSPredicate) -> Int? { return base.index(matching: predicate) }
  553. // MARK: Filtering
  554. override func filter(_ predicate: NSPredicate) -> Results<C.Element> { return base.filter(predicate) }
  555. // MARK: Sorting
  556. override func sorted(byKeyPath keyPath: String, ascending: Bool) -> Results<C.Element> {
  557. return base.sorted(byKeyPath: keyPath, ascending: ascending)
  558. }
  559. override func sorted<S: Sequence>
  560. (by sortDescriptors: S) -> Results<C.Element> where S.Iterator.Element == SortDescriptor {
  561. return base.sorted(by: sortDescriptors)
  562. }
  563. // MARK: Aggregate Operations
  564. override func min<T: MinMaxType>(ofProperty property: String) -> T? {
  565. return base.min(ofProperty: property)
  566. }
  567. override func max<T: MinMaxType>(ofProperty property: String) -> T? {
  568. return base.max(ofProperty: property)
  569. }
  570. override func sum<T: AddableType>(ofProperty property: String) -> T {
  571. return base.sum(ofProperty: property)
  572. }
  573. override func average(ofProperty property: String) -> Double? {
  574. return base.average(ofProperty: property)
  575. }
  576. // MARK: Sequence Support
  577. override subscript(position: Int) -> C.Element {
  578. return base[position as! C.Index]
  579. }
  580. override func makeIterator() -> RLMIterator<Element> {
  581. // FIXME: it should be possible to avoid this force-casting
  582. return base.makeIterator() as! RLMIterator<Element>
  583. }
  584. /// :nodoc:
  585. override func _asNSFastEnumerator() -> Any {
  586. return base._asNSFastEnumerator()
  587. }
  588. // MARK: Collection Support
  589. override var startIndex: Int {
  590. // FIXME: it should be possible to avoid this force-casting
  591. return base.startIndex as! Int
  592. }
  593. override var endIndex: Int {
  594. // FIXME: it should be possible to avoid this force-casting
  595. return base.endIndex as! Int
  596. }
  597. // MARK: Key-Value Coding
  598. override func value(forKey key: String) -> Any? { return base.value(forKey: key) }
  599. override func value(forKeyPath keyPath: String) -> Any? { return base.value(forKeyPath: keyPath) }
  600. override func setValue(_ value: Any?, forKey key: String) { base.setValue(value, forKey: key) }
  601. // MARK: Notifications
  602. /// :nodoc:
  603. override func _observe(_ queue: DispatchQueue?, _ block: @escaping (RealmCollectionChange<Wrapper>) -> Void)
  604. -> NotificationToken { return base._observe(queue, block) }
  605. // MARK: AssistedObjectiveCBridgeable
  606. override class func bridging(from objectiveCValue: Any, with metadata: Any?) -> _AnyRealmCollection {
  607. return _AnyRealmCollection(
  608. base: (C.self as! AssistedObjectiveCBridgeable.Type).bridging(from: objectiveCValue, with: metadata) as! C)
  609. }
  610. override var bridged: (objectiveCValue: Any, metadata: Any?) {
  611. return (base as! AssistedObjectiveCBridgeable).bridged
  612. }
  613. override var isFrozen: Bool {
  614. return base.isFrozen
  615. }
  616. override func freeze() -> AnyRealmCollection<Element> {
  617. return AnyRealmCollection(base.freeze())
  618. }
  619. }
  620. /**
  621. A type-erased `RealmCollection`.
  622. Instances of `RealmCollection` forward operations to an opaque underlying collection having the same `Element` type.
  623. */
  624. public struct AnyRealmCollection<Element: RealmCollectionValue>: RealmCollection {
  625. /// The type of the objects contained within the collection.
  626. public typealias ElementType = Element
  627. public func index(after i: Int) -> Int { return i + 1 }
  628. public func index(before i: Int) -> Int { return i - 1 }
  629. /// The type of the objects contained in the collection.
  630. fileprivate let base: _AnyRealmCollectionBase<Element>
  631. fileprivate init(base: _AnyRealmCollectionBase<Element>) {
  632. self.base = base
  633. }
  634. /// Creates an `AnyRealmCollection` wrapping `base`.
  635. public init<C: RealmCollection>(_ base: C) where C.Element == Element {
  636. self.base = _AnyRealmCollection(base: base)
  637. }
  638. // MARK: Properties
  639. /// The Realm which manages the collection, or `nil` if the collection is unmanaged.
  640. public var realm: Realm? { return base.realm }
  641. /**
  642. Indicates if the collection can no longer be accessed.
  643. The collection can no longer be accessed if `invalidate()` is called on the containing `realm`.
  644. */
  645. public var isInvalidated: Bool { return base.isInvalidated }
  646. /// The number of objects in the collection.
  647. public var count: Int { return base.count }
  648. /// A human-readable description of the objects contained in the collection.
  649. public var description: String { return base.description }
  650. // MARK: Index Retrieval
  651. /**
  652. Returns the index of the given object, or `nil` if the object is not in the collection.
  653. - parameter object: An object.
  654. */
  655. public func index(of object: Element) -> Int? { return base.index(of: object) }
  656. /**
  657. Returns the index of the first object matching the given predicate, or `nil` if no objects match.
  658. - parameter predicate: The predicate with which to filter the objects.
  659. */
  660. public func index(matching predicate: NSPredicate) -> Int? { return base.index(matching: predicate) }
  661. // MARK: Filtering
  662. /**
  663. Returns a `Results` containing all objects matching the given predicate in the collection.
  664. - parameter predicate: The predicate with which to filter the objects.
  665. - returns: A `Results` containing objects that match the given predicate.
  666. */
  667. public func filter(_ predicate: NSPredicate) -> Results<Element> { return base.filter(predicate) }
  668. // MARK: Sorting
  669. /**
  670. Returns a `Results` containing the objects in the collection, but sorted.
  671. Objects are sorted based on the values of the given key path. For example, to sort a collection of `Student`s from
  672. youngest to oldest based on their `age` property, you might call
  673. `students.sorted(byKeyPath: "age", ascending: true)`.
  674. - warning: Collections may only be sorted by properties of boolean, `Date`, `NSDate`, single and double-precision
  675. floating point, integer, and string types.
  676. - parameter keyPath: The key path to sort by.
  677. - parameter ascending: The direction to sort in.
  678. */
  679. public func sorted(byKeyPath keyPath: String, ascending: Bool) -> Results<Element> {
  680. return base.sorted(byKeyPath: keyPath, ascending: ascending)
  681. }
  682. /**
  683. Returns a `Results` containing the objects in the collection, but sorted.
  684. - warning: Collections may only be sorted by properties of boolean, `Date`, `NSDate`, single and double-precision
  685. floating point, integer, and string types.
  686. - see: `sorted(byKeyPath:ascending:)`
  687. - parameter sortDescriptors: A sequence of `SortDescriptor`s to sort by.
  688. */
  689. public func sorted<S: Sequence>(by sortDescriptors: S) -> Results<Element>
  690. where S.Iterator.Element == SortDescriptor {
  691. return base.sorted(by: sortDescriptors)
  692. }
  693. // MARK: Aggregate Operations
  694. /**
  695. Returns the minimum (lowest) value of the given property among all the objects in the collection, or `nil` if the
  696. collection is empty.
  697. - warning: Only a property whose type conforms to the `MinMaxType` protocol can be specified.
  698. - parameter property: The name of a property whose minimum value is desired.
  699. */
  700. public func min<T: MinMaxType>(ofProperty property: String) -> T? {
  701. return base.min(ofProperty: property)
  702. }
  703. /**
  704. Returns the maximum (highest) value of the given property among all the objects in the collection, or `nil` if the
  705. collection is empty.
  706. - warning: Only a property whose type conforms to the `MinMaxType` protocol can be specified.
  707. - parameter property: The name of a property whose minimum value is desired.
  708. */
  709. public func max<T: MinMaxType>(ofProperty property: String) -> T? {
  710. return base.max(ofProperty: property)
  711. }
  712. /**
  713. Returns the sum of the values of a given property over all the objects in the collection.
  714. - warning: Only a property whose type conforms to the `AddableType` protocol can be specified.
  715. - parameter property: The name of a property whose values should be summed.
  716. */
  717. public func sum<T: AddableType>(ofProperty property: String) -> T { return base.sum(ofProperty: property) }
  718. /**
  719. Returns the average value of a given property over all the objects in the collection, or `nil` if the collection is
  720. empty.
  721. - warning: Only the name of a property whose type conforms to the `AddableType` protocol can be specified.
  722. - parameter property: The name of a property whose average value should be calculated.
  723. */
  724. public func average(ofProperty property: String) -> Double? { return base.average(ofProperty: property) }
  725. // MARK: Sequence Support
  726. /**
  727. Returns the object at the given `index`.
  728. - parameter index: The index.
  729. */
  730. public subscript(position: Int) -> Element { return base[position] }
  731. /// Returns a `RLMIterator` that yields successive elements in the collection.
  732. public func makeIterator() -> RLMIterator<Element> { return base.makeIterator() }
  733. /// :nodoc:
  734. // swiftlint:disable:next identifier_name
  735. public func _asNSFastEnumerator() -> Any { return base._asNSFastEnumerator() }
  736. // MARK: Collection Support
  737. /// The position of the first element in a non-empty collection.
  738. /// Identical to endIndex in an empty collection.
  739. public var startIndex: Int { return base.startIndex }
  740. /// The collection's "past the end" position.
  741. /// endIndex is not a valid argument to subscript, and is always reachable from startIndex by
  742. /// zero or more applications of successor().
  743. public var endIndex: Int { return base.endIndex }
  744. // MARK: Key-Value Coding
  745. /**
  746. Returns an `Array` containing the results of invoking `valueForKey(_:)` with `key` on each of the collection's
  747. objects.
  748. - parameter key: The name of the property whose values are desired.
  749. */
  750. public func value(forKey key: String) -> Any? { return base.value(forKey: key) }
  751. /**
  752. Returns an `Array` containing the results of invoking `valueForKeyPath(_:)` with `keyPath` on each of the
  753. collection's objects.
  754. - parameter keyPath: The key path to the property whose values are desired.
  755. */
  756. public func value(forKeyPath keyPath: String) -> Any? { return base.value(forKeyPath: keyPath) }
  757. /**
  758. Invokes `setValue(_:forKey:)` on each of the collection's objects using the specified `value` and `key`.
  759. - warning: This method may only be called during a write transaction.
  760. - parameter value: The value to set the property to.
  761. - parameter key: The name of the property whose value should be set on each object.
  762. */
  763. public func setValue(_ value: Any?, forKey key: String) { base.setValue(value, forKey: key) }
  764. // MARK: Notifications
  765. /**
  766. Registers a block to be called each time the collection changes.
  767. The block will be asynchronously called with the initial results, and then called again after each write
  768. transaction which changes either any of the objects in the collection, or which objects are in the collection.
  769. The `change` parameter that is passed to the block reports, in the form of indices within the collection, which of
  770. the objects were added, removed, or modified during each write transaction. See the `RealmCollectionChange`
  771. documentation for more information on the change information supplied and an example of how to use it to update a
  772. `UITableView`.
  773. At the time when the block is called, the collection will be fully evaluated and up-to-date, and as long as you do
  774. not perform a write transaction on the same thread or explicitly call `realm.refresh()`, accessing it will never
  775. perform blocking work.
  776. Notifications are delivered via the standard run loop, and so can't be delivered while the run loop is blocked by
  777. other activity. When notifications can't be delivered instantly, multiple notifications may be coalesced into a
  778. single notification. This can include the notification with the initial collection.
  779. For example, the following code performs a write transaction immediately after adding the notification block, so
  780. there is no opportunity for the initial notification to be delivered first. As a result, the initial notification
  781. will reflect the state of the Realm after the write transaction.
  782. ```swift
  783. let results = realm.objects(Dog.self)
  784. print("dogs.count: \(dogs?.count)") // => 0
  785. let token = dogs.observe { changes in
  786. switch changes {
  787. case .initial(let dogs):
  788. // Will print "dogs.count: 1"
  789. print("dogs.count: \(dogs.count)")
  790. break
  791. case .update:
  792. // Will not be hit in this example
  793. break
  794. case .error:
  795. break
  796. }
  797. }
  798. try! realm.write {
  799. let dog = Dog()
  800. dog.name = "Rex"
  801. person.dogs.append(dog)
  802. }
  803. // end of run loop execution context
  804. ```
  805. You must retain the returned token for as long as you want updates to be sent to the block. To stop receiving
  806. updates, call `invalidate()` on the token.
  807. - warning: This method cannot be called during a write transaction, or when the containing Realm is read-only.
  808. - parameter block: The block to be called whenever a change occurs.
  809. - returns: A token which must be held for as long as you want updates to be delivered.
  810. */
  811. public func observe(on queue: DispatchQueue? = nil,
  812. _ block: @escaping (RealmCollectionChange<AnyRealmCollection>) -> Void)
  813. -> NotificationToken { return base._observe(queue, block) }
  814. /// :nodoc:
  815. // swiftlint:disable:next identifier_name
  816. public func _observe(_ queue: DispatchQueue?, _ block: @escaping (RealmCollectionChange<AnyRealmCollection>) -> Void)
  817. -> NotificationToken { return base._observe(queue, block) }
  818. // MARK: Frozen Objects
  819. /// Returns if this collection is frozen.
  820. public var isFrozen: Bool { return base.isFrozen }
  821. /**
  822. Returns a frozen (immutable) snapshot of this collection.
  823. The frozen copy is an immutable collection which contains the same data as this collection
  824. currently contains, but will not update when writes are made to the containing Realm. Unlike
  825. live collections, frozen collections can be accessed from any thread.
  826. - warning: This method cannot be called during a write transaction, or when the containing
  827. Realm is read-only.
  828. - warning: Holding onto a frozen collection for an extended period while performing write
  829. transaction on the Realm may result in the Realm file growing to large sizes. See
  830. `Realm.Configuration.maximumNumberOfActiveVersions` for more information.
  831. */
  832. public func freeze() -> AnyRealmCollection { return base.freeze() }
  833. }
  834. // MARK: AssistedObjectiveCBridgeable
  835. private struct AnyRealmCollectionBridgingMetadata<T: RealmCollectionValue> {
  836. var baseMetadata: Any?
  837. var baseType: _AnyRealmCollectionBase<T>.Type
  838. }
  839. extension AnyRealmCollection: AssistedObjectiveCBridgeable {
  840. internal static func bridging(from objectiveCValue: Any, with metadata: Any?) -> AnyRealmCollection {
  841. guard let metadata = metadata as? AnyRealmCollectionBridgingMetadata<Element> else { preconditionFailure() }
  842. return AnyRealmCollection(base: metadata.baseType.bridging(from: objectiveCValue, with: metadata.baseMetadata))
  843. }
  844. internal var bridged: (objectiveCValue: Any, metadata: Any?) {
  845. return (
  846. objectiveCValue: base.bridged.objectiveCValue,
  847. metadata: AnyRealmCollectionBridgingMetadata(baseMetadata: base.bridged.metadata, baseType: type(of: base))
  848. )
  849. }
  850. }
  851. // MARK: Collection observation helpers
  852. internal protocol ObservableCollection: RealmCollection {
  853. associatedtype BackingObjcCollection
  854. func isSameObjcCollection(_ objc: BackingObjcCollection) -> Bool
  855. init(objc: BackingObjcCollection)
  856. }
  857. extension ObservableCollection {
  858. // We want to pass the same object instance to the change callback each time.
  859. // If the callback is being called on the source thread the instance should
  860. // be `self`, but if it's on a different thread it needs to be a new Swift
  861. // wrapper for the obj-c type, which we'll construct the first time the
  862. // callback is called.
  863. internal typealias ObjcCollectionChange = (BackingObjcCollection?, RLMCollectionChange?, Error?) -> Void
  864. internal func wrapObserveBlock(_ block: @escaping (RealmCollectionChange<AnyRealmCollection<Element>>) -> Void) -> ObjcCollectionChange {
  865. var anyCollection: AnyRealmCollection<Element>?
  866. return { collection, change, error in
  867. if anyCollection == nil, let collection = collection {
  868. anyCollection = AnyRealmCollection(self.isSameObjcCollection(collection) ? self : Self(objc: collection))
  869. }
  870. block(RealmCollectionChange.fromObjc(value: anyCollection, change: change, error: error))
  871. }
  872. }
  873. internal func wrapObserveBlock(_ block: @escaping (RealmCollectionChange<Self>) -> Void) -> ObjcCollectionChange {
  874. var list: Self?
  875. return { array, change, error in
  876. if list == nil, let array = array {
  877. list = self.isSameObjcCollection(array) ? self : Self(objc: array)
  878. }
  879. block(RealmCollectionChange.fromObjc(value: list, change: change, error: error))
  880. }
  881. }
  882. }
  883. extension List: ObservableCollection {
  884. internal typealias BackingObjcCollection = RLMArray<AnyObject>
  885. internal func isSameObjcCollection(_ rlmArray: BackingObjcCollection) -> Bool {
  886. return _rlmArray === rlmArray
  887. }
  888. }
  889. extension Results: ObservableCollection {
  890. internal typealias BackingObjcCollection = RLMResults<AnyObject>
  891. internal func isSameObjcCollection(_ objc: RLMResults<AnyObject>) -> Bool {
  892. return objc === rlmResults
  893. }
  894. }
  895. extension LinkingObjects: ObservableCollection {
  896. internal typealias BackingObjcCollection = RLMResults<AnyObject>
  897. internal func isSameObjcCollection(_ objc: RLMResults<AnyObject>) -> Bool {
  898. return objc === rlmResults
  899. }
  900. }