After some reserach I "give up" about using a standard Apple object. It doesn't exists, for now. I've created my own proxy, it's quite simple (works only with "appearance:" by now).
Let's explain it.
I want to set the appearance of "textColor" on a NSObject subclass, let's call it "FLObject".
Make FLObject conforms to UIAppearance protocol and override the appearance method.
In this method, you should return a proxy class (the one I created):
+ (id)appearance
{
return [FLAppearance appearanceForClass:[self class]];
}
How it works?
FLAppearance creates a single instance of itself for each class passed by the appearanceForClass: method.
If you call it two times for the same class, the same instance is returned.
Then, you can do something like this:
[[FLObject appearance] setTextColor:[UIColor redColor]];
FLAppearance overrides the forwardInvocation: method, so it accepts all methods sent.
Then, it puts all invocations in an array.
When FLObject is initialized, a simple call to
[(FLAppearance *)[FLAppearance appearanceForClass:[self class]] startForwarding:self];
will start to send invocations and set the appearance.
Sure, this needs some tuning and error checking, but I think it's a good start.
@interface FLAppearance ()
@property (strong, nonatomic) Class mainClass;
@property (strong, nonatomic) NSMutableArray *invocations;
@end
static NSMutableDictionary *dictionaryOfClasses = nil;
@implementation FLAppearance
// this method return the same object instance for each different class
+ (id) appearanceForClass:(Class)thisClass
{
// create the dictionary if not exists
// use a dispatch to avoid problems in case of concurrent calls
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
if (!dictionaryOfClasses)
dictionaryOfClasses = [[NSMutableDictionary alloc]init];
});
if (![dictionaryOfClasses objectForKey:NSStringFromClass(thisClass)])
{
id thisAppearance = [[self alloc]initWithClass:thisClass];
[dictionaryOfClasses setObject:thisAppearance forKey:NSStringFromClass(thisClass)];
return thisAppearance;
}
else
return [dictionaryOfClasses objectForKey:NSStringFromClass(thisClass)];
}
- (id)initWithClass:(Class)thisClass
{
self = [self initPrivate];
if (self) {
self.mainClass = thisClass;
self.invocations = [NSMutableArray array];
}
return self;
}
- (id)init
{
[NSException exceptionWithName:@"InvalidOperation" reason:@"Cannot invoke init. Use appearanceForClass: method" userInfo:nil];
return nil;
}
- (id)initPrivate
{
if (self = [super init]) {
}
return self;
}
-(void)forwardInvocation:(NSInvocation *)anInvocation;
{
// tell the invocation to retain arguments
[anInvocation retainArguments];
// add the invocation to the array
[self.invocations addObject:anInvocation];
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
return [self.mainClass instanceMethodSignatureForSelector:aSelector];
}
-(void)startForwarding:(id)sender
{
for (NSInvocation *invocation in self.invocations) {
[invocation setTarget:sender];
[invocation invoke];
}
}