关联

作者: 无题007 | 来源:发表于2017-07-19 15:51 被阅读11次

开篇

可能有人会告诉你分类是不能添加属性的,分类真的不能添加属性吗?请往下看

创建分类:

@interface Person (Character)
@property(nonatomic,strong)NSString* name;
@end
@implementation Person (Character)
@end

常规调用:

Person* person = [[Person alloc] init];
person.name = @"陈二狗";

结果GG:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[Person setName:]: unrecognized selector sent to instance 0x60000000c6f0'

沃日你哥 咋不行呢 。别着急

我们做如下操作:

  • 我们创建一个分类,并在分类中声明一个实例变量:

会发现有报错,系统告诉你在分类中不能添加实例变量,也就是说,Person类的结构体中的实例变量链表(ivars)不可扩展,OC不支持往已存在的类中添加实例变量,因此不管是系统库提供的类,还是我们自己定义的类,都无法动态添加成员变量。有人可能会说,系统有个class_addIvar方法啊,怎么不行? 这个方法的用处是:我们通过运行时来创建一个类时,我们才可以使用class_addIvar函数添加实例变量。但是这个方法也只能在objc_allocateClassPair函数与objc_registerClassPair之间调用。另外,这个类不能是元类。

那么分类中添加实例变量是不可能了,还是沿着属性这条路走下去吧。我们到.m中查看,会发现Xcode的良心所在:

它告诉你你要实现settergetter方法,虽然ivars链表不能扩展,但是methodLists可以啊。但是之前的settergetter都是结合实例变量实现的,现在该咋办呢?
比比了这么多,那么现在有请今天的🐽脚登场:

/*
* object  源对象
* key  关键字
* value  被关联的对象
* policy  关联策略
*/
OBJC_EXPORT void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
    OBJC_AVAILABLE(10.6, 3.1, 9.0, 1.0);
OBJC_EXPORT id objc_getAssociatedObject(id object, const void *key)
    OBJC_AVAILABLE(10.6, 3.1, 9.0, 1.0);

上面的方法用来把一个对象与另一个对象进行关联,并不会像属性自动生成的实例变量一样在当前类开辟空间。

于是我们可以这样写:

-(NSString *)name {
    return objc_getAssociatedObject(self, @"name");
}

-(void)setName:(NSString *)name {
    objc_setAssociatedObject(self, @"name", name, OBJC_ASSOCIATION_COPY_NONATOMIC);
}

注意,这样的属性是不会生成实例变量的,不要总想用_name取到对应实例变量,它只是有对应的settergetter方法而已。

代码封装

#import <objc/runtime.h>
// 添加id类型属性
#define ASSOCIATED(propertyName, setter, type, objc_AssociationPolicy)\
- (type)propertyName {\
return objc_getAssociatedObject(self, _cmd);\
}\
\
- (void)setter:(type)object\
{\
objc_setAssociatedObject(self, @selector(propertyName), object, objc_AssociationPolicy);\
}

// 添加BOOL类型属性
#define ASSOCIATED_BOOL(propertyName, setter)\
- (BOOL)propertyName {\
NSNumber *value = objc_getAssociatedObject(self, _cmd); return value.boolValue;\
}\
\
- (void)setter:(BOOL)object\
{\
objc_setAssociatedObject(self, @selector(propertyName), @(object), OBJC_ASSOCIATION_RETAIN_NONATOMIC);\
}

// 添加NSInteger类型属性
#define ASSOCIATED_NSInteger(propertyName, setter)\
- (NSInteger)propertyName {\
NSNumber *value = objc_getAssociatedObject(self, _cmd); return value.integerValue;\
}\
\
- (void)setter:(NSInteger)object\
{\
objc_setAssociatedObject(self, @selector(propertyName), @(object), OBJC_ASSOCIATION_RETAIN_NONATOMIC);\
}

// 添加float类型属性
#define ASSOCIATED_float(propertyName, setter)\
- (float)propertyName {\
NSNumber *value = objc_getAssociatedObject(self, _cmd); return value.floatValue;\
}\
\
- (void)setter:(float)object\
{\
objc_setAssociatedObject(self, @selector(propertyName), @(object), OBJC_ASSOCIATION_RETAIN_NONATOMIC);\
}

// 添加double类型属性
#define ASSOCIATED_double(propertyName, setter)\
- (double)propertyName {\
NSNumber *value = objc_getAssociatedObject(self, _cmd); return value.doubleValue;\
}\
\
- (void)setter:(double)object\
{\
objc_setAssociatedObject(self, @selector(propertyName), @(object), OBJC_ASSOCIATION_RETAIN_NONATOMIC);\
}

// 添加long long类型属性
#define ASSOCIATED_longlong(propertyName, setter)\
- (long long)propertyName {\
NSNumber *value = objc_getAssociatedObject(self, _cmd); return value.longLongValue;\
}\
\
- (void)setter:(long long)object\
{\
objc_setAssociatedObject(self, @selector(propertyName), @(object), OBJC_ASSOCIATION_RETAIN_NONATOMIC);\
}

//在类别中添加属性
//使用方法如下:
/**
 .h
 #import <Foundation/Foundation.h>
 @interface Person (AssociatedTest)

 @property (nonatomic, strong) NSString *name;
 @property (nonatomic, weak) id delegate;
 @property (nonatomic, assign) BOOL isOK;

 @end

.m
 #import "Person + AssociatedTest.h"

 @implementation NSObject (AssociatedTest)

 ASSOCIATED(name, setName, NSString *, OBJC_ASSOCIATION_RETAIN_NONATOMIC)
 ASSOCIATED(delegate, setDelegate, id, OBJC_ASSOCIATION_ASSIGN)
 ASSOCIATED_BOOL(isOK, setIsOK)

 @end

 */

相关文章

  • 关联 不关联

    烟雨朦胧里 横生而发的一缕思绪 是否停驻在朦胧斑驳的一处 询问 那一日 这一日的光景 你可曾望见 世俗里 有顽固的...

  • Runtime 关联对象, 可在分类中添加属性

    Runtime 关联对象, 可在分类中添加属性 关联 API 如下 设置关联值 获取关联值 取消关联 关联策略

  • iOS~关联类型、关联值、关联对象

    1、Associated Type (关联类型) Practical Protocols with Associa...

  • 关联的关联472

    刚刚读到一个观点,关联是进步的天梯。于是我忍不住也想通过这个观点再向外关联思考。关联,如果是自己所理解的那样的话,...

  • 设计模式中常见的关系举例

    设计模式就是面向对象的一种数据结构 关联关系 关联可以是双向关联、单向关联,其中单向关联还可以包含一种特殊的关联就...

  • SQL Server 2016 表操作:多表关联查询

    INNER JOIN 交叉关联 LEFT JOIN 左关联 RIGHT JOIN 右关联

  • 关联

    有的人 走着走着就丢了 有的人无论多远 都丢不了 就像在大海游泳 身边的水 总是连着远处的水 如同河流,流过你和我...

  • 关联

    一个是伫立在塞纳河畔的巴黎铁塔, 一个是横跨海河的万国桥(解放桥), 两者相隔万水千山, 它们之间...

  • 关联

    沙漠,风,沙波涟漪 岁月,时光,额上皱纹

  • 关联

    几个学习的链接地址 ibm_umlcsdn_blog 关联是什么

网友评论

      本文标题:关联

      本文链接:https://www.haomeiwen.com/subject/vnplkxtx.html