自定义对象的UIAppearance代理

Lom*_*baX 17 objective-c ios uiappearance

我有一个自定义对象,它继承自NSObject.这个对象做了"一些事情",其中一个是用一些UIKit对象创建一个UIView(UILabel,UIButtons ecc ecc ...).此对象具有一些属性,如:textColor,font,backgroundColor ...,用于自定义包含的UIKit对象的外观.

我想为这个对象的所有创建实例定制这个属性"一次性",我已经看了UIAppearance协议.

标准UIKit对象已经符合UIAppearance协议,但我不想在所有UILabel或UIButtons上应用该样式.我想仅将样式应用于对象实例中包含的UILabel和UIButtons.而且,我不能(我不想)使用appearanceWhenContainedIn:因为使用我的自定义对象的开发人员可能不知道它内部包含什么类型的对象.

所以,我正在研究如何使我的自定义对象符合UIAppearance协议.

它必须实现AFAIK

+ (id)appearance
Run Code Online (Sandbox Code Playgroud)

方法.此方法应返回一个代理对象,您可以在其中发送所有自定义项.但是,看一下UIKit对象的外观方法,我发现返回了一个私有对象.类_UIAppearance的对象.

所以,似乎Apple没有给我一个标准的代理对象来定制我自己的,我必须从头开始创建.是对的还是我失去了什么?

谢谢

Lom*_*baX 15

经过一些研究,我"放弃"使用标准的Apple对象.它暂时不存在.我已经创建了自己的代理,它非常简单(仅适用于"外观:").

我们来解释一下吧.我想在NSObject子类上设置"textColor"的外观,我们称之为"FLObject".使FLObject符合UIAppearance协议并覆盖外观方法.在此方法中,您应该返回一个代理类(我创建的代理类):

+ (id)appearance
{
    return [FLAppearance appearanceForClass:[self class]];
}
Run Code Online (Sandbox Code Playgroud)

这个怎么运作?FLAppearance为appearanceForClass:方法传递的每个类创建一个自身的单个实例.如果对同一个类调用它两次,则返回相同的实例.

然后,你可以做这样的事情:

[[FLObject appearance] setTextColor:[UIColor redColor]]; 
Run Code Online (Sandbox Code Playgroud)

FLAppearance覆盖forwardInvocation:方法,因此它接受发送的所有方法.然后,它将所有调用放在一个数组中.当FLObject初始化时,简单调用

[(FLAppearance *)[FLAppearance appearanceForClass:[self class]] startForwarding:self];
Run Code Online (Sandbox Code Playgroud)

将开始发送调用并设置外观.当然,这需要一些调整和错误检查,但我认为这是一个良好的开端.

@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];
    }
}
Run Code Online (Sandbox Code Playgroud)