有什么方法可以将 Objective-C 类别仅应用于当前 class(或等效效果)?
Any way to apply Objective-C category only to current class (or equivalent effect)?
假设我有一个名为 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,但我希望该类别仅应用于我正在导入该类别的视图控制器,并且不是该文件中可能引用的任何其他视图控制器。
感谢任何和所有见解!我提前道歉,因为我相当确定上面描述的效果有更多正确的术语。
However, if I wanted UIView+Dictionary applied only to MyCustomView itself [...] is there a way to do so [...]?
只能通过将类别更改为在 MyCustomView 而不是 UIView 上。
header 与类别的方法是否在任何给定实例上存在 无关。如果类别被编译到您的程序中,那么无论在何处创建实例,方法都在那里。这就是前缀对添加到框架的方法如此重要的原因 classes:类别具有全局影响,名称冲突是未定义的行为。
header 仅影响编译器所关注的方法的可见性。无论如何,您都可以使用通常的技巧在运行时调用它们。
类别在 class 本身 上生效,当运行时在启动时被初始化。如果希望类别的方法只在某个class上可用,类别必须定义在那个class.
上
正如 Josh 所指出的,除非您调用它们,否则在类别中添加的任何方法基本上都是惰性的。我遇到的问题是类别中生成的属性和混合方法(因为,正如 Josh 还指出的那样,Objective-C 中没有混入)。
我能够通过在我的类别中添加默认为 NO
并充当我想要的任何类别方法和属性的 "switch" 的自定义 BOOL
来解决这个问题指定。
例如,如果我希望我的 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
而有所不同。 )
虽然这是一个微不足道的例子,但相同的策略可用于在类别中调配的方法。 (同样,在类别中混合方法可能是一种不好的形式,但在某些情况下是必要的邪恶。)
假设我有一个名为 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,但我希望该类别仅应用于我正在导入该类别的视图控制器,并且不是该文件中可能引用的任何其他视图控制器。
感谢任何和所有见解!我提前道歉,因为我相当确定上面描述的效果有更多正确的术语。
However, if I wanted UIView+Dictionary applied only to MyCustomView itself [...] is there a way to do so [...]?
只能通过将类别更改为在 MyCustomView 而不是 UIView 上。
header 与类别的方法是否在任何给定实例上存在 无关。如果类别被编译到您的程序中,那么无论在何处创建实例,方法都在那里。这就是前缀对添加到框架的方法如此重要的原因 classes:类别具有全局影响,名称冲突是未定义的行为。
header 仅影响编译器所关注的方法的可见性。无论如何,您都可以使用通常的技巧在运行时调用它们。
类别在 class 本身 上生效,当运行时在启动时被初始化。如果希望类别的方法只在某个class上可用,类别必须定义在那个class.
上正如 Josh 所指出的,除非您调用它们,否则在类别中添加的任何方法基本上都是惰性的。我遇到的问题是类别中生成的属性和混合方法(因为,正如 Josh 还指出的那样,Objective-C 中没有混入)。
我能够通过在我的类别中添加默认为 NO
并充当我想要的任何类别方法和属性的 "switch" 的自定义 BOOL
来解决这个问题指定。
例如,如果我希望我的 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
而有所不同。 )
虽然这是一个微不足道的例子,但相同的策略可用于在类别中调配的方法。 (同样,在类别中混合方法可能是一种不好的形式,但在某些情况下是必要的邪恶。)