iOS小技能:动态地给类添加新的方法、实例变量、属性。

5,872 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第16天,点击查看活动详情

前言

添加新的实例变量的原理:利用category结合runtime的API实现

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

I 添加新的实例变量

1.1 原理

利用 runtime APIobjc_setAssociatedObjectobjc_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、属性关联

blog.csdn.net/z929118967/…