Monday, March 29, 2010

Well, That's Embarrassing…

In the SuperDB application in More iPhone 3 Development, when we added multi-attribute validation, we inadvertently stopped the single-field validation on birthdate to stop working. In Hero.m, we have this at the end:

...
- (BOOL)validateForInsert:(NSError **)outError {
return [self validateNameOrSecretIdentity:outError];
}

- (BOOL) validateForUpdate:(NSError **)outError {
return [self validateNameOrSecretIdentity:outError];
}

@end

The method validateNameOrSecretIdentity: does our cross-field validation by looking at the two fields, but it doesn't do the rest of the validations, such as those from the data model, or those from custom validation methods. To handle those, we need a call to super.

The easiest way to handle this is to simply call super if validateNameOrSecretIdentity: returns NO. Typically, once we hit an error, we don't keep going. We could implement a more complex version that kept a running track of all errors and returned them, but I'm going to keep things simple here. Replace the code above with the following to get the rest of the validations working again:

...
- (BOOL)validateForInsert:(NSError **)outError {
BOOL validated = [self validateNameOrSecretIdentity:outError];
if (!validated)
return validated;
return [super validateForInsert:outError];
}

- (BOOL)validateForUpdate:(NSError **)outError {
BOOL validated = [self validateNameOrSecretIdentity:outError];
if (!validated)
return validated;
return [super validateForUpdate:outError];
}

@end

I apologize for that!



5 comments:

Rodrigo Moyle said...

in wrong, in method validateForUpdate has a call to return [super validateForInsert:outError];

Jeff LaMarche said...

Yep, fixed! Thanks.

AlBlue said...

Why not just return [self validate] && [super validate], instead of an if/if!/return combination?

Joe said...

Greetings! I see what you mean about keeping things simple and not collecting lots-o errors. I was re-re-reading NSManagedObject and happened across this li'l bit under "Validation Methods":

If you implement custom inter-property validation methods (such as validateForUpdate:), you should call the superclass’s implementation first. This ensures that individual property validation methods are also invoked. If there are multiple validation failures in one operation, you should collect them in an array and add the array—using the key NSDetailedErrorsKey—to the userInfo dictionary in the NSError object you return. For an example, see Model Object Validation.

If I understand then, normally (makes double quote signs with fingers), we'd invoke super first, _then_ call our custom validation methods … all the while possibly assembling an array of multiple (Detailed) Errors … which would then have to be parsed gracefully back in Attribute Editor land. Inneresting.

One thing I stumbled upon in the course of an attempted simplification: Let's say I remove validateForInsert: and validateForUpdate:, and just use the automagic form validateKey:error: (where Key is the attribute du jour). I end up with at least two NSDetailedErrors in the error's userInfo dict anyway. Arrgh, the best laid plans … :)

So, correct me if I'm off base here, but it looks like the best way to mitigate all of that complexity is to just keep it the way you've got it (above) and do not rely on the automagic validation methods … though they sure look rather useful. Otherwise, the error alert view would either need to show the first error, or a combo of all of them. But wouldn't that be useful too? Or is that TMI? Decisions, decisions!

h4ns said...

What youre saying is completely true. I know that everybody must say the same thing, but I just think that you put it in a way that everyone can understand. I also love the images you put in here. They fit so well with what youre trying to say. Im sure youll reach so many people with what youve got to say.

Arsenal vs Huddersfield Town live streaming
Arsenal vs Huddersfield Town live streaming
Wolverhampton Wanderers vs Stoke City Live Streaming
Wolverhampton Wanderers vs Stoke City Live Streaming
Notts County vs Manchester City Live Streaming
Notts County vs Manchester City Live Streaming
Bologna vs AS Roma Live Streaming
Bologna vs AS Roma Live Streaming
Juventus vs Udinese Live Streaming
Juventus vs Udinese Live Streaming
Napoli vs Sampdoria Live Streaming
Napoli vs Sampdoria Live Streaming
Fulham vs Tottenham Hotspur Live Streaming
Fulham vs Tottenham Hotspur Live Streaming
AS Monaco vs Marseille Live Streaming
AS Monaco vs Marseille Live Streaming
Alajuelense vs Perez Zeledon Live Streaming
Alajuelense vs Perez Zeledon Live Streaming
Technology News | News Today | Live Streaming TV Channels