Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/objective-c/26.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 自定义对象的UI外观代理_Ios_Objective C_Uiappearance - Fatal编程技术网

Ios 自定义对象的UI外观代理

Ios 自定义对象的UI外观代理,ios,objective-c,uiappearance,Ios,Objective C,Uiappearance,我有一个自定义对象,它继承自NSObject。 此对象执行“某些操作”,其中之一是使用一些UIKit对象(UILabel、UIButtons ecc ecc…)创建UIView。 此对象具有一些属性,如:textColor、字体、backgroundColor。。。用于自定义包含的UIKit对象的外观 我想为这个对象的所有创建实例自定义这个属性“一次”,我已经看过UIAppearance协议 标准UIKit对象已经符合UIAppearance协议,但我不想在所有UILabel或UIButton上

我有一个自定义对象,它继承自NSObject。 此对象执行“某些操作”,其中之一是使用一些UIKit对象(UILabel、UIButtons ecc ecc…)创建UIView。 此对象具有一些属性,如:textColor、字体、backgroundColor。。。用于自定义包含的UIKit对象的外观

我想为这个对象的所有创建实例自定义这个属性“一次”,我已经看过UIAppearance协议

标准UIKit对象已经符合UIAppearance协议,但我不想在所有UILabel或UIButton上应用该样式。我只想将样式应用于对象实例中包含的UILabel和UIButton。 此外,我不能(也不希望)在包含时使用AppearanceIn:因为使用我的自定义对象的开发人员可能不知道其中“包含”了什么类型的对象

因此,我正在研究如何使自定义对象符合UIAppearance协议

看来它必须实施

+ (id)appearance
方法。此方法应返回一个代理对象,您可以在其中发送所有自定义设置。 但是,查看UIKit对象的外观方法,我看到返回了一个私有对象。 外观上属于类的对象

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

谢谢退房

基本上,您只需要使用
UI\u外观\u选择器
标记您的属性,只要您的类是
UI视图
的子类,它将处理私有
\u外观
类的实际销售,一切都可以正常工作


编辑:

您最好使用单例和一些类方法来运行自己的解决方案,而不是尝试在运行时做一些可怕的事情。它看起来不像
ui外观
支持您的用例

另一方面,您可以将提供的每个对象粘贴到私有的
UIView
子类中,然后提供该子类的实例。然后,您可以将发送到
NSObject
的外观消息转发到您提供的实例,并在包含时使用
appearance:
。不过,这可能会变得混乱,也可能会让你们这一类的消费者感到困惑。

经过一些关于使用标准Apple对象的研究后,我“放弃”了。现在还不存在。我已经创建了自己的代理,非常简单(目前只适用于“外观”)

让我们解释一下。 我想在NSObject子类上设置“textColor”的外观,我们称之为“FLObject”。 使FLObject符合UIAppearance协议并重写外观方法。 在这个方法中,您应该返回一个代理类(我创建的):

它是如何工作的? FlaAppearance为appearanceForClass:方法传递的每个类创建一个自身实例。 如果对同一个类调用它两次,则返回同一个实例

然后,您可以这样做:

[[FLObject appearance] setTextColor:[UIColor redColor]]; 
flaappearance覆盖forwardInvocation:method,因此它接受发送的所有方法。 然后,它将所有调用放在一个数组中。 初始化FLObject时,对

[(FLAppearance *)[FLAppearance appearanceForClass:[self class]] startForwarding:self];
将开始发送调用并设置外观。 当然,这需要一些调整和错误检查,但我认为这是一个好的开始

@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];
    }
}

很好的实现,我稍微修改了代码,并将该类创建为
NSProxy
的子类。在项目中使用它时,我发现内存泄漏:

例如:使用代理设置全局设置/外观,该类的每个实例永远不会达到refCount 0,因此永远不会调用
dealloc

泄漏代码:

-(void)forwardInvocation:(NSInvocation *)anInvocation;
{
    [...]

    // !! This will retain also the target

    [anInvocation retainArguments];

    [...]
}
修正:

NSInvocation的复制类别

-(id)copy
{
     NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[self methodSignature]];
     NSUInteger numberOfArguments = [[self methodSignature] numberOfArguments];

     [invocation setTarget:self.target];
     [invocation setSelector:self.selector];

     if (numberOfArguments > 2) {
         for (int i = 0; i < (numberOfArguments - 2); i++) {
             char buffer[sizeof(intmax_t)];
             [self getArgument:(void *)&buffer atIndex:i + 2];
             [invocation setArgument:(void *)&buffer atIndex:i + 2];
         }
     }

     return invocation;
}
-(id)复制
{
NSInvocation*invocation=[NSInvocation invocationWithMethodSignature:[self-methodSignature]];
NSUInteger numberOfArguments=[[self-methodSignature]numberOfArguments];
[调用setTarget:self.target];
[调用集合选择器:self.selector];
如果(numberOfArguments>2){
对于(int i=0;i<(numberOfArguments-2);i++){
字符缓冲区[sizeof(intmax_t)];
[self-getArgument:(void*)&缓冲区索引:i+2];
[invocation setArgument:(void*)&buffer-atIndex:i+2];
}
}
返回调用;
}

为了我自己的项目,我收集了所有信息并发布了自定义UIApprance代理作为开源项目

谢谢,我知道如何在UIView子类中使用它。正如我指定的,我希望在NSObject子类中实现UIAppearance我选择创建自己的与UIAppearance协议兼容的代理,这比看起来更简单:-)我在答案中添加了代码。工作正常我扩展了它,因此它也将向上移动到类Hirarch,以便它还可以设置父类的选项:(代码太长,无法添加内联)。做得好!作为改进,您可以使用
instancetype
而不是
id
作为返回类型,这样您甚至可以跳过显式转换到
flaappearance
。答案在开始前有一个小错误,应该是:NSInvocation*targetInvocation=[invocation copy];[targetInvocation设置目标:发送方];[targetInvocation调用];targetInvocation=nil;
-(void)forwardInvocation:(NSInvocation *)anInvocation
{
     [anInvocation setTarget:nil];
     [anInvocation retainArguments];

     // add the invocation to the array
     [self.invocations addObject:anInvocation];
}

-(void)startForwarding:(id)sender
{
     for (NSInvocation *invocation in self.invocations) {

         // Create a new copy of the stored invocation,
         // otherwise setting the new target, this will never be released
         // because the invocation in the array is still alive after the call

         NSInvocation *targetInvocation = [invocation copy];
         [targetInvocation setTarget:sender];
         [targetInvocation invoke];
         targetInvocation = nil;
     }
}
-(id)copy
{
     NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[self methodSignature]];
     NSUInteger numberOfArguments = [[self methodSignature] numberOfArguments];

     [invocation setTarget:self.target];
     [invocation setSelector:self.selector];

     if (numberOfArguments > 2) {
         for (int i = 0; i < (numberOfArguments - 2); i++) {
             char buffer[sizeof(intmax_t)];
             [self getArgument:(void *)&buffer atIndex:i + 2];
             [invocation setArgument:(void *)&buffer atIndex:i + 2];
         }
     }

     return invocation;
}