Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Realm addNotificationBlock returning error #4693

Closed
tuomijal opened this issue Feb 23, 2017 · 8 comments
Closed

Realm addNotificationBlock returning error #4693

tuomijal opened this issue Feb 23, 2017 · 8 comments

Comments

@tuomijal
Copy link

tuomijal commented Feb 23, 2017

Goals

I am trying to instantiate a NotificationToken to listen to changes in a specific property of my Realm objects. The goal is to display every object matching the query in viewController.

Expected Results

The variable called 'location' in my Realm objects is changed by a helper method which is triggered by a Timer instance. When 'location' property is changed to value 2, I expect the Realm to notify the notificationToken object about the change allowing me to push the new result to viewController.

Actual Results

Immediately after launching the app, addNotificationBlock method returns the following error:
Error Domain=io.realm Code=1 "std::exception" UserInfo={NSLocalizedDescription=std::exception, Error Code=1}
Notifications are not listened after this. (Which is of course the way this enumeration is supposed to work.) I opened a thread on StackOverflow and based on given instructions managed to setup a breakpoint which pointed to method called void RealmCoordinator::pin_version(VersionID versionid)

Steps to Reproduce

It is difficult to say how to reproduce this error since I am (as far as I'm concerned) using the addNotificationBlock as instructed and not trying to accomplish anything complicated. I am happy to deliver the full Xcode workspace if necessary.

Code Sample

The contents of my viewController:

import UIKit
import RealmSwift

class PatientCell: UITableViewCell {
    
    @IBOutlet weak var hetu: UITextView!
    @IBOutlet weak var name: UITextView!
    @IBOutlet weak var photo: UITextView!
    
}

class PäivystyslistaVC: UIViewController, UIScrollViewDelegate, UITableViewDelegate, UITableViewDataSource, UIPopoverControllerDelegate {
    
    @IBOutlet weak var tableView: UITableView!
    @IBOutlet var patientPopupView: UIView!
    
    var patients: Results<Patient2>!
    var realm = try! Realm()
    var timer: Timer!
    var notificationToken: NotificationToken? = nil
    
    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.dataSource = self
        tableView.delegate = self
        let realm = try! Realm()
        patients = realm.objects(Patient2.self).filter("location = 2")
        
        print("Patients on the ER: \(patients)")
        
        notificationToken = patients.addNotificationBlock { (changes: RealmCollectionChange) in
            switch changes {
            case .initial:
                print("From initial")
                break
            case .update:
                print("From update")
                break
            case .error(let err):
                print("Error occured \(err)")
                break
            }
        }
        
        timer = Timer.scheduledTimer(timeInterval: 10, target: self, selector: #selector(self.addPatient), userInfo: nil, repeats: true)
    }
    
    func addPatient() {
        print("")
        print("Timer launched")
        print("Patients on the ER: \(patients.count)")
        sendPatientToER()
        print("")
        tableView.reloadData()
    }
    
    
    
    // MARK: TableView:n hallinta
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return patients.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "patient", for: indexPath) as! PatientCell
        
        let patient = patients[indexPath.row]
        cell.hetu?.text = patient.hetu
        cell.name?.text = patient.fullName
        cell.photo?.text = patient.photo
        
        return cell
        
    }
    
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        let potilastiedotVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "PotilastiedotVC")
        self.present(potilastiedotVC, animated: true, completion: nil)
        
        tableView.deselectRow(at: indexPath, animated: true)
    }
    
    func tableView(_ tableView: UITableView, editActionsForRowAt: IndexPath) -> [UITableViewRowAction]? {
        let kotiuta = UITableViewRowAction(style: .normal, title: "Kotiuta") { action, index in
            try! self.realm.write {
                self.realm.create(Patient2.self, value: ["id": index.row, "location": 1], update: true)
            }
            self.tableView.deleteRows(at: [index], with: .left)
            
        }
        kotiuta.backgroundColor = UIColor.vihreä
        
        let osastolle = UITableViewRowAction(style: .normal, title: "Osastolle") { action, index in
            try! self.realm.write {
                self.realm.create(Patient2.self, value: ["id": index.row, "location": 3], update: true)
            }
            self.tableView.deleteRows(at: [index], with: .top)
        }
        osastolle.backgroundColor = UIColor.oranssi
        
        let lähetä = UITableViewRowAction(style: .normal, title: "Lähetä") { action, index in
            try! self.realm.write {
                self.realm.create(Patient2.self, value: ["id": index.row, "location": 3], update: true)
            }
            self.tableView.deleteRows(at: [index], with: .top)
        }
        lähetä.backgroundColor = UIColor.vaaleansininen
        
        return [kotiuta, lähetä, osastolle]
    }

In addition I have a helper method in another file:

import UIKit
import RealmSwift

func sendPatientToER() {
    let realm = try! Realm()
    let count = realm.objects(Patient2.self).filter("location == 1").count
    print("Count of patients waiting at home: \(count)")
    let randomId = Int(arc4random_uniform(UInt32(count)))
    print("Random id generated: \(randomId)")
    realm.beginWrite()
    realm.create(Patient2.self, value: ["id": randomId, "location": 2], update: true)
    try! realm.commitWrite()
}

Thank you in advance.

Version of Realm and Tooling

Realm version: 2.4.2

Xcode version: 8.2.1

iOS/OSX version: 10.12.3

Dependency manager + version: Cocoapods 1.1.1

@karapigeon
Copy link

Hi @EmilOsvald. Thanks for reaching out about this. My apologies for the delay in getting back to you. I'll have one of the engineers look at this and follow-up with a solution or additional questions.

@bdash bdash assigned tgoyne and unassigned bdash Feb 24, 2017
@tgoyne
Copy link
Member

tgoyne commented Feb 27, 2017

There's nothing particularly suspicious in the code you've posted. If you're willing to share the full project I'd be happy to dig into it, as the function that's throwing is something that shouldn't be able to fail.

@tuomijal
Copy link
Author

Hi @tgoyne, thank you for your input and sorry for the delay. I cleared the decks and everything works in my refactored project like a charm. I suppose the problem was that I had done some rookie mistake in my code (as I had suspected). Would you nevertheless like to see the original version?

@tgoyne
Copy link
Member

tgoyne commented Mar 15, 2017

Yes, that'd still be helpful. Even if you did only hit problems due to a mistake on your end, you still hit a case where Realm isn't behaving properly and it'd be good to be able to fix that.

@TimOliver
Copy link
Contributor

Hey @EmilOsvald! Just checking in on this issue. Would you be able to provide us with a copy of the original version of your project for us to analyse? Thanks a lot!

@tuomijal
Copy link
Author

Hi @TimOliver. I went through all my previous app versions on Git but unfortunately the version of interest seems to be lost. I am sorry.

@TimOliver
Copy link
Contributor

@EmilOsvald Ahh okay. No problems then! It can't be helped. If you do manage to find the issue again, please let us know! Thanks!

@hons82
Copy link

hons82 commented Sep 24, 2019

I know this issues quite old and probably not interesting anymore, I was struggling however with the same problem for quite a while now and I'd like to share my findings.
In my case it happened after a bulk delete. Whenever a user does a logout I have to clear some of my tables

- (void)deleteSecureContent:(RLMRealm *)realm {
    NSError *error;
    NSArray *array = [realm.schema.objectSchema valueForKey:@"className"];
    [realm transactionWithBlock:^{
        for(NSString *className in array){
            Class<VLProtectedEntity> realmClass = NSClassFromString(className);
            if(realmClass && [[realmClass class] respondsToSelector:@selector(isProtectedEntity)]){
                BOOL protected = [[realmClass class] isProtectedEntity];
                if(protected){
                    [realm deleteObjects:[[realmClass class] allObjectsInRealm:realm]];
                }
            }
        }
    } error: &error];
    [realm refresh];
    if (error) {
        DDLogError(@"error %@ deleteSecureContent",error);
        [[Crashlytics sharedInstance] recordError:error];
    }
}

This is already the working version of the code. The important row in this case was the call to refresh the realm. Without that I had exactly the same error.
It's probably important to say that I'm working with two realms in this project one is persistent and one is in-memory and only the latter, so the in-memory instance did suffer from this problem.

I'm on Realm (3.18.0)

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Mar 15, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

9 participants