一、簡介
動態(tài)編程機(jī)制可以讓Object-C語言更加靈活,Object-C提供了3種編程方式與運行環(huán)境交互。
1.直接通過Object-C的源代碼。這是最常見的方式
2.通過NSObject類中定義的方法進(jìn)行動態(tài)編程。
3.直接調(diào)用運行時函數(shù)進(jìn)行動態(tài)編程。
二、獲得Class與檢查繼承關(guān)系
1.獲得Class,先創(chuàng)建一個Animal對象
//通過類名獲取類
Class clazz = NSClassFromString(@"Animal");
NSLog(@"獲取到的類為:%@",clazz);
//通過類獲取類
Class clazz1 = Animal.class;
NSLog(@"獲取到的類為:%@",clazz1);
//通過對象獲取類
Animal * animal = [[clazz alloc] init];
Class clazz2 = animal.class;
NSLog(@"獲取到的類為:%@",clazz2);
輸出的結(jié)果為:
2016-06-15 13:30:26.217 繼承關(guān)系-test[10930:404401] 獲取到的類為:Animal
2016-06-15 13:30:26.218 繼承關(guān)系-test[10930:404401] 獲取到的類為:Animal
2016-06-15 13:30:26.218 繼承關(guān)系-test[10930:404401] 獲取到的類為:Animal
2.檢查繼承關(guān)系,創(chuàng)建兩個繼承自Animal的對象分別為Person和Dog;
Person * person = [[Person alloc] init];
Dog* dog = [[Dog alloc] init];
//判斷是否是該類或其子類的實例。
bool bl = [person isKindOfClass:[Animal class]];
//判斷是否是該類的實例
bool bl1 = [person isMemberOfClass:[Animal class]];
bool bl2 = [person isKindOfClass:[Dog class]];
NSLog(@"是否為該類或其子類:%d",bl);//1
NSLog(@"是否為為該類:%d",bl1);//0
NSLog(@"是否為該類或其子類:%d",bl2);//0
三、動態(tài)調(diào)用方法
1.判斷是否遵從了某項協(xié)議,指定animalDelegate協(xié)議
import <Foundation/Foundation.h>
@protocol animalDelegate <NSObject>
-(void)testFun;
@end
@interface Animal : NSObject
@end
若Dog類沒有遵從協(xié)議
import <Foundation/Foundation.h>
import "Animal.h"
@interface Dog : Animal
@end
調(diào)用方法
Dog* dog = [[Dog alloc] init];
//是否遵從了協(xié)議
bool bl = [dog conformsToProtocol:@protocol(animalDelegate)];
NSLog(@"%d",bl);//0
當(dāng)遵從了協(xié)議后
import <Foundation/Foundation.h>
import "Animal.h"
@interface Dog : Animal<animalDelegate>
@end
調(diào)用方法
Dog* dog = [[Dog alloc] init];
//是否遵從了協(xié)議
bool bl = [dog conformsToProtocol:@protocol(animalDelegate)];
NSLog(@"%d",bl);//1
2.判斷某個對象是否可以調(diào)用某個方法
//可以調(diào)用返回yes,不可以返回no
bl = [dog respondsToSelector:@selector(testFun)];
NSLog(@"%d",bl);
三、動態(tài)調(diào)用
給Dog類添加私有方法
-(NSString *)moveWithSpeed:(NSNumber *)speed{
NSLog(@"移動");
NSInteger num = [speed integerValue];
return [NSString stringWithFormat:@"移動速度:%ld",num];
}
-(NSString *)runWithSpeed:(NSNumber*)speed{
NSLog(@"快跑");
NSInteger num = [speed integerValue];
return [NSString stringWithFormat:@"快跑速度:%ld",num];
}
利用動態(tài)方法調(diào)用這兩個方法
Dog* dog = [[Dog alloc] init];
//動態(tài)調(diào)用方法
//方法一:performSelector
//參數(shù)可以傳1個或2個。若要傳入多個參數(shù)可以用集合的方式實現(xiàn)。
//返回值id
NSString * speed = [dog performSelector:@selector(moveWithSpeed:) withObject:[NSNumber numberWithInteger:5]];
NSLog(@"speed:%@",speed);
NSString * speed1 = [dog performSelector:@selector(moveWithSpeed:) withObject:@(5) withObject:nil];
NSLog(@"speed1:%@",speed1);
//方法二:objc_msgSend();
//需要在project-Build Setting- Enable Strict Checking of objc_msgSend Calls 選項設(shè)置為NO;
//可以傳入任意個參數(shù)。第一個為方法的調(diào)用者, 第二個為@selector(方法名),后邊為方法需要傳入的參數(shù)可以有多個。
//返回值為id,
NSString * speed2 = objc_msgSend(dog, @selector(runWithSpeed:),@(5),nil);
NSLog(@"speed2:%@",speed2);
//方法三:methodForSelector
//1.定義IMP指針 指針變量為runSpeed
NSString* (*runSpeed)(id,SEL,NSNumber*);
//2-1.methodForSelector:方法返回的是IMP。
//2-2.通過(NSString* (*)(id,SEL,NSNumber*))對返回的IMP進(jìn)行類型強轉(zhuǎn)。
runSpeed = (NSString* (*)(id,SEL,NSNumber*))[dog methodForSelector:@selector(runWithSpeed:)];
//通過runSpeed指針調(diào)用方法,并拿到返回值。
NSString * speed3 = runSpeed(dog,@selector(runWithSpeed:),@(100));
NSLog(@"speed3:%@",speed3);
輸出結(jié)果為:
2016-06-15 14:00:31.209 繼承關(guān)系-test[11662:423726] 移動
2016-06-15 14:00:31.209 繼承關(guān)系-test[11662:423726] speed:移動速度:5
2016-06-15 14:00:31.209 繼承關(guān)系-test[11662:423726] 移動
2016-06-15 14:00:31.209 繼承關(guān)系-test[11662:423726] speed1:移動速度:5
2016-06-15 14:00:31.209 繼承關(guān)系-test[11662:423726] 快跑
2016-06-15 14:00:31.210 繼承關(guān)系-test[11662:423726] speed2:快跑速度:5
2016-06-15 14:00:31.210 繼承關(guān)系-test[11662:423726] 快跑
2016-06-15 14:00:31.210 繼承關(guān)系-test[11662:423726] speed3:快跑速度:100