将类别属性添加到确认协议的类中

问题描述 投票:0回答:2

我有一个生成器,该生成器返回符合协议A的对象。我想为这些对象添加一个属性(可能带有类别),以便我可以做一些事来达到自己的目的,这显然不在协议中。

这可行吗?

objective-c objective-c-runtime objective-c-category
2个回答
0
投票
我对这个问题的思考越多,我就越同意它不是重复的,实际上,只要您说的是您真正想要的,答案就非常简单。

鉴于您要返回符合某种协议的值,请创建符合该协议的类型,并将所有协议方法转发给包装的值。然后,您可以添加所需的任何其他属性。

例如,给定类似协议:

@protocol Runnable <NSObject> - (void)run; @end

您可以创建一个简单的包装,例如:

@interface AnyRunnable: NSObject <Runnable> - (instancetype)initWithRunnable:(id<Runnable>)runnable; @end @interface AnyRunnable (Private) @property (nonatomic, readwrite) id<Runnable> wrapped; @end @implementation AnyRunnable - (instancetype)initWithRunnable:(id<Runnable>)wrapped { self = [super init]; if (self) { self.wrapped = wrapped; } return self; } - (void)run { [self.wrapped run]; } @end

现在,AnyRunnableRunnable,因此您可以从方法中返回它。这也是您控制的类型,因此您可以向其添加任何所需的属性。这可以扩展到任何协议。您只需要实现所需的方法即可。

出于Why can't categories have instance variables?中给出的原因,无法通过类别执行此操作(如果可以基于协议(而非类)添加属性,则可以定义与您的类匹配的协议,然后绕过该协议限制。)


0
投票
这里是可能的方法(基于与Objective-C相关的对象)。经过测试和工作。

假设我们有一些我们无法接触的课程

@interface SomeClass: NSObject @end @implementation SomeClass @end

然后可以通过以下方式注入一些新属性

@interface SomeClass (VirtualProperty) @property (atomic) NSInteger virtualProperty; @property (nonatomic, readonly) NSInteger calculableProperty; @end static const char *kVirtualPropertyKey = "virtualProperty"; @implementation SomeClass (VirtualProperty) @dynamic virtualProperty; - (NSInteger)calculableProperty { return self.virtualProperty * 2; } - (NSInteger)virtualProperty { return [(NSNumber *)objc_getAssociatedObject(self, kVirtualPropertyKey) integerValue]; } - (void)setVirtualProperty:(NSInteger)newValue { objc_setAssociatedObject(self, kVirtualPropertyKey, @(newValue), OBJC_ASSOCIATION_RETAIN); } @end

用法:

SomeClass *some = SomeClass.new; some.virtualProperty = 5; NSLog(@"Result: %lu", some.calculableProperty);

© www.soinside.com 2019 - 2024. All rights reserved.