对于我来说,这是一个非常间歇性的故障。我在几个罕见的场合看过它,但只有一次在开发过程中,而且仅在上个月左右。
有时,当我收到更改通知时,返回的对象数组为空,但修改列表中包含索引。
let results = realmService.getThings()
self.token = results.addNotificationBlock { changes in
switch changes {
case .initial:
break
case .update(let objects, _, _, let modifications):
// Modifications has indexes, objects is empty.
let updatedObjects = modifications
self.doSomething(for: modifications.map({ objects[$0] }))
case .error(let error):
log.error(error)
}
这是一些重现的代码。只看到这个删除。
我添加了一个UITableView和UIButtons来添加和修改。
我不明白的是,当我删除一行时,删除打印为:
(lldb) po deletions
▿ 2 elements
- 0 : 6
- 1 : 19
此代码的输出是:
Initial 20
Delete: CEB53276-03AB-4DED-9807-D5109199FB73
19 objects. Delete: 6,19
2017-06-03 16:04:00.799 RealmTest[49654:2598964] *** Terminating app due to uncaught exception 'RLMException', reason: 'Index 19 is out of bounds (must be less than 19)'
*** First throw call stack:
(
0 CoreFoundation 0x0000000106426b0b __exceptionPreprocess + 171
1 libobjc.A.dylib 0x0000000103c50141 objc_exception_throw + 48
2 Realm 0x0000000102d1de96 _ZL10throwErrorP8NSString + 646
3 Realm 0x0000000102d1a2e7 _ZL15translateErrorsIZ28-[RLMResults objectAtIndex:]E3$_3EDaOT_P8NSString + 103
4 Realm 0x0000000102d1a21e -[RLMResults objectAtIndex:] + 110
5 RealmSwift 0x0000000103605246 _TFC10RealmSwift7Resultsg9subscriptFSix + 118
6 RealmTest 0x00000001029c29bf _TFFFC9RealmTest14ViewController11viewDidLoadFT_T_U_FGO10RealmSwift21RealmCollectionChangeGCS1_7ResultsCS_5Model__T_U0_FSiS4_ + 31
7 RealmTest 0x00000001029c2a0d _TTRXFo_dSi_oC9RealmTest5ModelzoPs5Error__XFo_iSi_iS0_zoPS1___ + 45
8 RealmTest 0x00000001029c61b9 _TPA__TTRXFo_dSi_oC9RealmTest5ModelzoPs5Error__XFo_iSi_iS0_zoPS1___.56 + 89
9 libswiftCore.dylib 0x00000001059965ba _TFEsPs10Collection3mapurfzFzWx8Iterator7Element_qd__GSaqd___ + 762
10 RealmTest 0x00000001029c1856 _TFFC9RealmTest14ViewController11viewDidLoadFT_T_U_FGO10RealmSwift21RealmCollectionChangeGCS1_7ResultsCS_5Model__T_ + 2038
11 RealmSwift 0x0000000103606fff _TFFC10RealmSwift7Results20addNotificationBlockFFGOS_21RealmCollectionChangeGS0_x__T_CSo20RLMNotificationTokenU_FTGSqGCSo10RLMResultsCSo9RLMObject__GSqCSo19RLMCollectionChange_GSqPs5Error___T_ + 367
12 RealmSwift 0x00000001035ce445 _TTRXFo_oGSqGCSo10RLMResultsCSo9RLMObject__oGSqCSo19RLMCollectionChange_oGSqPs5Error____XFdCb_dGSqGS_S0___dGSqS1__dGSqCSo7NSError___ + 149
13 Realm 0x0000000102bb3195 _ZZ23RLMAddNotificationBlockIN5realm7ResultsEEP20RLMNotificationTokenP11objc_objectRT_U13block_pointerFvS5_P19RLMCollectionChangeP7NSErrorEbENKUlRKNS0_19CollectionChangeSetESt13exception_ptrE_clESG_SH_ + 741
14 Realm 0x0000000102bb2bd4 _ZN5realm24CollectionChangeCallback4ImplIZ23RLMAddNotificationBlockINS_7ResultsEEP20RLMNotificationTokenP11objc_objectRT_U13block_pointerFvS7_P19RLMCollectionChangeP7NSErrorEbEUlRKNS_19CollectionChangeSetESt13exception_ptrE_E5afterESI_ + 52
15 Realm 0x0000000102ad513a _ZN5realm24CollectionChangeCallback5afterERKNS_19CollectionChangeSetE + 58
16 Realm 0x0000000102ad50a5 _ZZN5realm5_impl18CollectionNotifier13after_advanceEvENK3$_9clINSt3__111unique_lockINS4_5mutexEEENS1_8CallbackEEEDaRT_RT0_ + 165
17 Realm 0x0000000102aaee41 _ZN5realm5_impl18CollectionNotifier17for_each_callbackIZNS1_13after_advanceEvE3$_9EEvOT_ + 273
18 Realm 0x0000000102aaed29 _ZN5realm5_impl18CollectionNotifier13after_advanceEv + 25
19 Realm 0x0000000102ab1b88 _ZN5realm5_impl15NotifierPackage13after_advanceEv + 456
20 Realm 0x0000000102e0de72 _ZN12_GLOBAL__N_126advance_with_notificationsIZN5realm5_impl11transaction7advanceERKNSt3__110unique_ptrINS1_11SharedGroupENS4_14default_deleteIS6_EEEEPNS1_14BindingContextERNS2_15NotifierPackageEE3$_0EEvSD_SB_OT_SF_ + 1586
21 Realm 0x0000000102e0d82c _ZN5realm5_impl11transaction7advanceERKNSt3__110unique_ptrINS_11SharedGroupENS2_14default_deleteIS4_EEEEPNS_14BindingContextERNS0_15NotifierPackageE + 60
22 Realm 0x0000000102b415d1 _ZN5realm5_impl16RealmCoordinator16advance_to_readyERNS_5RealmE + 913
23 Realm 0x0000000102d766ce _ZN5realm5Realm6notifyEv + 862
24 Realm 0x0000000102e3f9cb _ZNK5realm5_impl17WeakRealmNotifier8CallbackclEv + 75
25 Realm 0x0000000102e4084c _ZZN5realm4util15EventLoopSignalINS_5_impl17WeakRealmNotifier8CallbackEEC1EOS4_ENKUlPvE_clES7_ + 28
26 Realm 0x0000000102e40828 _ZZN5realm4util15EventLoopSignalINS_5_impl17WeakRealmNotifier8CallbackEEC1EOS4_ENUlPvE_8__invokeES7_ + 24
27 CoreFoundation 0x00000001063ccc01 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
28 CoreFoundation 0x00000001063b20cf __CFRunLoopDoSources0 + 527
29 CoreFoundation 0x00000001063b15ff __CFRunLoopRun + 911
30 CoreFoundation 0x00000001063b1016 CFRunLoopRunSpecific + 406
31 GraphicsServices 0x000000010bda8a24 GSEventRunModal + 62
32 UIKit 0x00000001041220d4 UIApplicationMain + 159
33 RealmTest 0x00000001029c6d37 main + 55
34 libdyld.dylib 0x0000000106aad65d start + 1
35 ??? 0x0000000000000001 0x0 + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
代码本身是:
import UIKit
import RealmSwift
class Model: Object {
dynamic var id: String = ""
dynamic var text: String = ""
override static func primaryKey() -> String? {
return "id"
}
}
class ViewController: UIViewController {
let realm = try! Realm()
var results: Results<Model>?
var token: NotificationToken!
fileprivate lazy var queue: DispatchQueue = {
return DispatchQueue(label: "realm")
}()
@IBOutlet weak var tableView: UITableView! {
didSet {
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "UITableViewCell")
}
}
override func viewDidLoad() {
super.viewDidLoad()
results = realm.objects(Model.self)
token = results?.addNotificationBlock { changes in
switch changes {
case .initial(let objects):
print("Initial \(objects.count)")
case .update(let objects, let deletions, let insertions, let modifications):
if !deletions.isEmpty {
let indexes = deletions.map({ "\($0)" }).joined(separator: ",")
print("\(objects.count) objects. Delete: \(indexes)")
print(deletions.map({ objects[$0] }))
}
if !insertions.isEmpty {
let indexes = insertions.map({ "\($0)" }).joined(separator: ",")
print("\(objects.count) objects. Insert: \(indexes)")
print(insertions.map({ objects[$0] }))
}
if !modifications.isEmpty {
let indexes = modifications.map({ "\($0)" }).joined(separator: ",")
print("\(objects.count) objects. Modify: \(indexes)")
print(insertions.map({ objects[$0] }))
}
self.tableView.reloadData()
case .error(let error):
print(error.localizedDescription)
}
}
}
@IBAction func add(_ sender: UIButton) {
let id = UUID().uuidString
print("Add: \(id)")
queue.async {
let realm = try! Realm()
let model = Model()
model.id = id
do {
try realm.write {
realm.add(model, update: true)
}
}
catch let error {
print(error.localizedDescription)
}
}
}
@IBAction func modify(_ sender: UIButton) {
guard let model = realm.objects(Model.self).first else { return }
let id = model.id
print("Modify: \(id)")
queue.async {
let r = try! Realm()
guard let object = r.object(ofType: Model.self, forPrimaryKey: id) else { return }
do {
try r.write {
object.text = "\(Date().description)"
}
}
catch let error {
print(error.localizedDescription)
}
}
}
func delete(id: String) {
print("Delete: \(id)")
queue.async {
let realm = try! Realm()
guard let object = realm.object(ofType: Model.self, forPrimaryKey: id) else { return }
do {
try realm.write {
realm.delete(object)
}
}
catch let error {
print(error.localizedDescription)
}
}
}
}
extension ViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return results!.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "UITableViewCell") else { fatalError() }
cell.textLabel!.text = results?[indexPath.row].id
return cell
}
}
extension ViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let object = results![indexPath.row]
delete(id: object.id)
}
}
加细