最近做了個動態更新模塊的功能,是使用動態庫來完成的。因爲要求動態更新所以就不方便引入頭文件了這裏就只好採用動態調用動態庫的方法了。具體包含以下幾個方面:創建對象並設置屬性值,調用對象的方法這個方法包括類方法(靜態方法)和對象方法,設置對象的代理並實現代理方法。
在一切開始之前我們要先加載動態庫這個在前面的博客中有說明的感興趣的可以去看看。
首先創建對象這個很簡單OC中有個方法NSClassFromString(NSString *aClassName)
,官方解釋爲:Obtains a class by name,通過類名獲取類。然後我們可以通過類創建對象了,這個創建出來的對象是id類型的。
Class FWPayParam = NSClassFromString(className);
_param = [[FWPayParam alloc] init];
對象創建出來了我們要給它賦值,這裏我採用的方法是再創建一個類FanWeiPayParam,這個類的屬性跟FWPayParam一樣然後我們通過對象直接賦值,接下來看具體實現:
- (void)copy:(id)payParam {
//定義無符號int類型
unsigned int outCount,count;
//獲取包含指定類公開的屬性名地址(不包括這個類的父類屬性)的數組,outCount數組長度
objc_property_t *property = class_copyPropertyList([self class], &outCount);
//遍歷數組
for (count = 0; count<outCount; count++) {
objc_property_t t = property[count];
//獲取屬性名
NSString *key = [NSString stringWithUTF8String:property_getName(t)];
//獲取屬性名對應的屬性值
id value = [self valueForKey:key];
//設置屬性和屬性值
[payParam setValue:value forKey:key];
}
free(property);
}
我們先獲取FanWeiPayParam的屬性和屬性值然後通過- (void)setValue:(nullable id)value forKey:(NSString *)key
這個方法設置屬性值。
屬性值設置到這裏就完成了,因爲代理通常都是作爲一個對象屬性的比如:
@property (nonatomic,weak) id<FWManagerDelegate> delegate
我們可以採用上面的方法直接給它設置這個屬性值,也可以把這個代理屬性作爲一個函數的傳入參數,這個稍後再說。
調用動態庫裏面的方法我們首先也需要通過類名獲取類,在OC裏面方法有兩種類型一種是類方法類似於其他語言裏面的靜態方法,還有一種是對象方法。在oc裏面對象方法是由對象調用的,類方法是由類調用的但同時我們又常說類也是一個對象它是類對象所以在這裏調用動態庫的方法時我們都使用下面幾個方法無論它是類方法或者是對象方法區別只在於如果是對象方法要先創建一個對象,類方法無需創建對象。
- (id)performSelector:(SEL)aSelector;
- (id)performSelector:(SEL)aSelector withObject:(id)object;
- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;
第一個傳入參數是SEL類型的值表示將要調用的函數,後面如果有值都表示將要調用的函數的參數。具體的實現如下:
- (void)thisClass:(NSString *)className performSelector:(NSString *)meth withObject:(id)object1 withObject:(id)object2 {
Class FWPay = NSClassFromString(className);
if ([FWPay respondsToSelector:NSSelectorFromString(meth)]) {
if (object1 != nil && object2 != nil) {
[FWPay performSelector:NSSelectorFromString(meth) withObject:object1 withObject:object2];
return;
}
if (object1 != nil && object2 == nil) {
[FWPay performSelector:NSSelectorFromString(meth) withObject:object1];
return;
}
if (object1 == nil && object2 == nil) {
[FWPay performSelector:NSSelectorFromString(meth)];
return;
}
}
}
接下來看完整的調用吧:
FWInvoke *invoke = [[FWInvoke alloc] initWithParamClass:@"FWPayParam"];
[payParam copy:invoke.param];
[invoke thisClass:@"FWPay" performSelector:@"startPay:delegate:" withObject:invoke.param withObject:self];
上面最後一個參數self就是我們設置的代理對象,至於我們要實現的代理方法直接在代理對象裏面實現就可以了,原因很簡單我們在使用代理的時候一般都先判斷代理對象裏面有沒有實現代理方法了,如果實現了再使用代理對象調用代理方法。還有下面這種調用:
FWInvoke *invoke = [[FWInvoke alloc] init];
[invoke thisClass:@"FWPay" performSelector:@"applicationWillEnterForeground:" withObject:application withObject:nil];
下面是封裝好的動態庫調用的代碼.h文件
#import <Foundation/Foundation.h>
@interface FWInvoke : NSObject
@property (nonatomic,strong) id param;
- (instancetype)initWithParamClass:(NSString *)className;
-(void)thisClass:(NSString *)className performSelector:(NSString *)meth withObject:(id)object1 withObject:(id)object2;
@end
下面是.m文件
#import "FWInvoke.h"
@implementation FWInvoke
- (instancetype)initWithParamClass:(NSString *)className {
self = [super init];
if (self) {
if (className != nil) {
Class FWPayParam = NSClassFromString(className);
_param = [[FWPayParam alloc] init];
}
}
return self;
}
- (void)thisClass:(NSString *)className performSelector:(NSString *)meth withObject:(id)object1 withObject:(id)object2 {
Class FWPay = NSClassFromString(className);
if ([FWPay respondsToSelector:NSSelectorFromString(meth)]) {
if (object1 != nil && object2 != nil) {
[FWPay performSelector:NSSelectorFromString(meth) withObject:object1 withObject:object2];
return;
}
if (object1 != nil && object2 == nil) {
[FWPay performSelector:NSSelectorFromString(meth) withObject:object1];
return;
}
if (object1 == nil && object2 == nil) {
[FWPay performSelector:NSSelectorFromString(meth)];
return;
}
}
}
@end
限於筆者水平有限這裏面會有很多錯漏的地方在此拋磚引玉歡迎大家指正。