每個(gè)人的學(xué)習(xí)方式不同竖螃,我習(xí)慣于先了解每個(gè)方法的使用方式是什么记舆,方法是做什么用的。今天的runtime也是凳鬓。我們可以從官方文檔中找出runtime的所有方法
類相關(guān)的方法
在文檔中我們可以看到類相關(guān)的所有方法茁肠。
順便做個(gè)整理
class_get
- (了解) class_getName (獲取類名) ,返回值類型
const char *
// 獲取類名 (獲取的是const char 類型數(shù)據(jù))
NSLog(@"類名 :%s",class_getName([UILabel class]));
有點(diǎn)類似NSStringFromClass
缩举,不過NSStringFromClass
返回的是NSString
- (了解) class_getSuperclass(獲取一個(gè)類的父類)垦梆,返回值類型
class
// 獲取父類
NSLog(@"父類 : %@",class_getSuperclass([UILabel class]));
NSObject里提供了一個(gè)superclass
的只讀屬性,也可以獲取父類蚁孔。
- (了解) class_getProperty ,(獲取指定的屬性)奶赔,返回值類型
objc_property類型結(jié)構(gòu)體
objc_property_t property = class_getProperty([UILabel class], "text");
// 打印一下獲取的屬性是什么 ,通過property_getName
NSString *propertyString = [[NSString alloc] initWithCString:property_getName(property) encoding:NSUTF8StringEncoding];
NSLog(@"取出的屬性 = %@",propertyString);
- (了解)class_getVersion,(獲取版本號(hào)),返回值類型
int
NSLog(@"版本號(hào) = %d", class_getVersion([UILabel class]));
- (了解)class_getImageName,(獲取類坐在的動(dòng)態(tài)庫位置),返回類型
const char *
NSLog(@"獲取類坐在的動(dòng)態(tài)庫位置 = %s", class_getImageName([UILabel class]));
- (重要)class_getClassMethod杠氢,(獲取類方法)站刑,返回類型
Method
Method method = class_getClassMethod([UILabel class], @selector(userInterfaceLayoutDirectionForSemanticContentAttribute:));
NSLog(@"方法名 = %s",sel_getName(method_getName(method)));
- (重要)class_getInstanceMethod,(獲取實(shí)例方法)鼻百,返回類型
Method
Method instanceMethod = class_getInstanceMethod([UILabel class], @selector(setBackgroundColor:));
NSLog(@"實(shí)例方法名 = %s",sel_getName(method_getName(instanceMethod)));
- (了解)class_getClassVariable绞旅,(獲取類的成員變量信息)摆尝,返回類型
Ivar
Ivar ivar = class_getClassVariable([Person class], "_sex");
- (重要)class_getMethodImplementation,(獲取實(shí)例方法)因悲,返回類型
IMP
IMP imp = class_getMethodImplementation([UILabel class], @selector(setBackgroundColor:));
- (了解)class_getInstanceSize堕汞,(獲取實(shí)例對(duì)象大小),返回類型
size_t
size_t size = class_getInstanceSize([UILabel class]);
NSLog(@"實(shí)例對(duì)象大小 = %li",size);
(了解)class_getIvarLayout([UILabel class]) class_getWeakIvarLayout([UILabel class])晃琳,(獲取類的成員變量信息)讯检,返回類型
const uint8_t *
,可以參考這篇輸出
2018-08-02 18:36:31.060785+0800 runtime[27722:927392] 類名 :UILabel
2018-08-02 18:36:31.060988+0800 runtime[27722:927392] 類名 :UILabel
2018-08-02 18:36:31.061228+0800 runtime[27722:927392] 父類 : UIView
2018-08-02 18:36:31.064525+0800 runtime[27722:927392] 取出的屬性 = text
2018-08-02 18:36:31.064713+0800 runtime[27722:927392] 版本號(hào) = 0
2018-08-02 18:36:31.064841+0800 runtime[27722:927392] 獲取類坐在的動(dòng)態(tài)庫位置 = /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/System/Library/Frameworks/UIKit.framework/UIKit
2018-08-02 18:36:31.064974+0800 runtime[27722:927392] 方法名 = userInterfaceLayoutDirectionForSemanticContentAttribute:
2018-08-02 18:36:31.065233+0800 runtime[27722:927392] 實(shí)例方法名 = setBackgroundColor:
2018-08-02 18:36:31.065715+0800 runtime[27722:927392] 實(shí)例對(duì)象大小 = 728
class_copy
- (重要)class_copyIvarList卫旱,(獲取類的實(shí)例變量列表)人灼,返回類型
Ivar *
獲取類的實(shí)例變量列表
unsigned int count = 0;
Ivar * varList = class_copyIvarList([UILabel class], &count);;
for (int i = 0; i<count; i++) {
NSLog(@"%s",ivar_getName(varList[i]));
}
//釋放varList
free(varList);
- (重要)class_copyMethodList,(獲取類的所有方法)顾翼,返回類型
Method *
獲取類的所有方法
unsigned int count = 0;
Method *method = class_copyMethodList([UILabel class], &count);;
for (int i = 0; i<count; i++) {
NSLog(@"%s",sel_getName(method_getName(method[i])));
}
//釋放varList
free(method);
- (重要)class_copyPropertyList投放,(獲取類的屬性列表),返回類型
objc_property_t *
獲取屬性列表
unsigned int count = 0;
objc_property_t *property = class_copyPropertyList([UILabel class], &count);;
for (int i = 0; i<count; i++) {
NSLog(@"%s",property_getName(property[i]));
}
//釋放varList
free(property);
- (重要)class_copyProtocolList适贸,(獲取類的協(xié)議列表)灸芳,返回類型
Protocol * __unsafe_unretained *
Protocol * __unsafe_unretained *protocol = class_copyProtocolList([UITableViewController class], &count);;
for (int i = 0; i<count; i++) {
Protocol *pro = protocol[I];
NSLog(@"%@",NSStringFromProtocol(pro));
}
//釋放varList
free(protocol);
因?yàn)樯厦娴膸讉€(gè)方法打印的東西太長,就不輸出了拜姿。
class_add
- (了解)class_addIvar烙样,(為類動(dòng)態(tài)添加實(shí)例變量),返回類型
BOOL
class_addIvar([Person class], "addLength", sizeof(NSInteger), log2(_Alignof(NSInteger)), @encode(NSInteger));
- (重要)class_addMethod砾隅,(為類動(dòng)態(tài)添加方法)误阻,返回類型
BOOL
這里說重要注意是因?yàn)閙ethod swizzle
// 取得函數(shù)名稱
SEL originSel = @selector(setText:);
SEL swizzleSel = @selector(swizzleSetText:);
Method originMethod = class_getInstanceMethod(class, originSel);
Method swizzleMethod = class_getInstanceMethod(class, swizzleSel);
// 添加方法
BOOL addMethod = class_addMethod(class, originSel, method_getImplementation(swizzleMethod),method_getTypeEncoding(swizzleMethod));
- (了解)class_addProperty债蜜,(為類動(dòng)態(tài)添加屬性)晴埂,返回類型
BOOL
我們開發(fā)中一般用關(guān)聯(lián)對(duì)象添加屬性。
objc_property_attribute_t type = { "T", "@\"NSString\"" };//屬性類型為NSString
objc_property_attribute_t ownership = { "C", "copy" }; // C = copy
objc_property_attribute_t backingivar = { "V", "_personName" };
objc_property_attribute_t attrs[] = { type, ownership, backingivar };
class_addProperty([Person class], "personName", attrs, 3);
- (了解)class_addProtocol寻定,(為類動(dòng)態(tài)添加屬性)儒洛,返回類型
BOOL
class_addProtocol(<#Class _Nullable __unsafe_unretained cls#>, <#Protocol * _Nonnull protocol#>)
class_replace
- (重要)class_replaceMethod,(為類替換方法)
class_replaceMethod(class, swizzleSel, method_getImplementation(originMethod), method_getTypeEncoding(originMethod));
- (了解)class_replaceProperty狼速,(替換類的屬性)
void class_replaceProperty ( Class cls, const char *name, const objc_property_attribute_t *attributes, unsigned int attributeCount );
class_conformsTo
- (了解)class_conformsToProtocol,(類是否實(shí)現(xiàn)指定的協(xié)議) 琅锻,返回值類型(BOOL)
class_conformsToProtocol ( Class cls, Protocol *protocol );
實(shí)際開發(fā)我們一般用NSObject的- (BOOL)conformsToProtocol:(Protocol *)aProtocol;
方法。
class_respondsTo
- (了解)** class_respondsToSelector**,(是否可以響應(yīng)方法) 向胡,返回值類型(BOOL)
class_respondsToSelector(<#Class _Nullable __unsafe_unretained cls#>, <#SEL _Nonnull sel#>)
實(shí)際開發(fā)我們一般用NSObject的- (BOOL)respondsToSelector:(SEL)aSelector;
方法恼蓬。
objc_ 和 object_
-
objc_ 所有方法
官方文檔runtime objc_相關(guān).gif -
object_所有方法
屏幕快照 2018-08-03 下午3.01.26.png
objc_get
- (重要)objc_getClass,(獲取對(duì)象的類) ,返回值類型
Class
NSLog(@"%@",objc_getClass("Person"));
輸出
2018-08-03 15:26:46.212256+0800 runtime[30988:1216350] Person
在實(shí)際開發(fā)中我們一般用NSClassFromString()
來通過類名獲取一個(gè)類
- (重要)object_getClass,(獲取一個(gè)類isa指針指向的類) 僵芹,返回值類型
Class
4τ病!拇派!注意這個(gè)方法要和上面區(qū)分開荷辕,這是用來獲取isa指針指向的類凿跳,如果不知道isa指針的同學(xué)自己去百度
Class metaClass = object_getClass([Person class]);
NSLog(@"%@", class_isMetaClass(metaClass) ? @"是元類" : @"不是元類");
NSLog(@"%@", class_isMetaClass([Person class]) ? @"是元類" : @"不是元類");
NSLog(@"Person類的isa指向%@",object_getClass([Person class]));
NSLog(@"Person元類的isa指向%@",object_getClass(object_getClass([Person class])));
NSLog(@"NSObject元類的isa指向%@",object_getClass(object_getClass(object_getClass([Person class]))));
NSLog(@"NSObject元類的父類 = %@",class_getSuperclass(object_getClass(object_getClass([Person class]))));
NSLog(@"NSObject元類的父類的父類 = %@",class_getSuperclass(class_getSuperclass(object_getClass(object_getClass([Person class])))));
輸出
2018-08-03 16:00:14.819770+0800 runtime[31283:1243260] 是元類
2018-08-03 16:00:14.819992+0800 runtime[31283:1243260] 不是元類
2018-08-03 16:00:14.820157+0800 runtime[31283:1243260] Person類的isa指向Person
2018-08-03 16:00:14.820287+0800 runtime[31283:1243260] Person元類的isa指向NSObject
2018-08-03 16:00:14.820417+0800 runtime[31283:1243260] NSObject元類的isa指向NSObject
2018-08-03 16:00:14.820518+0800 runtime[31283:1243260] NSObject元類的父類 = NSObject
2018-08-03 16:00:14.820645+0800 runtime[31283:1243260] NSObject元類的父類的父類 = (null)
我們可以看出 object_getClass方法是獲取一個(gè)類的元類,Person類的isa指針指向Person元類,Person元類的isa指針指向NSObject元類疮方,NSObject元類的isa指向自己控嗜,形成了一個(gè)閉環(huán)。并且NSObject元類的父類是NSObject骡显,NSObject的父類為null
是不是想起了一張圖
- (了解)objc_getMetaClass,(獲取類的元類) 疆栏,返回值類型
Class *
- (了解)object_getClassName,(獲取類的元類名稱) ,返回值類型
const char *
區(qū)別于object_getClass
獲取元類惫谤,objc_getMetaClass獲取元類用的是c字符串承边。既然object_getClass
是獲取一個(gè)對(duì)象的元類對(duì)象,那么object_getClassName
一個(gè)猜想的出來是獲取元類對(duì)象的名稱石挂。
NSLog(@"Person類的元類 = %@",objc_getMetaClass("Person"));
NSLog(@"Person元類的元類的名稱 = %s",object_getClassName(objc_getMetaClass("Person")));
NSLog(@"Person元類的isa指針指向 = %@",objc_getMetaClass(object_getClassName(objc_getMetaClass("Person"))));
輸出
2018-08-03 16:14:49.051873+0800 runtime[31357:1254499] Person類的isa指針 = Person
2018-08-03 16:14:49.052081+0800 runtime[31357:1254499] Person元類名稱 = NSObject
2018-08-03 16:14:49.052217+0800 runtime[31357:1254499] Person元類的isa指針指向 = NSObject
- (了解)objc_getProtocol,(獲取一個(gè)協(xié)議) 博助,返回值類型
Protocol *
Protocol *protocol = objc_getProtocol("PersonDelegate");
這個(gè)在實(shí)際開發(fā)中就是@protocol(PersonDelegate)
- (了解)objc_getClassList,(獲取類列表)
我們可以用這個(gè)方法來打印一個(gè)類所有的子類
int numClasses = 0, newNumClasses = objc_getClassList(NULL, 0);
Class *classes = NULL;
while (numClasses < newNumClasses) {
numClasses = newNumClasses;
classes = (Class *)realloc(classes, sizeof(Class) * numClasses);
newNumClasses = objc_getClassList(classes, numClasses);
for (int i = 0; i < numClasses; i++) {
const char *className = class_getName(classes[i]);
if (class_getSuperclass(classes[i]) == [UILabel class]) {
NSLog(@"%s" , className);
}
}
}
free(classes);
輸出UILabel的所有子類對(duì)象。
2018-08-03 16:45:45.430312+0800 runtime[31498:1276113] _MKUILabel
2018-08-03 16:45:45.430450+0800 runtime[31498:1276113] _UITableViewHeaderFooterViewLabel
2018-08-03 16:45:45.430567+0800 runtime[31498:1276113] _UIActivityGroupActivityCellTitleLabel
2018-08-03 16:45:45.430899+0800 runtime[31498:1276113] UITabBarButtonLabel
2018-08-03 16:45:45.431003+0800 runtime[31498:1276113] UITableViewLabel
2018-08-03 16:45:45.431205+0800 runtime[31498:1276113] UITextFieldLabel
2018-08-03 16:45:45.431304+0800 runtime[31498:1276113] UIButtonLabel
2018-08-03 16:45:45.431396+0800 runtime[31498:1276113] UIDateLabel
2018-08-03 16:45:45.431498+0800 runtime[31498:1276113] UITextLabel
2018-08-03 16:45:45.431594+0800 runtime[31498:1276113] UISegmentLabel
(了解)objc_getRequiredClass,(返回一個(gè)類痹愚,要是沒有這個(gè)類就去除這個(gè)類 ) 富岳,返回值類型
Protocol *
!!! 要設(shè)置Build Phase——》Compile Sources相應(yīng)文件ARC轉(zhuǎn)非ARC-fno-objc-arc;才能支持objc_getRequiredClass(重要)objc_getAssociatedObject,(關(guān)聯(lián)對(duì)象get) 拯腮,返回值類型
Protocol *
- (UILabel *)badge {
return objc_getAssociatedObject(self, _cmd);
}
- (void)setBadge:(UILabel *)label {
objc_setAssociatedObject(self, @selector(badge), label, OBJC_ASSOCIATION_RETAIN);
}
這里個(gè)人喜歡用@selector()即當(dāng)前方法選擇子來代替關(guān)鍵字窖式。
- (了解)object_getIvar,(獲取實(shí)例變量的值) ,返回值類型
id*
_person = [[Person alloc] init];
_person.name = @"小妹";
// 獲取_person實(shí)例對(duì)象中的name實(shí)例變量的值
NSString *name = object_getIvar(_person, class_getInstanceVariable([Person class], "_name"));
NSLog(@"name = %@",name);
輸出
2018-08-03 17:51:48.294600+0800 runtime[33733:1321519] name = 小妹
objc_copy
- (了解)objc_copyClassList 动壤,返回值類型
Class _Nonnull *
萝喘。
獲得已經(jīng)注冊(cè)的所有的類,下面打印UIScrollView的所有子類琼懊。
unsigned int outCount;
Class *classes = objc_copyClassList(&outCount);
for (int i = 0; i < outCount; i++) {
@autoreleasepool {
if (class_getSuperclass(classes[i]) == [UIScrollView class]) {
NSLog(@"%s",class_getName(classes[i]));
}
}
}
free(classes);
輸出
2018-08-05 19:32:34.376451+0800 runtime[37322:1424135] _MKPlacePhotoView
2018-08-05 19:32:34.376782+0800 runtime[37322:1424135] NUIContentScrollView
2018-08-05 19:32:34.376940+0800 runtime[37322:1424135] _UIInterfaceActionRepresentationsSequenceView
2018-08-05 19:32:34.377093+0800 runtime[37322:1424135] _UIQueuingScrollView
2018-08-05 19:32:34.377196+0800 runtime[37322:1424135] _UIAlertControllerShadowedScrollView
2018-08-05 19:32:34.377307+0800 runtime[37322:1424135] _UICompatibilityTextView
2018-08-05 19:32:34.377404+0800 runtime[37322:1424135] UIPrinterSetupPINScrollView
2018-08-05 19:32:34.377599+0800 runtime[37322:1424135] UITextView
2018-08-05 19:32:34.377743+0800 runtime[37322:1424135] UIWebOverflowScrollView
2018-08-05 19:32:34.377845+0800 runtime[37322:1424135] UIPageControllerScrollView
2018-08-05 19:32:34.378044+0800 runtime[37322:1424135] UIWebScrollView
2018-08-05 19:32:34.378150+0800 runtime[37322:1424135] UIFieldEditor
2018-08-05 19:32:34.378248+0800 runtime[37322:1424135] UITableView
2018-08-05 19:32:34.378335+0800 runtime[37322:1424135] UITableViewWrapperView
2018-08-05 19:32:34.378437+0800 runtime[37322:1424135] UICollectionView
(了解)objc_copyImageNames,(獲取所有加載的Objective-C框架和動(dòng)態(tài)庫的名稱) 阁簸,返回值類型
const char * _Nonnull *
(了解)objc_copyProtocolList,(獲取運(yùn)行時(shí)所知道的所有協(xié)議的數(shù)組) ,返回值類型
Protocol * __unsafe_unretained _Nonnull *
(了解)objc_copyClassNamesForImage,(獲取指定庫或框架中所有類的類名) 哼丈,返回值類型
const char * _Nonnull *
unsigned int outCount;
const char ** classes = objc_copyClassNamesForImage(class_getImageName(NSClassFromString(@"UIView")), &outCount);
for (int i = 0; i < outCount; i++) {
NSLog(@"class name: %s", classes[i]);
}
free(classes);
objc_set
- (重要)objc_setAssociatedObject,(設(shè)置關(guān)聯(lián)對(duì)象)
objc_setAssociatedObject(id _Nonnull object, //關(guān)聯(lián)對(duì)象
const void * _Nonnull key, // 關(guān)聯(lián)對(duì)象標(biāo)識(shí)符key启妹,我通常用@selector()作為標(biāo)識(shí)符
id _Nullable value, // 關(guān)聯(lián)對(duì)象的值
objc_AssociationPolicy policy) // 關(guān)聯(lián)對(duì)象的內(nèi)存管理語義
- objc_AssociationPolicy是一個(gè)枚舉
OBJC_ASSOCIATION_ASSIGN 等價(jià)于 @property(assign)。
OBJC_ASSOCIATION_RETAIN_NONATOMIC等價(jià)于 @property(strong, nonatomic)醉旦。
OBJC_ASSOCIATION_COPY_NONATOMIC等價(jià)于@property(copy, nonatomic)饶米。
OBJC_ASSOCIATION_RETAIN等價(jià)于@property(strong,atomic)。
OBJC_ASSOCIATION_COPY等價(jià)于@property(copy, atomic)
object_set
- (重要)object_setIvar,(設(shè)置實(shí)例變量的值)
_person = [[Person alloc] init];
_person.name = @"小妹";
object_setIvar(_person, class_getInstanceVariable([Person class], "_name"),@"新名字");
NSLog(@"name = %@",_person.name);
輸出
2018-08-05 20:29:36.249324+0800 runtime[37441:1457957] name = 新名字
- (重要)object_setClass,(設(shè)置對(duì)象的isa指向)
!!! 類對(duì)象中存儲(chǔ)著實(shí)例對(duì)象的實(shí)例方法车胡,元類對(duì)象中存儲(chǔ)著類的類方法檬输。如果改變isa指向,會(huì)導(dǎo)致本來是對(duì)A類的方法緩存或方法列表中查找Method匈棘,變成從B類中查找Method丧慈。
@interface Person : NSObject
// 在Person .h文件中,有eat方法
- (void)eat:(NSString *)foodName;
@end
@implementation Person
- (instancetype)init {
if (self = [super init]) {
// 改變isa指針指向Animal類
object_setClass(self, [Animal class]);
}
return self;
}
// 人吃食物
- (void)eat:(NSString *)foodName {
NSLog(@"人吃食物 : %@",foodName);
}
@end
@interface Animal : NSObject
- (void)eat:(NSString *)foodName;
@end
@implementation Animal
- (void)eat:(NSString *)foodName {
NSLog(@"動(dòng)物吃食物 : %@",foodName);
}
@end
調(diào)用方法
_person = [[Person alloc] init];
[_person eat:@"香蕉"];
輸出
2018-08-05 20:38:18.353851+0800 runtime[37495:1465311] 動(dòng)物吃食物 : 香蕉
所以真正調(diào)用方法的類并不一定是代碼中調(diào)用方法的那個(gè)類羹饰,最終和運(yùn)行時(shí)對(duì)象的isa指向有關(guān)伊滋。
- (了解)object_setIvarWithStrongDefault,(設(shè)置實(shí)例變量的值)
_person = [[Person alloc] init];
_person.name = @"小妹";
object_setIvarWithStrongDefault(_person, class_getInstanceVariable([Person class], "_name"),@"新名字");
NSLog(@"name = %@",_person.name);
輸出
2018-08-05 20:53:05.701262+0800 runtime[37528:1475141] name = 新名字
創(chuàng)建銷毀類
- (重要)** objc_allocateClassPair**,(創(chuàng)建一個(gè)類)
- (重要)** objc_registerClassPair**,(注冊(cè)一個(gè)類)
- (重要)** objc_disposeClassPair**,(銷毀一個(gè)類)
runtime能在運(yùn)行時(shí)動(dòng)態(tài)添加一個(gè)類
// 創(chuàng)建一個(gè)類
Class newClass = objc_allocateClassPair([Person class], "Man", 0);
// 方法
Method method = class_getInstanceMethod([self class], @selector(buyClothes));
// 為類添加一個(gè)方法
class_addMethod(newClass, method_getName(method), method_getImplementation(method), method_getTypeEncoding(method));
// 注冊(cè)類
objc_registerClassPair(newClass);
// 創(chuàng)建類的實(shí)例對(duì)象 alloc
id newInstance = class_createInstance(newClass, sizeof(unsigned));
// init
id hangzhouMan = [newInstance init];
// 調(diào)用方法
[hangzhouMan performSelector:@selector(buyClothes) withObject:nil];
創(chuàng)建類并調(diào)用方法碳却,輸出
2018-08-05 21:21:43.576871+0800 runtime[37627:1495822] 男人買衣服
銷毀
objc_disposeClassPair(newClass);
// 調(diào)用方法
[hangzhouMan performSelector:@selector(buyClothes) withObject:nil]
銷毀之后調(diào)用方法,出現(xiàn)EXC_BAD_ACCESS
ivar(實(shí)例變量)
先看看ivar在底層的數(shù)據(jù)結(jié)構(gòu)
typedef struct objc_ivar *Ivar;
struct objc_ivar {
char *ivar_name OBJC2_UNAVAILABLE; // 變量名
char *ivar_type OBJC2_UNAVAILABLE; // 變量類型
int ivar_offset OBJC2_UNAVAILABLE; // 基地址偏移字節(jié)
#ifdef __LP64__
int space OBJC2_UNAVAILABLE;
#endif
}
所有我們就能知道ivar
通過runtime
能獲得的變量
- (重要)ivar_getName,(獲取實(shí)例變量名) 笑旺,返回值類型
const char *
- (重要)ivar_getOffset,(獲取實(shí)例基地址偏移字節(jié)) 昼浦,返回值類型
int
- (重要)ivar_getTypeEncoding,(獲取實(shí)例變量類型) ,返回值類型
const char *
結(jié)合上面介紹的 - class_addIvar 筒主,(添加一個(gè)實(shí)例變量)
- class_getInstanceVariable 关噪,(獲取實(shí)例變量)
- object_setIvarWithStrongDefault ,(為實(shí)例變量賦值)
- object_setIvar 乌妙,(為實(shí)例變量賦值)
- object_getIvar 使兔,(獲取實(shí)例變量的值)
- class_copyIvarList ,(獲取類的實(shí)例變量列表)
我來創(chuàng)建一個(gè)類藤韵,并在類中添加實(shí)例變量虐沥,賦值并打印。
// 創(chuàng)建一個(gè)類newClass繼承Person
Class newClass = objc_allocateClassPair([Person class], "Man", 0);
// 添加實(shí)例變量_skinColor
BOOL flag1 = class_addIvar(newClass, "_skinColor", sizeof(NSString*), log2(sizeof(NSString *)), @encode(NSString *));
if (flag1) {
NSLog(@"NSString*類型 _skinColor變量添加成功");
}
// 注冊(cè)這個(gè)類
objc_registerClassPair(newClass);
// 獲取類的實(shí)例變量_skinColor
Ivar colorIvar = class_getInstanceVariable(newClass, "_skinColor");
// 創(chuàng)建實(shí)例對(duì)象instance
id instance = [class_createInstance(newClass, sizeof(unsigned)) init];
// 為這個(gè)實(shí)例對(duì)象的_skinColor賦值為黃色
object_setIvar(instance, colorIvar, @"黃色");
// 打印
NSLog(@"膚色skinColor = %@",object_getIvar(instance, colorIvar));
// 打印實(shí)例變量列表
unsigned int count = 0;
Ivar *ivarList = class_copyIvarList(newClass, &count);
for (int i = 0; i < count; i++) {
Ivar ivar = ivarList[i];
NSLog(@"實(shí)例變量name = %s",ivar_getName(ivar));
NSLog(@"實(shí)例變量變量類型type = %s",ivar_getTypeEncoding(ivar));
NSLog(@"實(shí)例變量地址偏移name = %td",ivar_getOffset(ivar));
}
輸出
2018-08-06 10:43:30.631866+0800 runtime[42814:1664021] NSString*類型 _skinColor變量添加成功
2018-08-06 10:43:30.632097+0800 runtime[42814:1664021] 膚色skinColor = 黃色
2018-08-06 10:43:30.632235+0800 runtime[42814:1664021] 實(shí)例變量name = _skinColor
2018-08-06 10:43:30.632406+0800 runtime[42814:1664021] 實(shí)例變量變量類型type = @
2018-08-06 10:43:30.632506+0800 runtime[42814:1664021] 實(shí)例變量地址偏移name = 32
Method
先看看Method在底層的數(shù)據(jù)結(jié)構(gòu)
typedef struct objc_method *Method;
struct objc_method {
SEL method_name OBJC2_UNAVAILABLE; // 方法名
char *method_types OBJC2_UNAVAILABLE; // 參數(shù)類型
IMP method_imp OBJC2_UNAVAILABLE; // 方法實(shí)現(xiàn)
}
所有我們就能知道Method
通過runtime
能獲得的變量
Method method = class_getInstanceMethod([self class], @selector(buyClothes));
NSLog(@"name = %s",sel_getName(method_getName(method)));
NSLog(@"TypeEncoding = %s",method_getTypeEncoding(method));
NSLog(@"參數(shù)個(gè)數(shù) = %u",method_getNumberOfArguments(method));
IMP imp = method_getImplementation(method);
輸出
2018-08-06 18:50:56.227579+0800 runtime[46116:1950929] name = buyClothes
2018-08-06 18:50:56.227773+0800 runtime[46116:1950929] TypeEncoding = v16@0:8
2018-08-06 18:50:56.227903+0800 runtime[46116:1950929] 參數(shù)個(gè)數(shù) = 2