假设我有一个名为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+Dictionary
,UIView+Border
,UIView+CustomAnimations
)。
在我自己的实际情况中,我已经编写了一个类别来自动在视图控制器中实现自定义UINavigationBar,但我希望该类别仅应用于我导入的视图控制器类别,而不是该文件中可能引用的任何其他视图控制器。
感谢所有见解!我提前道歉,因为我相当确定上述效果有更正确的术语。
答案 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)
,但我们的行为将根据enableDictionary
是YES
还是NO
而有所不同。 )
虽然这是一个简单的例子,但同样的策略可以用于在类别中不断变化的方法。 (同样,类别中的混合方法可能是糟糕的形式,但在某些情况下是必要的邪恶。)