天天看點

iOS小技能:動态地給類添加新的方法、執行個體變量、屬性。

前言

添加新的執行個體變量的原理:利用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、動态添加/交換方法的實作

  • Objective-C 運作時以及 Swift 的動态性
  • knpost