目标 C:通过自定义根类允许类别中的属性

Posted

技术标签:

【中文标题】目标 C:通过自定义根类允许类别中的属性【英文标题】:Objective C: allow properties in category via custom root class 【发布时间】:2013-12-16 15:00:53 【问题描述】:

关于类别属性问题有很多问题。 我知道解决这个问题的一些可能性:

use a singleton registry objc_setAssociatedObject and objc_getAssociatedObject

从我的角度来看,两者都不干净,因为当创建此类属性的对象被释放时,分配的内存永远不会被清除。

类别是保持代码整洁和为现有类动态添加功能的好方法。它们有助于将功能分组并在更多开发人员之间分配实施工作。

类别的坏处是缺少存储。

我现在多次遇到这个问题,我想知道以下是否会以一种干净的方式解决这个问题,同时也注意内存,以及是否有任何我现在看不到的问题。

一个限制,我可以忽略,因为我是一名框架开发人员:我能够创建自己的自己的根类,而其他所有的类可以继承

首先声明新的根对象:

@interface RootObject : NSObject

- (void)setRuntimeProperty:(id)runtimeProperty forKey:(id<NSCopying>)key;
- (id)runtimePropertyForKey:(id)key;

@end

配合相应的实现:

#import "RootObject.h"

@interface RootObject ()
@property (readwrite) NSMutableDictionary *runtimeProperties;
@end

@implementation RootObject
@synthesize runtimeProperties = _runtimeProperties;

- (id)init 
    self = [super init];

    if (self)
    
        _runtimeProperties = [[NSMutableDictionary alloc] initWithCapacity:1];
    

    return self;


- (void)dealloc 
    [_runtimeProperties release];
    _runtimeProperties = nil;

    [super dealloc];


- (id)runtimePropertyForKey:(id)key 
    return [self.runtimeProperties objectForKey:key];


- (void)setRuntimeProperty:(id)runtimeProperty forKey:(id<NSCopying>)key 
    if (key)
    
        if (runtimeProperty)
        
            [self.runtimeProperties setObject:runtimeProperty forKey:key];
        
        else
        
            [self.runtimeProperties removeObjectForKey:key];
        
    


@end

通过使用RootObject 而不是NSObject,应该很容易将“属性”添加到类的类别中。考虑上课MyClass

@interface MyClass : RootObject
// some interface here
@end

在此类之上实现特殊行为时,您现在可以添加如下属性:

@interface MyClass (specialBehavior)
@property (nonatomic, retain) NSString *name;
@property (nonatomic, copy) NSDate *birthday;
@end

有相应的实现:

@implementation MyClass (specialBehavior)
@dynamic name;
- (NSString *)name 
    return [self runtimePropertyForKey:@"name"];

- (void)setName:(NSString *)name 
    [self setRuntimeProperty:name forKey:@"name"];

@dynamic birthday;
- (NSDate *)birthday 
    return [self runtimePropertyForKey:@"birthday"];

- (void)setBirthday:(NSDate *)birthday 
    [self setRuntimeProperty:[birthday copy] forKey:@"birthday"];

@end

只需在 setter 方法中添加必要的调用,这样的实现也可以兼容 KVO。 非常直截了当,但我想知道我是否错过了一些重要的事情? (例如,具有许多此类声明的属性或使用许多此类对象的运行时性能非常非常差)

【问题讨论】:

如果您正在开发有问题的类并且只是使用类别进行组织,为什么不直接将必要的属性添加到您的类中呢?仅当您无法更改类定义时,类别的存储“问题”才适用。 @Caleb:事情并不像这里显示的那么简单。通过直接更改MyClass,它会随着每个特殊行为的实现而增长和增长。并回到框架开发;行为将与MyClass 绑定,即使此类行为仅用于特殊项目。所以我的目标是拥有只有根功能的苗条类。 随着每一种特殊行为而成长和成长 嗯,是的,当您向类添加属性时会发生这种情况。 即使这样的行为只在一个特殊的项目中使用 那么为什么要将这些行为添加到类本身呢?子类化似乎是解决这两个问题的合理解决方案。如果您的解决方案适合您,那就太好了(但请先阅读 Jesse 的回答)。 【参考方案1】:

这实际上与 objc_setAssociatedObject 和 objc_getAssociatedObject 相同,它们在对象被释放时释放内存(取决于关联类型)。我猜它们的开销也比您建议的代码低得多。

【讨论】:

我快速实施了一个测试来验证这一点。我记得我们在开发的早期阶段遇到了一个问题,即内存没有被清除。但是现在在我的测试中一切都按预期工作,所以我们过去可能做错了什么。 KVO 也使用such an implementation 开箱即用。谢谢!

以上是关于目标 C:通过自定义根类允许类别中的属性的主要内容,如果未能解决你的问题,请参考以下文章

使用 DataTables 时,自定义下拉搜索不允许我添加新项目

类别中的自定义 NSManagedObject 设置器

php Сustom类别过滤器解析URL类别过滤器按自定义过滤器按属性自定义过滤器自定义排序

php 通过acf选择字段查询类别中的自定义帖子类型

php 通过acf选择字段查询类别中的自定义帖子类型

目标 C 中选择器上的 EXC_BAD_ACCESS