oc底層原理學習
1、oc對象的本質是什麼
oc本質就是就是結構體,。
class_getInstanceSize([Student class])。
獲取對象佔用的內存。
可以用c語言來實現對象原理。
oc對象主要可以分爲三種:
- instance對象 (實例對象)
- objc_object 是這個
struct Student_IMPL {
Class isa;
//根類的實例變量
//倒數第二層父類的實例變量
…
//父類的實例變量
//類的實例變量
};
struct Student_IMPL {
struct NSObject_IMPL NSObject_IVARS;
int _no;
int _age;
NSString *_name;
NSString *_school;
}; - class 對象 (類對象)
- objc_class 是這個
struct object_class *isa;
struct objc_class {
struct objc_class isa;//或者叫Class isa;
const char *_NonNull name;
long version
long info
long instance_size
struct objc_ivar_list * _NUllable ivars;
struct oject_method_list * _Nullable * _Nullable methodLists
struct objc_cache * _Nonnull cache
struct objc_protocol_list * _Nullable protocols;
}
Printing description of ivarList:
<__NSArrayM 0x12d908690>(
_number1,
_number2,
_name,
_school
)
#import <Foundation/Foundation.h>
@interface Earth : NSObject {
int lang;
int uage;
}
@property(nonatomic, copy) NSString *country;
@property(nonatomic, copy) NSString *xinyang;
@end
@implementation Earth
@end
@interface Student : Earth {
@public
int _no;
int _age;
}
@property(nonatomic, copy) NSString *name;
@property(nonatomic, copy) NSString *school;
@end
@implementation Student
int main(int argc, const char *argv[]){
@autoreleasepool {
Student *stu = [[Student alloc] init];
stu -> _no = 4;
stu -> _age = 5;
NSLog(@"%@",stu);
}
return 0;
}
@end
沒有繼承的代碼
@interface Student : NSObject {
@public
int _no;
int _age;
}
@property(nonatomic, copy) NSString *name;
@property(nonatomic, copy) NSString *school;
@end
@implementation Student
int main(int argc, const char *argv[]){
@autoreleasepool {
Student *stu = [[Student alloc] init];
stu -> _no = 4;
stu -> _age = 5;
NSLog(@"%@",stu);
}
return 0;
}
@end
得到的測試數據:
clang獲得實例對象裏面的數據
struct Earth_IMPL {
struct NSObject_IMPL NSObject_IVARS;
int lang;
int uage;
NSString *_country;
NSString *_xinyang;
};
通過runtime獲取到的實例對象裏面的數據
struct Student_IMPL {
struct Earth_IMPL Earth_IVARS;
int _no;
int _age;
NSString *_name;
NSString *_school;
};
但是我們發現那個
+(NSArray *)getAllIvars
{
u_int count;
Ivar * ivars = class_copyIvarList([self class], &count);
NSMutableArray *lvarsArray = [NSMutableArray arrayWithCapacity:count];
for (int i = 0; i < count ; i++)
{
const char* ivarName = ivar_getName(ivars[i]);
[propertiesArray addObject: [NSString stringWithUTF8String: ivarName]];
}
free(ivars);
return lvarsArray;
}
獲取到的列表只有四個,即
Printing description of ivarList:
<__NSArrayM 0x1013014c0>(
_no,
_age,
_name,
_school
)
總結
- 測試發現實例變量在實例的結構體和Class結構體裏面都有。
- 實例對面通過結構體包含結構體羅列了從基類到目前類所有的實例變量
- 但是類對象裏面只獲取到本類的實例變量
簡稱:Class isa;
- meta-class 對象(元類對象)
這個也是Class isa;
2、instance 對象是什麼
instance 對象在內存中存儲的信息主要包括
- isa指針
- 成員變量
3、Class對象原理是什麼
我們通過class方法或runtime方法得到一個class對象,class對象也就是類對象
Class objectClass1 = [object1 class];
Class objectClass3 = [NSObject class];
class 對象在內存中存儲的信息主要包括
- isa指針
- superclass指針
- 類的屬性信息,類的成員變量信息
- 類的對象方法信息(instance method),類的協議信息(protocol)
4、meta-class對象
每個類在內存中有且只有一個meta-class對象。
meta-class對象和class對象的內存結構是一樣的,但是用途不一樣,在內存中存儲的信息主要包括。
- isa 指針
- superclass指針
- 類的類方法的信息(class method)
meta-class對象和class對象的內存結構是一樣的,所以meta-class中也有類的屬性信息,類的對象方法信息等成員變量,但其中的值可能是空的
5、isa指針指向哪裏
- 對象的isa指針指向了哪裏
[stu studentMethod]
(1)、當對象調用實例方法的時候,我們上面講到,實例方法信息是存儲在class類對象中的,那麼要想找到實例方法,就必須找到class類對象,就必須找到class類對象,那麼此時isa的作用就來了。
instance的isa指向class,當調用對象方法時,通過instance的isa找到class,最後找到對象方法的實現進行調用。
(2)、當類對象調用類方法的時候,同上,類方法是存儲在meta-class元類對象中的。那麼要找到類方法,就需要找到meta-class元類對象,而class類對象的isa指針就指向元類對象。
(3)、當對象調用其父類對象方法的時候,又是怎麼找到父類對象的方法呢?,此時就需要使用到class類對象的superclass指針。
[stu personMethod]
[stu init]
當Student的instance對象要調用Person的對象時,會先通過isa找到student的class,然後通過superclass找到person的class,最後找到對象方法的實現進行調用,同樣如果person發現自己沒有響應的對象方法,又會通過Person的superclass指針找到NSObject的class對象,去尋找響應的方法。
(4)當類對象調用父類的類方法時,就需要先通過isa指針找到meta-class,然後通過superclass去尋找響應的方法。
[student personClassMethod];
[student load];
當Student的class要調用Person的類方法時,會先通過isa找到Student的meta-class,然後通過superclass找到Person的meta-class,最後找到類方法的實現進行調用。
第二次學習
類對象
typedef struct objc_class *Class;
實例對象
struct objc_object {
Class _Nonnull isa OBJC_ISA_AVAILABILITY;
};
優秀提問
- 爲什麼不能通過runtime增加屬性呢?