【问题标题】:add category property to a class confirming to a protocol将类别属性添加到确认协议的类
【发布时间】:2020-02-08 00:09:55
【问题描述】:

我有一个生成器,它返回符合协议 A 的对象。 我想为这些对象添加一个可能带有类别的属性,以便我可以做一些事情来服务于我的目的,这显然不在协议中。

这可行吗?

【问题讨论】:

  • 什么属性,什么类型?至少示意性地向我们展示您将要实现的目标。
  • @Asperi 为什么它很重要?假设它是一个“int”属性。
  • 请注意,链接的答案不会直接用于 int 属性。如果您对此很认真,那么您需要调整它以通过NSNumber 包装和打开它。如果您对 int 不认真,这就是 Asperi 提出问题的原因。这很重要。您不能对原始类型执行与在 ObjC 中对对象执行的完全相同的操作。
  • @RobNapier 这个问题与上面链接的问题“Objective-C:类别中的属性/实例变量”不同,因为我试图将属性添加到符合协议的所有实例,而不是特定的课程,我无权访问这些课程。

标签: objective-c objective-c-runtime objective-c-category


【解决方案1】:

这个我想得越多,我越同意这不是重复的,其实答案很直接,只要你说你想要的就是你真正想要的。

假设您正在返回符合某些协议的值,请创建一个符合该协议的类型,并将所有协议方法转发到包装值。然后你可以添加任何你想要的附加属性。

例如,给定如下协议:

@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? 中给出的原因,不可能通过类别来执行此操作(如果可以基于协议而不是类添加属性,那么您可以定义一个与您的类匹配的协议,然后绕过这个限制。)

【讨论】:

    【解决方案2】:

    这是可能的方法(基于 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);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-20
      • 1970-01-01
      • 2020-02-17
      • 2023-01-31
      • 2018-05-21
      • 1970-01-01
      相关资源
      最近更新 更多