iOS - 如何给1个类添加属性

有些时候在使用1个类的时候,往往不想子类话,而直接给这个类添加属性.

找了一些方法无果.

有个比较猥琐的办法:另外添加1个类用来管理.效果不理想.pass


利用运行时动态绑定关联技术.伪造实现类别添加属性效果


搜索一下找到解决办法:

http://www.ddeville.me/2011/03/add-variables-to-an-existing-class-in-objective-c/


http://oleb.net/blog/2011/05/faking-ivars-in-objc-categories-with-associative-references/


In OS X 10.6 and iOS 3.1, Apple added Associative References to the Objective-C runtime. Essentially, this means that each and every object has an optional dictionary you can add arbitrary key/value pairs to.

This is a great feature, especially considering that Objective-C has forever had a feature to add methodsto existing classes: categories. Categories, however, do not permit you to add instance variables. Using associative references, it’s easy to fake ivars.

In the C API of the Objective-C runtime, you add a key/value pair to an object and read it again with these two functions:

void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
id objc_getAssociatedObject(id object, const void *key)

If we wrap these calls in a property’s custom getter and setter, we can make the implementation of our fake “ivar” totally opaque to the user of our API.

Using objects to tag UIViews

As an example, say we want to add the ability to add an arbitrary object as a tag to a UIView (UIView’s existing tag property only takes integers, which can be limiting at times). The interface of our “object tag” category could look like this:

@interface UIView (ObjectTagAdditions)

@property (nonatomic, retain) id objectTag;

- (UIView *)viewWithObjectTag:(id)object;

@end

Using associative references, the implementation of the property is straightforward:

#import <objc/runtime.h>

static char const * const ObjectTagKey = "ObjectTag";

@implementation UIView (ObjectTagAdditions)
@dynamic objectTag;

- (id)objectTag {
    return objc_getAssociatedObject(self, ObjectTagKey);
}

- (void)setObjectTag:(id)newObjectTag {
    objc_setAssociatedObject(self, ObjectTagKey, newObjectTag, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

...

By specifying OBJC_ASSOCIATION_RETAIN_NONATOMIC, we tell the runtime to retain the value for us. Other possible values are OBJC_ASSOCIATION_ASSIGN,OBJC_ASSOCIATION_COPY_NONATOMICOBJC_ASSOCIATION_RETAIN,OBJC_ASSOCIATION_COPY, corresponding to the familiar property declaration attributes.

Update December 22, 2011: It’s important to note that the key for the association is a void pointer void *key, not a string. That means that when retrieving an associated reference, you have to pass the exact same pointer to the runtime. It would not work as intended if you used a C string as the key, then copied the string to another place in memory and tried to access the associated reference by passing the pointer to the copied string as a key.

Finally, here is the code for the recursive -viewWithObjectTag: method:

- (UIView *)viewWithObjectTag:(id)object {
    // Raise an exception if object is nil
    if (object == nil) {
        [NSException raise:NSInternalInconsistencyException format:@"Argument to -viewWithObjectTag: must not be nil"];
    }

    // Recursively search the view hierarchy for the specified objectTag
    if ([self.objectTag isEqual:object]) {
        return self;
    }
    for (UIView *subview in self.subviews) {
        UIView *resultView = [subview viewWithObjectTag:object];
        if (resultView != nil) {
            return resultView;
        }
    }
    return nil;
}

Update May 16, 2011: Vadim Shpakovski asked on Twitter why, when the argument toviewWithObjectTag: is nil, I chose to generate an exception over returning nil to the caller. The reason is that returning nil would be ambiguous since it means that no view with the specifiedobjectTag could be found. Since nil is the default value of objectTag, this is highly unlikely.

A good alternative to raising an exception is to return the first view whose objectTag actually is nil, just like viewWithTag: does. I chose not to do that because I imagine it’s more likely that calling -viewWithObjectTag: with a nil argument is a programmer error than intended usage. It’s just a matter of preference, though.

Update December 22, 2011: Improved the declaration of the ObjectTagKey pointer and added a missing #import statement to the code sample.





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值