前言

添加新的实例变量的原理:利用category结合runtime的API实现 iOS小技能:动态地给类添加新的方法、实例变量、属性。_动态创建

动态创建属性的应用场景:利用属性进行传值的时候,我们就可以利用本文的方法进行动态创建属性。尤其在逆向其他app的时候,往已经存在class新增一个属性,用于数据传递,尤其是异步操作的时候。

I 添加新的实例变量

1.1 原理

利用 runtime API​​objc_setAssociatedObject​​​和​​objc_getAssociatedObject​​ objc_setAssociatedObject

/**
* Sets an associated value for a given object using a given key and association policy.
*
* @param object The source object for the association.
* @param key The key for the association.
* @param value The value to associate with the key key for object. Pass nil to clear an existing association.
* @param policy The policy for the association. For possible values, see “Associative Object Behaviors.”
*
* @see objc_setAssociatedObject
* @see objc_removeAssociatedObjects
*/
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);

/**
* Returns the value associated with a given object for a given key.
*
* @param object The source object for the association.
* @param key The key for the association.
*
* @return The value associated with the key \e key for \e object.
*
* @see objc_setAssociatedObject
*/
OBJC_EXPORT id objc_getAssociatedObject(id object, const void *key)
OBJC_AVAILABLE(10.6, 3.1, 9.0, 1.0);

1.2 例子

类别​​(Category)​​​通过增加新的类和实例方法来扩展现有类的行为。作为惯例,类别被定义在它们自己的​​.{h,m}​​文件里。

//  
// Teacher+Profession.m
//

#import "Teacher+Profession.h"
#import <objc/runtime.h>

const char *ProfessionType = "NSString *"; //就是属性的key
@implementation Teacher (Profession)

-(void)setProf:(NSString*)prof
{
objc_setAssociatedObject(self, ProfessionType, prof, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

-(NSString *)prof
{
NSString *pro = objc_getAssociatedObject(self, ProfessionType);
return pro;
}

@end

II 动态创建属性

使用分类、​​@dynamic​​、objc_setAssociatedObject、objc_getAssociatedObject 实现。

2.1 应用场景

利用属性进行传值的时候,我们就可以利用本文的方法进行动态创建属性。尤其在逆向其他app的时候,往已经存在class新增一个属性,用于数据传递,尤其是异步操作的时候。

//结合@dynamic的 associatedObject例子
@implementation NSObject (AssociatedObject)
@dynamic associatedObject;
- (void)setAssociatedObject:(id)object {
objc_setAssociatedObject(self,
@selector(associatedObject), object,
OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (id)associatedObject {
return objc_getAssociatedObject(self,
@selector(associatedObject));
}

2.2 例子:为VC新增一个属性

WCNewCommitViewController+KNWCNewCommitViewControllerAssociatedObject.h

#import "WCNewCommitViewController.h"

@interface NSObject (KNWCNewCommitViewControllerAssociatedObject)
// isa (Class): NSKVONotifying_WCNewCommitViewController (isa, 0x5a10db2abf7)
@property (nonatomic, strong) id associatedObject;
@end

WCNewCommitViewController+KNWCNewCommitViewControllerAssociatedObject.m

#import "WCNewCommitViewController+KNWCNewCommitViewControllerAssociatedObject.h"

@implementation NSObject (KNWCNewCommitViewControllerAssociatedObject)

@dynamic associatedObject;
- (void)setAssociatedObject:(id)object {
objc_setAssociatedObject(self,
@selector(associatedObject), object,
OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (id)associatedObject {
return objc_getAssociatedObject(self,
@selector(associatedObject));
}

@end

2.3 效果

  • usage:
#import "WCNewCommitViewController+KNWCNewCommitViewControllerAssociatedObject.h"

[WCNewCommit setAssociatedObject:@"sssss"];
  • ret
NSLog(@"associatedObject:%@",[self valueForKey:@"associatedObject"]);//2018-09-06 12:06:06.977711 WeChat[717:226743] associatedObject:sssss

See Also

  • iOS运行时的应用:


1、实现路由(接口控制app跳任意界面 )

2、获取修改对象的成员属性

3、动态添加/交换方法的实现

4、属性关联


  • Objective-C 运行时以及 Swift 的动态性
  • knpost