Validating Data with TWTValidation

A few months ago, Andrew and I were working on a project that required some validation of model objects and form data. After looking around a bit, we quickly came to the conclusion that there aren’t any widely accepted best practices for data validation in Cocoa. If you’re using Core Data, you can declare some validators for strings and numbers in your data model. If you’re not, you have to roll your own validation system, perhaps using Key-Value Validation (KVV), a part of Foundation that many experienced Cocoa developers have never even heard of.

There’s a huge gap between these two options. Core Data’s managed object validation is declarative: you don’t describe how to perform validation, you just declare what validations need to take place. Key-Value Validation is the exact opposite: you override ‑validateValue:​forKey:​error: (or ‑validate«Key»:​error:) and write the code that actually performs the validations. What we set out to do was to bring the simplicity and clarity of Core Data’s declarative approach to non-Core Data classes. We think we’ve done that with TWTValidation.

TWTValidation

TWTValidation is a Cocoa framework that allows you to easily validate data with reusable validator objects, each of which is a subclass of TWTValidator. The common interface for all validators is a single method: ‑validateValue:​error:. This method returns whether a given value is valid and, if not, indirectly returns an error describing why validation failed. With just this simple interface, we’ve been able to build some pretty interesting validators. While going over each of them would take too much time, here’s a brief summary:

  • Value validators can validate that a value is of a particular class. They can also optionally allow for values that are nil or the NSNull instance.
    • Number validators can check if a number is within a given range. You can also optionally require that a value be an integer.
    • String validators are value validators that validate strings. There are a variety of string validators for doing things like checking the length of a string or validating that it matches a particular pattern.
  • Compound validators allow you to combine multiple validators using logical operators like AND, OR, and NOT.
  • Collection validators validate the count and elements of arrays and sets.
  • Keyed collection validators validate the count, keys, values, and specific key-value pairs for dictionaries and map tables.
  • Block validators allow you to easily create a TWTValidator with custom validation logic using a block.

These validators are incredibly useful—see the [TWTValidation readme][Readme] for code examples—and fundamentally important to any use of TWTValidation, but my favorite class in the framework is TWTKeyValueCodingValidator.

Key-Value Coding Validators

Key-value coding (KVC) validators validate an object using validators that the object itself provides. Each KVC validator is initialized with a set of KVC keys.

NSSet *keys = [NSSet setWithObjects:@"property1", @"property2", nil];
TWTKeyValueCodingValidator *validator = [[TWTKeyValueCodingValidator alloc] initWithKeys:keys];

Later, when the validator validates an object, it iterates over each key in its key set, gets the object’s value for that key (using ‑valueForKey:), gets the object’s validators for that key, and then validates the key’s value. In pseudo-code, this looks like:

for (NSString *key in self.keys) {
    id value = [object valueForKey:key];

    // Get validators from object somehow
    NSSet *validators = … ;

    // Run the validators on value, accumulating and returning any errors
}

How does it get object’s validators for a key? TWTKeyValueCodingValidator declares an informal protocol containing the method +twt_validatorsForKey:, which classes can override to return the set of TWTValidator objects for a given KVC key. For example,

+ (NSSet *)twt_validatorsForKey:(NSString *)key
{
    if ([key isEqualToString:@"property1"]) {
        // Create and return an NSSet containing the validators for property1
    } else if ([key isEqualToString:@"property2"]) {
        // Create and return an NSSet containing the validators for property2
    }

    // Otherwise, ask the superclass
    return [super twt_validatorsForKey:key];
}

Unfortunately, cascading if-else statements like this are sort of gross, particularly when you have a lot of keys you want to validate. We remedy this by borrowing a simple pattern from Key-Value Coding, Key-Value Observing, and Key-Value Validation. The base implementation of +twt_validatorsForKey: checks to see if the receiver responds to +twt_validatorsFor«Key», where «Key» is the capitalized form of the key parameter. If so, we simply return the result of that method; otherwise, we returns nil. Knowing this, we can now simplify the cascading if-else into:

+ (NSSet *)twt_validatorsForProperty1
{
    // Create and return an NSSet containing the validators for property1
}

+ (NSSet *)twt_validatorsForProperty2
{
    // Create and return an NSSet containing the validators for property2
}

To my eyes, this is a lot clearer. Basically, if you implement these methods, validation of the property1 and property2 keys will just work. Any other keys will not be validated, i.e., they will implicitly pass, because you haven’t declared any validators for them.

Let’s walk through a complete example just to drive this whole idea home.

Example: Validating a User Object

For our example, we’ll create a simple class that models users for some imaginary online service.

@interface TWTUser : NSObject

@property (nonatomic, strong) NSNumber *ID;
@property (nonatomic, strong) NSString *fullName;
@property (nonatomic, copy) NSString *username;

@end

User IDs must be positive integers. Full names must be strings between 0 and 64 characters long. Usernames must only contain alphanumeric characters and '_' and must be between 1–15 characters long. To work with TWTKeyValueCodingValidators, we need to implement +twt_validatorsForID, +twt_validatorsForUsername, and +twt_validatorsForFullName. Let’s get to it.

Validating the ID is really simple. We just need to create a number validator that allows a minimum value of 1, no maximum, and requires integral values:

@implementation TWTUser

+ (NSSet *)twt_validatorsForID
{
    TWTNumberValidator *validator = [[TWTNumberValidator alloc] initWithMinimum:@1 maximum:nil];
    validator.requiresIntegralValue = YES;
    return [NSSet setWithObject:validator];
}

@end

Easy enough. Validating full names is very similar. We just need a string validator with a minimum length of 0 and a maximum length of 64. We’ll go ahead and allow nil for good measure.

+ (NSSet *)twt_validatorsForFullName
{
    TWTStringValidator *validator = [TWTStringValidator stringValidatorWithMinimumLength:0 maximumLength:64];
    validator.allowsNil = YES;
    return [NSSet setWithObject:validator];
}

Validating usernames is only slightly trickier. TWTValidation has support for validating strings using a regular expression. We can express the validation rule for usernames with the (unescaped) regular expression ^\w{1,15}$. This pattern only matches strings that are composed of 1–15 alphanumeric or underscore characters.

+ (NSSet *)twt_validatorsForUsername
{
    NSRegularExpression *usernameExpression = [[NSRegularExpression alloc] initWithPattern:@"^\\w{1,15}$"
                                                                                   options:0
                                                                                     error:NULL];

    TWTStringValidator *validator = [TWTStringValidator stringValidatorWithRegularExpression:usernameExpression
                                                                                     options:0];
    return [NSSet setWithObject:validator];
}

Okay, so we have our validators declared. Now we just need to actually perform validation. Let’s add an ‑isValid method to TWTUser for that purpose. Internally, it will use a KVC validator to actually perform the validation. We’ll store that in an internal property.

@interface TWTUser ()
@property (nonatomic, strong) TWTKeyValueCodingValidator *objectValidator;
@end


@implementation TWTUser

- (instancetype)init
{
    self = [super init];
    if (self) {
        NSSet *keys = [NSSet setWithObjects:@"ID", @"fullName", @"username", nil];
        _objectValidator = [[TWTKeyValueCodingValidator alloc] initWithKeys:keys];
    }

    return self;
}

// ...

@end

Finally, we can implement ‑isValid:

- (BOOL)isValid
{
    return [self.objectValidator validateValue:self error:NULL];
}

And that’s it.

There are some important things to point out about our implementation. First, while we have our own private KVC validator, other KVC validators can be used as well. This might be desirable if you only wanted to validate the user’s username and ID, but not its full name.

We also aren’t limited to performing validation internally. If you have a controller that needs to perform some validation on a different key set, it can do that using its own KVC validator, which will still get the appropriate validators from the TWTUser object.

Finally, KVC validators can co-exist with KVV. For example, suppose that we didn’t implement +twt_validatorsForFullName and instead had an equivalent KVV method:

- (BOOL)validateFullName:(NSString **)ioValue error:(NSError **)outError
{
    if (!*ioValue || ([*ioValue isKindOfClass:[NSString class]] && [*ioValue length] <= 16)) {
        return YES;
    } else if (outError) {
        // Construct an NSError and assign it to outError
    }

    return NO;
}

When the KVC validators finds that you have no validators declared for fullName, it falls back on key-value validation to do its work. In other words, everything just works. This can be useful if you want to transition your code from KVV to TWTValidation.


So, that’s a taste of TWTValidation. We think it’s a great approach to doing data validation in Cocoa. We’ve only covered a small part of the framework, so read the docs and take a look at our GitHub project page. We’re also hard at work on the next release of TWTValidation, so be on the lookout for some updates in the next couple of weeks. If you have any questions or ideas for new validators, I’m @prachigauriar on Twitter!

Using Auto Layout with Interface Builder

I’ll admit it, I was an Interface Builder hater. In the past everything I did was in code: Auto Layout, custom views, custom cells, everything. The frustrations of Xcode 4’s implicit constraint generation made using Auto Layout difficult. Going to code was far simpler.

Continue reading “Using Auto Layout with Interface Builder” »

Good Documentation

Every day I find myself relying on well documented code to work efficiently and productively. Good documentation helps me understand what a class or method does, what it was created for, or what that other developer was thinking when they wrote the module my code hinges on. Unfortunately, I have a history of preferring to read good documentation much more than I’ve preferred writing it, often because it seems too difficult and time consuming.

Lately however, I’ve been working on writing better documentation, and I’ve found it’s much easier than I expected. In this article, I’ll share some tips to help you document your own code more quickly and easily. We’ll look at what makes or breaks documentation, in which cases it is most vital, and what my process is for writing better docs.

Continue reading “Good Documentation” »

Solving the Massive Storyboard Problem

At Two Toasters, we’ve been building iOS interfaces in code for years. Every so often, someone will suggest that we try using Interface Builder and storyboards, but we’ve traditionally found the experience to be frustrating and unproductive. The tools seemed immature and cumbersome, and with all of our experience building UIs by hand, it never really seemed like a worthy undertaking.

Over the last year though, things have begun to change. There were signs at WWDC 2013 that Apple was putting serious effort into improving storyboards and Interface Builder. A few weeks ago, Apple introduced Adaptive Layout and Size Classes in the iOS 8 SDK, and Xcode 6 features many improvements that aim squarely to address the complaints that people have had about Interface Builder. Apple clearly believes Interface Builder and storyboards are a viable tool for building UIs more productively and efficiently.

Continue reading “Solving the Massive Storyboard Problem” »

Better Class Variables with Settings Objects

What a week! WWDC 2014 was chock full of exciting news for developers, and we at Two Toasters ate it up. We’re super excited about extensions, custom keyboards, Hand-off, size classes, and of course Swift. There’s a lot to digest, but rest assured that we’ll be discussing iOS 8’s new APIs and technologies here in the coming weeks and months.

Today though, we’re going to discuss a really simple design pattern that works around one of Objective-C’s shortcomings: the lack of class variables. When we started working on URLMock, we found ourselves in a bind. Because of NSURLProtocol’s architecture, URLMock’s primary interface is the UMKMockURLProtocol class itself, not instances of it. To add an expected mock request, you have to use +expectMockRequest:; to verify that your URL code is working as expected, you have to use +verifyWithError:. This means that all our bookkeeping data—whether URLMock is enabled, whether verification is enabled, what mock requests are expected, which unexpected requests have been received, etc.—have to be stored at the class level.

Continue reading “Better Class Variables with Settings Objects” »

Translating Autoresizing Masks Into Constraints

Auto Layout has been a great improvement to the layout system on iOS. It allows expressing layout rules more explicitly and reduces the need for custom layout logic. I especially appreciate that you can mix Auto Layout with manual layout in cases where setting a view’s frame expresses the intended behavior more clearly.

Continue reading “Translating Autoresizing Masks Into Constraints” »

NSProxy, NSObject’s Lesser-Known Sibling

When we were testing URLMock, one of the first things we needed to verify was that we were sending the appropriate messages to NSURLConnection delegates. URLMock can send response data in multiple chunks, so we needed to check that certain delegate messages were received multiple times, while others were received once or not at all.

Continue reading “NSProxy, NSObject’s Lesser-Known Sibling” »

NSNumberFormatter and Objective-C Types

On a recent project, I ran into some very unexpected behavior with NSNumberFormatter. I was working with an API that delivered price information in cents. The price needed to be displayed in dollars. I decided to store the value in cents to maintain consistency with the API and to use NSNumberFormatter to generate the string for the UI. It seemed like a great solution.

Continue reading “NSNumberFormatter and Objective-C Types” »