0

I tried to debug and trace what line the error occur , and I found out the error occur after reading the print(tcb_filteredArray) and I tried to put the print(tcb_filteredArray) below the self.tableView.reloadData() and make a debug and trace it again and it still error occur in print(tcb_filteredArray)

My search filtering code

        let realm = try! Realm()
        let tcb = realm.objects(TrialCourtBranches.self)
        let tcb_safe = ThreadSafeReference(to: tcb)
        DispatchQueue.global(qos: .userInitiated).sync {
            guard let filtered = realm.resolve(tcb_safe) else{ return }
            tcb_filteredArray = filtered.filter({ $0.branch_name.lowercased().contains(searchText.lowercased()) || ($0.loc?.pc?.province.lowercased().contains(searchText.lowercased()))! || ($0.loc?.pc?.city_municipality.lowercased().contains(searchText.lowercased()))! || $0.office_no.lowercased().contains(searchText.lowercased())})
            DispatchQueue.main.async {
                self.tableView.reloadData()
            }
        }
jpcarts23
  • 468
  • 9
  • 16

2 Answers2

4

Realm objects, by default, can only be accessed from the thread on which they are created. So your array of filtered objects, created on a background thread, cannot be accessed straightforwardly on the main thread.

Realm offers a couple of solutions to this - see this blog post for further details.

The post describes a few ways of solving the problem:

  1. Create (an) unmanaged Realm object(s) containing the relevant data (the problem occurs only with objects backed by a realm).
  2. Read the data out into a variable with a thread safe type (e.g. string, int etc)
  3. Use the new ThreadSafeReference class - with the following steps:

    • Create a reference in the original thread:
      let personRef = ThreadSafeReference(to: person)

      (where person is a Realm backed object)

    • Inside the second thread block, resolve the reference:

       let realm = try! Realm()
       guard let person = realm.resolve(personRef) else {
         return // person was deleted
       } 
      

You'll need to wrap each of the items in your array in a ThreadSafeReference if you go down this route.

Rich Tolley
  • 3,812
  • 1
  • 30
  • 39
  • i will try this sir @Rich Tolley – jpcarts23 Feb 03 '18 at 01:56
  • I edited my code please have a look at top, there's an error @Rich Tolley – jpcarts23 Feb 03 '18 at 02:06
  • @jpcarts23 Looks like you're passing the original collection into the `ThreadSafeReference`, and not the filtered output, so you have a type mismatch. Not sure what types the `ThreadSafeReference` can wrap - you may need to use a map to wrap each realm object ref individually and then unwrap them on the other side – Rich Tolley Feb 03 '18 at 02:10
  • edited post again , please have a look , still not match @Rich Tolley – jpcarts23 Feb 03 '18 at 02:13
  • something like `let tcbSafeArray = tcbFilteredArray.map { ThreadSafeReference(to: $0) }`, then individually unwrap them. Also you have a missing `let` in the main thread block `guard` – Rich Tolley Feb 03 '18 at 02:15
  • @jpcarts23 You shouldn't need to wrap the array itself - you've already wrapped each object in it. Try passing `tcbSafeArray` into the block and then iterate or `map` over it and unwrap each object individually, i.e. the reverse of what you did in the first `map` – Rich Tolley Feb 03 '18 at 02:29
  • I don't know what to pass and where to pass the variables – jpcarts23 Feb 03 '18 at 02:57
1

This is the correct answer

searchBar.rx.text.orEmpty.debounce(0.3, scheduler: MainScheduler.instance)
        .distinctUntilChanged()
        .filter { !$0.isEmpty }
        .observeOn(MainScheduler.instance)
            .subscribe(onNext: { (data) in
                let realm = try! Realm()
                let tcb = realm.objects(TrialCourtBranches.self)
                let predicate = NSPredicate(format: "(branch_name CONTAINS[c] %@) OR (office_no CONTAINS[c] %@) OR (loc.pc.city_municipality CONTAINS[c] %@) OR (loc.pc.province CONTAINS[c] %@) OR (loc.address1 CONTAINS[c] %@)",data.lowercased(),data.lowercased(),data.lowercased(),data.lowercased(),data.lowercased())
                tcb_filteredArray = tcb.filter(predicate)
                self.tableView.reloadData()
            }, onError: { (errorResult) in
                print(errorResult)
            }, onCompleted: {
                print("onCompleted")
            }, onDisposed: {
                print("onDisposed")
            })
        .disposed(by: bag)
jpcarts23
  • 468
  • 9
  • 16