Objective-C library for writing selectors that alter your object's properties at runtime.
Objective-C Shell
Switch branches/tags
Nothing to show
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.


PropSetter is an Objective C library for writing XPath/CSS like selectors against your NSObjects, and having those selectors change values in those bjects at runtime.  Expressions look similar to this:

NSString[self = 'The text that it should match']
MyViewController[.stringArray contains 'This string'].title
UIView[.backgroundColor = .foregroundColor].alpha

These expressions follow the basic form:


Expression operators include:
Equals: =, ==, eq
Not equals: !=, ne
Less than: <, lt
Greater than: >, gt
Greater than, equals: >=, gte
Less than, equals: <=, tle
Contains: =>, contains

Expressions may be and'ed and or'ed to each other, like so:

MyViewController[.title = 'Sports' and .dataSource.stale = true].staleIndicatorVisible

The full language is expressed in the selector.grammar file included in the source. Parsing facilities are provided by parsekit (http://parsekit.com/), the lipo'd static lib of which is included with this app. (Revealing the clear iPhone bias of the author. If you happen to patch support for Mac OS compiling into the project, I will happily patch it back into the library.)

Use the PropSetterManager object to allow for these expressions to take action upon your objects. The PropSetterManager object keeps a weak reference to your objects as they are observed for changes, using the KVO functionality provided in Cocoa.  For example:

[[PropSetterManager manager] addSelectorFromString:@"UIView[.text = 'Red'].backgroundColor" withValue:[UIColor redColor]];
[[PropSetterManager manager] beginObservingObject:myLabel];

As your object is deallocated, you must remove the references to it by calling:

[[PropSetterManager manager] stopObservingObject:myLabel];


You may create custom operators for use in expressions by registering them with the shared PropSetter object, like so:

[[PropSetter sharedInstance] addTarget:self andSelector:@selector(customOperator:forLvalue:andRvalue:) forCustomOperator:@"soundex"];

To use the custom operator, prefix the name you registered the operator as with an @ symbol, like so:

NSString[self @soundex 'Lion']

Registering a delegate method as a custom operator requires that the delegate method adhere to the following signature:

-(BOOL) customOperator:(NSString *)name forLvalue:(id)l andRvalue:(id)r;

You may also specify custom functions for values which are not easily represented by strings.  You may do so by registering the function a la:

[[PropSetter sharedInstance] addTarget:self andSelector:@selector(customColorFunction:arguments:) forCustomFunction:@"color"];

where customColorFunction:arguments: is a method signature of the following form:

-(id) customColorFunction:(NSString *)name arguments:(NSArray *)args;

You may then use the custom function in the following form:

UIView[.backgroundColor = @color(0.3,0.3,0.3,1.0)]


You may also register callback functions to take action whenever a particular property changes, using syntax like the following.

[[PropSetterManager manager] addSelectorFromString:@"NSObject[.text].backgroundColor" withTarget:self andSelector:@selector(changeColorOfObject:)];

The argument passed to this method will be the object that is ebing changed.


To allow for simple rules where NSString, NSData, NSDictionary or NSNumber values are the only values of note to insert into a given object, you may use a property list to add rules to the manager.

[[PropSetterManager manager] addSelectorsFromPlist:filename]

Additionally, you may specify that NSString values may be parsed for PropSetter custom functions when they are encountered by the PropSetterManager. To indicate that you want this behavior, load the rules in the following manner:

[[PropSetterManager manager] addSelectorsFromPlist:filename  parsingStringsAsValues:YES];

This will allow you to use custom functions you have registered with the shared PropSetter instance in cases where the NSString values in your property file have the following form: 

@nameOfFunction("value1", 2.0, true)

If an NSString fails to be parsed correctly, it will be assumed that the value is intended as a literal string, and will be imported as such.

This code was written for the Indianapolis Star, and has been open sourced by them using the MIT license.