是否只将Objective-C类应用于当前类(或等效效果)?

时间:2016-09-15 20:53:33

标签: objective-c objective-c-category

假设我有一个名为MyCustomView的UIView的自定义子类。我们还说我在UIView上有一个名为UIView+Dictionary的类别,它为每个UIView添加了一个名为dictionary的NSDictionary属性。

如果我要将UIView+Dictionary.h导入MyCustomView.m,则MyCustomView.m中引用的每个视图都会添加dictionary属性,这在很多情况下都是所需的行为。

但是,如果我希望UIView+Dictionary仅应用于MyCustomView本身而不是MyCustomView.m中引用的每个UIView,是否有办法(或实现类似效果)?

我想避免让MyCustomView成为另一个自定义子类的子类(例如,MyViewWithDictionary),因为我非常希望能够为某些内容导入多个类别类似于多重继承(例如UIView+DictionaryUIView+BorderUIView+CustomAnimations)。

在我自己的实际情况中,我已经编写了一个类别来自动在视图控制器中实现自定义UINavigationBar,但我希望该类别仅应用于我导入的视图控制器类别,而不是该文件中可能引用的任何其他视图控制器。

感谢所有见解!我提前道歉,因为我相当确定上述效果有更正确的术语。

2 个答案:

答案 0 :(得分:2)

  

但是,如果我想将UIView + Dictionary仅应用于MyCustomView本身[...]有没有办法这样做[...]?

仅将类别更改为MyCustomView而不是UIView。

标题与任何给定实例上的类别方法是否存在无关。如果将类别编译到程序中,则无论在何处创建实例,方法都在那里。这就是前缀在添加到框架类的方法中如此重要的原因:类别具有全局效果,名称冲突是未定义的行为。

就编译器而言,标头仅影响方法的可见性。无论如何,你都可以使用通常的技巧在运行时调用它们。

当在启动时初始化运行时,该类别对类本身生效。如果您希望类别的方法仅在某个类上可用,则必须在该类上定义该类别。

答案 1 :(得分:0)

正如Josh指出的那样,除非你打电话,否则任何类别中添加的方法都是惰性的。我遇到的问题是生成属性和类别中的混合方法(因为,正如Josh所指出的那样,Objective-C中没有mixins)。

我能够通过在我的类别中添加默认为BOOL的自定义NO来解决此问题,并充当"切换"对于我想指定的任何类别方法和属性。

例如,如果我希望我的dictionary属性被懒惰地实例化,但只能在MyCustomView内,我可以执行以下操作:

// UIView+Dictionary.h

@interface UIView (Dictionary)
@property (nonatomic) BOOL enableDictionary;
@property (nonatomic, strong) NSDictionary *dictionary;
@end

// UIView+Dictionary.m

#import "UIViewController+CustomNavigationBar.h"
#import <objc/runtime.h>

@implementation UIView (Dictionary)

- (void)setEnableDictionary:(BOOL)enableDictionary {
    objc_setAssociatedObject(self, @selector(enableDictionary), @(enableDictionary), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (BOOL)enableDictionary {
    NSNumber *enableDictionaryValue = objc_getAssociatedObject(self, @selector(enableDictionary));
    if (enableDictionaryValue) {
        return enableDictionaryValue.boolValue;
    }

    objc_setAssociatedObject(self, @selector(enableDictionary), @NO, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    return self.enableDictionary;
}

- (void)setDictionary:(NSDictionary *)dictionary {
    objc_setAssociatedObject(self, @selector(dictionary), dictionary, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (NSDictionary *)dictionary {
    if (!self.enableDictionary) {
        return nil;
    }

    NSDictionary *dictionary = objc_getAssociatedObject(self, @selector(dictionary));
    if (dictionary) {
        return dictionary;
    }

    objc_setAssociatedObject(self, @selector(dictionary), @{}, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    return self.dictionary;
}

@end

然后在-[MyCustomView viewDidLoad]内,我可以简单地拨打self.enableDictionary = YES。这样,只有MyCustomView的实例才会有一个非零延迟实例化的NSDictionary。 (请注意,在此示例中,UIViews的所有实例仍将响应选择器@selector(dictionary),但我们的行为将根据enableDictionaryYES还是NO而有所不同。 )

虽然这是一个简单的例子,但同样的策略可以用于在类别中不断变化的方法。 (同样,类别中的混合方法可能是糟糕的形式,但在某些情况下是必要的邪恶。)