Luciano Nascimento Luciano Nascimento - 6 months ago 56
Objective-C Question

Error: Object has been deleted or invalidated. (Realm)

Sometimes (rarely but occurs) I got error

Object has been deleted or invalidated.
, when trying to modify my model object with a property or inside AFnetworking Block. Can anyone help me to find what I'm doing wrong?




Error - Case 1:

Code:

- (void)myFunction {
Model *model = [Model objectForPrimaryKey:1];

if (model) {
[self updateModel:model];
}
}

- (void)updateModel:(Model *)model {

AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[manager PUT:@"http://www.example.com" parameters:parameters success:^(AFHTTPRequestOperation *operation, id responseObject) {

[[RLMRealm defaultRealm] beginWriteTransaction];
model.updated = YES; // Crash: Object has been deleted or invalidated.
[[RLMRealm defaultRealm] commitWriteTransaction];

} failure:nil];
}





Error - Case 2:

Property:

@property (strong, nonatomic) Model *model;


Code:

- (void)myFunction {
Model *model = [Model objectForPrimaryKey:1];

if (model) {
self.model = model;

UIAlertView * alert = [[UIAlertView alloc] initWithTitle:@"" message:@"Would you like to edit the model?" delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"Ok", nil];
[alert show];
}
}


UIAlertView Delegate:

- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
if (buttonIndex == 1) {
[[RLMRealm defaultRealm] beginWriteTransaction];
self.model.updated = YES; // Crash: Object has been deleted or invalidated.
[[RLMRealm defaultRealm] commitWriteTransaction];
}
}


Thanks.

Answer

As for example 1 the network request is executed asynchronous on a different operation queue and calls back to the main thread, it's very likely that you have some code in place, which can be triggered meanwhile by a user action and delete the object concurrently. The model object reference you're holding will be automatically updated and reflect the deletion. Because a deleted object can't be modified it comes to the error.

Also example 2 involves concurrency. Your code retrieves the model object first, then it shows the alert view. While the UIAlertView is shown, the main thread is not blocked. Theoretically at the same time, a network operation enqueued before could finish, the completion block could be dispatched, a deletion of the model object occurs. The user confirms the modifications. Your implementation of the delegate is called, but expects the previously retrieved object to be still existing.

One possibility to avoid the crashes is to store just a primary key instead of a full model object reference, which would keep updating and reflecting recent changes. The primary key will stay constant and should always be able to identify your object. You can then use the primary key later to retrieve the object directly in your write transaction.

Note that it will be in any case up to you to define how your app behaves, if your data was modified concurrently. You can try to recreate the object, by keeping more data in copy around, or ignore the event and let the delete win, or make sure that there won't happen conflicting modifications by restricting the UI adequately. You have to come up with a conflict resolution strategy.