Walking Smarts

WSCoreLaziness

From time to time I often find myself repeating certain small amounts of code which consists of a few lines. In the beginning it was ok, since I didn’t mind it because of my lack of experience in Cocoa coding. Afterwards it got really annoying. Coming from Ruby (and Rails) background I remembered how awesome it was to have ActiveSupport around. It had so many helpful classes and functions that would improve developers’ productivity and clear up the code!

WSCoreLaziness is a shot at making ActiveSupport for Cocoa frameworks. The idea is simple - create a collection of (as of this writing) Foundation framework categories that aim to shorten the amount of your typing and increase the amount of hitting Esc and Tab keys, provide familiar API and sensible defaults.

The framework is being developed using TDD using standard SenTestingKit.framework that comes together with Xcode.

Installation

Installation process is pretty much the same as for any other framework out there (Sparkle, Growl anyone?) except it does not require any framework specific tweaks. Here’s how I do it:

  1. Copy the WSCoreLaziness.framework bundle to $(SRCROOT)/Frameworks.
  2. Add the bundle (or whole Frameworks directory) to Xcode project (⌘+⌥+A, drag’n’drop or right-click and “Add files to project…”).
  3. Add “Copy files” build phase right before the “Link Binary With Libraries” phase. Make sure framework is added there as well as operation’s destination is set to Frameworks.
  4. Link your project with WSCoreLaziness.framework by adding it to “Link Binary With Libraries” phase.
  5. Add the import statement to your Prefix.pch file: #import "WSCoreLaziness/WSCoreLaziness.h".

General convention

Since the classes I write categories for are not owned, every method is prefixed with ws_. It’s recommended practice. Although it makes code look a bit uglier, but it’s better to be safe than sorry.

What’s covered

There are very few methods currently. Since the documentation is yet to be written, here are the classes with their respective methods:

  • NSString
    • - (BOOL)ws_stringIsEmpty - returns YES if string is equal to @"". Otherwise returns no;
    • - (BOOL)ws_stringIsBlank - returns YES if string empty or it contains only whitespace characters (" ", \n and \t);
  • NSArray
    • - (void)ws_enumerateObjectsWithIndexesUsingBlock:(void (^)(id, NSInteger))block; - iterates through array with passed in block which receives object and it’s index.
    • - (id)ws_selectObjectUsingBlock:(BOOL (^)(id))block; - returns object that makes passed in block return YES;
    • - (NSInteger)ws_integerValueAtIndex:(NSInteger)integer; - returns NSInteger value for an object at index. Useful for arrays consisting of NSNumbers. Returns 0 if object does not respond to integerValue;
    • - (CGFloat)ws_floatValueAtIndex:(NSInteger)integer; - returns CGFloat value for an object at index. Useful for arrays consisting of NSNumbers. Returns 0.0f if object does not respond to floatValue;
    • - (NSString *)ws_stringValueAtIndex:(NSInteger)integer; - returns stringValue for an object at index. Useful for arrays consisting of NSNumbers and other objects. If object does not respond to stringValue, description method is being called;
  • NSMutableArray
    • - (void)ws_mapEachObjectUsingBlock:(id (^)(id))block - replaces each object of array by an object returned from the block;
  • NSDictionary
    • - (NSArray *)ws_sortedKeysUsingDescriptors:(NSArray *)sortDescriptors; - returns array of sorted keys using passed in descriptors;
    • - (NSArray *)ws_sortedValuesUsingDescriptors:(NSArray *)sortDescriptors; - returns array of sorted values using passed in descriptors;
    • - (NSInteger)ws_integerValueForKey:(NSString *)key; - returns NSInteger for given key. Useful for dictionaries having keys with NSNumber values. Returns 0 if object does not respond to integerValue;
    • - (CGFloat)ws_floatValueForKey:(NSString *)key; - returns CGFloat for given key. Useful for dictionaries having keys with NSNumber values. Returns 0.0f if object does not respond to floatValue.
    • - (NSString *)ws_stringValueForKey:(NSString *)key; - returns stringValue for given key. Useful for dictionaries with NSNumbers and other type values. If object does not respond to stringValue, description is being called instead.
  • NSMutableDictionary
    • - (void)ws_updateValueForKey:(NSString *)key usingBlock:(id (^)(id, NSString *))block; - modifies value at given key by using returned object from provided block which accepts existing value;
    • - (id)ws_extractValueForKey:(NSString *)key; - returns and removes object at given key;

Framework’s file structure

Each framework should have it’s own directory. In directory of a framework, files named NSClass+WSCoreLaziness.h and NSClass+WSCoreLaziness.m should reside showing that NSClass has a category from WSCoreLaziness. Since it’s very fresh and has less than 20 methods it has only categories for most generic Cocoa classes like NSString, NSArray, NSDictionary and their mutable children. Same goes for tests covering the aforementioned categories. Here’s the outline of a framework having foundation classes extended with categories:

  • /WSCoreLaziness
    • /Foundation
      • /NSString+WSCoreLaziness.h
      • /NSString+WSCoreLaziness.m
      • /NSArray+WSCoreLaziness.h
      • /NSArray+WSCoreLaziness.m
  • /WSCoreLazinessTest
    • /Foundation
      • /NSStringWSCoreLazinessTest.h
      • /NSStringWSCoreLazinessTest.m
      • /NSArrayWSCoreLazinessTest.h
      • /NSArrayWSCoreLazinessTest.m

Resources

Here are some links related to this project: