Objective-C的本質(zhì)
Objective-C -> C/C++ -> 匯編語言 ->機器語言
Objective-C 簡單轉(zhuǎn)換 C\C++代碼(代碼比較多)
clang -rewrite-objc main.m -o main.cpp
轉(zhuǎn)換成對應平臺下cpp文件
模擬器(i386, x86-64) 32bit(armv7) 64bit(arm64)
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main-arm64.cpp
Objective-C的面向?qū)ο蠖际腔贑\C++實現(xiàn)的,本質(zhì)是結(jié)構(gòu)體.
@interface NSObject <NSObject> {
Class isa;
}
struct NSObject_IMPL {
Class isa;
};
typedef struct objc_class *Class;
至少需要多少內(nèi)存(計算結(jié)構(gòu)體內(nèi)存大小)
class_getInstanceSize([NSObject class]) // 8
實際分配內(nèi)存大小(操作系統(tǒng)內(nèi)存對齊)
malloc_size((__bridge const void *)([[NSObject alloc] init])) // 16
指針變量obj占用多少內(nèi)存空間
NSObject *obj = [[NSObject alloc] init];
sizeof(obj); //8
Objective-C的分類
instance對象(實例對象)
obj是NSObject的instance對象(實例對象)
NSObject *obj = [[NSObject alloc] init];
instance對象在內(nèi)存中存儲信息主要包括
isa指針
其他成員變量
......
class對象(類對象)
objClass1,objClass2,objClass3是同一個對象,每個類有且只有一個類對象
Class objClass1 = [obj class];
Class objClass2 = [NSObject class];
Class objClass3 = object_getClass(obj);
class對象在內(nèi)存中存儲信息主要包括
isa指針
superClass指針
類的屬性(@property),類的對象方法(instance method)
類的協(xié)議(protocol),類的成員變量(ivar)
......
meta-class對象(元類對象)
objMetaClass是NSObject的元類對象,每個類有且只有一個元類對象
Class objMetaClass = object_getClass([NSObject class]);
是否是元類對象
BOOL isMeta = class_isMetaClass(objMetaClass);
元類對象是特殊的類對象
meta-class對象在內(nèi)存中存儲信息主要包括
isa指針
superClass指針
類的類方法(class method)
......
isa指針和superClass指針
instance對象 isa -> class對象 -> meta-class對象 -> 基類的meta-class對象
class的superClass -> 父類的class(若是空,superClass是nil)
meta-class的superClass -> 父類的meta-class
基類的meta-class的superClass -> 基類的class
instance調(diào)用對象方法路徑: isa找到class,若不存在,通過superClass找父類
class調(diào)用類方法路徑:isa找meta-class,若不存在,通過superClass找父類

isa指針
從64位開始優(yōu)化,需要&ISA_MASK
instance的 isa & ISA_MASK 得到 class的isa
class的 isa & ISA_MASK 得到 meta-class 的isa
objc4源碼查看 https://opensource.apple.com/tarballs/objc4/
typedef struct objc_class *Class;
struct objc_class {
Class isa;
Class superClass;
cache_t cache; //方法緩存
class_data_bits_t bits; //用于獲取具體的類信息
......
};
bits & FAST_DATA_MASK 得到 class_rw_t
struct class_rw_t {
uint32_t flags;
uint32_t version;
const class_ro_t *ro;
method_array_t methods;
property_array_t properties;
protocol_array_t protocols;
Class firstSubclass;
Class nextSiblingClass;
char *demangledName;
......
};
struct class_ro_t {
uint32_t flags;
uint32_t instanceStart;
uint32_t instanceSize;
#ifdef __LP64__
uint32_t reserved;
#endif
const uint8_t * ivarLayout;
const char * name;
method_list_t * baseMethodList;
protocol_list_t * baseProtocols;
const ivar_list_t * ivars;
const uint8_t * weakIvarLayout;
property_list_t *baseProperties;
method_list_t *baseMethods() const {
return baseMethodList;
}
};
KVO的全稱是Key-Value Observing,俗稱“鍵值監(jiān)聽”,可以用于監(jiān)聽某個對象屬性值的改變
KVO代碼層面使用
//添加監(jiān)聽屬性
- (void)addKVOTest {
self.kvo = [[KVOTest alloc] init];
NSKeyValueObservingOptions options = NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld;
[self.kvo addObserver:self forKeyPath:@"age" options:options context:@"123"];
}
//合適時機銷毀
- (void)dealloc {
[self.kvo removeObserver:self forKeyPath:@"age"];
}
//監(jiān)聽屬性的變化
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary<NSKeyValueChangeKey,id> *)change
context:(void *)context {
NSLog(@"監(jiān)聽到%@的%@屬性值改變了 - %@ - %@", object, keyPath, change, context);
}
KVO底層原理:
使用KVO監(jiān)聽后,runtime會動態(tài)創(chuàng)建一個 NSKVONotifying_監(jiān)聽類,是監(jiān)聽類的子類
調(diào)用方法順序
willChangeValueForKey:
setAge: ( Foundation下_NSSetIntValueAndNotify() )
observerValueForKey
didChangeValueForKey:
KVC的全稱是Key-Value Coding,俗稱“鍵值編碼”,可以通過一個key來訪問某個屬性
- (void)setValue:(id)value forKeyPath:(NSString *)keyPath;
- (void)setValue:(id)value forKey:(NSString *)key;
- (id)valueForKeyPath:(NSString *)keyPath;
- (id)valueForKey:(NSString *)key;
setValueForKey的流程
1、按照setKey、_setKey順序查找方法, 找到了直接調(diào)用方法
2、如果找不到,查看accessInstanceVariablesDirectly(能否直接訪問成員變量)的返回值,
NO,直接報錯 setValue:forUndefinedKey:,
YES,通過_key, _isKey, key, isKey順序查找成員變量,找到了直接賦值,都找不到直接報錯 setValue:forUndefinedKey:
valueForKey的流程
1、按照getKey、Key、isKey、_key的順序查找方法,找到直接調(diào)用
2、如果找不到,查看accessInstanceVariablesDirectly(能否直接訪問成員變量)的返回值,
NO,直接報錯 setValue:forUndefinedKey:,
YES,通過_key, _isKey, key, isKey順序查找成員變量,找到了直接取值,都找不到直接報錯 setValue:forUndefinedKey:
Category
分類的底層結(jié)構(gòu)
終端輸入
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc NSObject+FenLeiTest.m
struct _category_t {
const char *name;
struct _class_t *cls;
const struct _method_list_t *instance_methods;
const struct _method_list_t *class_methods;
const struct _protocol_list_t *protocols;
const struct _prop_list_t *properties;
};
1、通過Runtime加載某個類的所有Category數(shù)據(jù)
2、把所有Category的方法、屬性、協(xié)議數(shù)據(jù),合并到一個大數(shù)組中
后面參與編譯的Category數(shù)據(jù),會在數(shù)組的前面
3、將合并后的分類數(shù)據(jù)(方法、屬性、協(xié)議),插入到類原來數(shù)據(jù)的前面