使用基于变量的 属性 在 objective-c 中扩展 class

extend class in objective-c with variable based property

我在 objective-c 中有一个表单实现,我想扩展我的小部件(NSButton、NSTextField 等)以包含额外的字符串,表示它们在提交后使用的唯一标识符字符串事件发生,触发生成 json 包含所有小部件 id/value 对。

我试过使用类别来扩展 NSControl,它是所有这些小部件的公共父级,如下所示。

NSControl+formItemSupport.h
-------------------------------

@interface NSControl (formItemSupport)

@property NSString * formItemId;

@end

NSControl+formItemSupport.m
-------------------------------
@implementation NSControl (formItemSupport)

-(NSString *)formItemId {
    return self.formItemId;
}

-(void)setFormItemId:(NSString *)formItemId {
    self.formItemId = formItemId;
}


在我从 NSControl+formItemSupport.m 导入的 form.m 文件中,但是当我尝试在 NSButton : NSControl 对象中设置此字段时。但是,当我尝试设置 属性 formItemId 时,我进入了无限循环。也许还有另一种方法可以在不使用继承的情况下使用基于变量的 属性 扩展 objc class ?

你可以

@synthesize formItemId = _formItemId;

//synthesize needs local declaration of _formItemId;
@implementation ExtraWurst {
    NSString *_formItemId;
}

但这是在没有@synthesize 的情况下 Xcode 在幕后为您完成的。
有时以这种方式为 属性 定义内部变量的使用仍然更容易。

除此之外,您可以并且必须按以下方式更改 setter 和 getter 方法。

-(NSString *)formItemId {
    return _formItemId;
}

-(void)setFormItemId:(NSString *)formItemId {
    _formItemId = formItemId;
}

这将防止您陷入循环。

为什么?
因为 self.formItemId = 指的是 -(void)setFormItemId:
所以你会在 setter 中调用 setter ,它会一次又一次地设置相同的值,也就是无限循环。 您可以按照上述相同的方式处理 getter。

self.yourProperty用在什么地方?
您可以在 class 中的任何地方使用 self.formItemId,但不能在 formItemId 的 getter 和 setter 内使用。

说的对,实例变量不能放在类别中。 这意味着如果你需要这样你必须 subclass UIControl 但这会破坏你使用的 UIControls 的继承。您必须将您以后使用的所有 SpecialUIControl 子class。

另一个解决方案,您可以在您的实现中定义一个常量,然后使用 objective-C 运行时函数并自己关联这个常量。当心,因为您为所有 UIControl classes 转换了 ObjectModel 然后..

#import "NSControl+formItemSupport.h"
#import <objc/runtime.h>

@implementation UIControl (formItemSupport)
NSString const *key = @"formItemSupport.forItemKey";
-(void)setFormItemId:(NSString *)formItemId {
    objc_setAssociatedObject(self, &key, formItemId, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
-(NSString *)formItemId {
    return objc_getAssociatedObject(self, &key);
}
@end

不过,子class您自己的 UIControl 而不是扩展从 UIControl 继承的所有子class 更容易、更安全、更灵活。
为什么 subclassing 在这里更容易?
正如您提到的,您稍后想 json 使用给定的每个控件的 formItemId,您可以使用子 classes 的归档器/解档器设计模式,这很适合稍后 jsonify .