Note that there are some explanatory texts on larger screens.

plurals
  1. POCoreData - How to use validateForDelete: to determine if a managed object should be deleted
    text
    copied!<p><strong>Goal:</strong> I want to check a managed object to make sure that it is okay for deletion</p> <p><strong>Expectation:</strong> <code>-[NSManagedObject validateForDelete:]</code> should return a <code>BOOL</code> based on the delete rules setup in the managed object model</p> <p><hr></p> <h1>NSManagedObject Class Reference</h1> <blockquote> <p>validateForDelete:</p> <p>Determines whether the receiver can be deleted in its current state.</p> <p><code>- (BOOL)validateForDelete:(NSError **)error</code></p> <p><strong>Parameters</strong></p> <p><em>error</em></p> <p>If the receiver cannot be deleted in its current state, upon return contains an instance of NSError that describes the problem.</p> <p><strong>Return Value</strong></p> <p><code>YES</code> if the receiver can be deleted in its current state, otherwise <code>NO</code>.</p> <p><strong>Discussion</strong></p> <p>An object cannot be deleted if it has a relationship has a “deny” delete rule and that relationship has a destination object.</p> <p><code>NSManagedObject</code>’s implementation sends the receiver’s entity description a message which performs basic checking based on the presence or absence of values.</p> </blockquote> <p>Reading this I assume that I should be able to do something like this:</p> <pre><code>BOOL canDelete = [myManagedObject validateForDelete:&amp;error]; if (canDelete) { [managedObjectContext deleteObject:myManagedObject]; } else { [self requestUserFeedback]; } </code></pre> <p>However, this method almost always returns <code>NO</code>.</p> <p><hr></p> <h1>Example Code</h1> <p><em>Managed Object Model</em> </p> <pre><code>Department - Attribute: name - Value: String - Relationship: employees - To Many - Destination: Employee - Delete Rule: Nullify - Inverse: department Employee - Attribute: name - Value: String - Relationship: department - To One - Destination: Department - Delete Rule: Nullify - Inverse: employees </code></pre> <p>Example Code:</p> <pre><code>NSManagedObject *department = [NSEntityDescription insertNewObjectForEntityForName:@"Department" inManagedObjectContext:self.managedObjectContext]; for (int i = 0; i &lt; 10; i++) { NSManagedObject *employee = [NSEntityDescription insertNewObjectForEntityForName:@"Employee" inManagedObjectContext:self.managedObjectContext]; [employee setValue:department forKey:@"department"]; if ([employee validateForDelete:NULL]) { NSLog(@"Can delete employee"); } else { NSLog(@"WARNING: Cannot delete employee"); } } NSError *error; BOOL canDelete = [department validateForDelete:&amp;error]; if (canDelete) { NSLog(@"Can delete department"); } else { NSLog(@"WARNING: Cannot delete department"); } </code></pre> <p>Output:</p> <blockquote> <p>Can delete employee<br> Can delete employee<br> Can delete employee<br> Can delete employee<br> Can delete employee<br> Can delete employee<br> Can delete employee<br> Can delete employee<br> Can delete employee<br> Can delete employee<br> WARNING: Cannot delete department </p> </blockquote> <p>To my surprise, <code>canDelete</code> is <code>NO</code>. Why would the department object be invalid for deletion when the employee objects are not invalid? The error returned contains the following (abbreviated)</p> <pre><code>Error Domain=NSCocoaErrorDomain Code=1600 UserInfo= &lt;&gt;{ NSValidationErrorObject=&lt; department object &gt; NSValidationErrorKey=employees NSValidationErrorValue=Relationship 'employees' on managed object } </code></pre> <p>So, <code>validateForDelete:</code> is not returning what I expect for to-many relationships, but does return the expected value for to-one relationships. But, go back to the documentation for a second:</p> <blockquote> <p>An object cannot be deleted if it has a relationship has <em>[sic]</em> a “deny” delete rule and that relationship has a destination object.</p> <p>NSManagedObject’s implementation sends the receiver’s entity description a message which performs basic checking based on the presence or absence of values.</p> </blockquote> <p>This calls out how the default implementation of validateForDelete: works and makes a concerted effort to draw attention to the "deny" delete rule. There is no mention of nullify or cascade delete rules or differences between to-one or to-many relationships.</p> <p><hr></p> <h1>Further Research</h1> <p>A Google search turns up <a href="http://lists.apple.com/archives/cocoa-dev/2009/Mar/msg00888.html" rel="nofollow">this hit on the Apple Mailing List archives from 2009</a>, which basically says: <code>-[NSManagedObject validateForDelete:]</code> is a hook for subclassers, you need to implement your own logic in a separate method to determine if an object is valid for deletion.</p> <p>What? Is this true? That's not what the documentation for this method would lead one to believe:</p> <blockquote> <p>Determines whether the receiver can be deleted in its current state.</p> </blockquote> <hr> <p><strong>How are we suppose to check if a managed object is in a state that is okay for deletion?</strong></p> <p>I've set up a small sample project on <a href="https://github.com/evandelaney/StackOverflow-20722804" rel="nofollow">GitHub</a> that illustrates my findings with both production code and unit tests.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload