- objc_object: 我们平时所使用的数据结构都是id类型的,对应到runtime中的类型是objc_object,其中包含isa_t、关于isa操作相关的方法、弱引用相关的方法、关联对象相关的方法、内存管理相关的方法
struct objc_object {
private:
isa_t isa;
public:
// ISA() assumes this is NOT a tagged pointer object
Class ISA();
// getIsa() allows this to be a tagged pointer object
Class getIsa();
// initIsa() should be used to init the isa of new objects only.
// If this object already has an isa, use changeIsa() for correctness.
// initInstanceIsa(): objects with no custom RR/AWZ
// initClassIsa(): class objects
// initProtocolIsa(): protocol objects
// initIsa(): other objects
void initIsa(Class cls /*nonpointer=false*/);
void initClassIsa(Class cls /*nonpointer=maybe*/);
void initProtocolIsa(Class cls /*nonpointer=maybe*/);
void initInstanceIsa(Class cls, bool hasCxxDtor);
// changeIsa() should be used to change the isa of existing objects.
// If this is a new object, use initIsa() for performance.
Class changeIsa(Class newCls);
bool hasNonpointerIsa();
bool isTaggedPointer();
bool isBasicTaggedPointer();
bool isExtTaggedPointer();
bool isClass();
// object may have associated objects?
bool hasAssociatedObjects();
void setHasAssociatedObjects();
// object may be weakly referenced?
bool isWeaklyReferenced();
void setWeaklyReferenced_nolock();
// object may have -.cxx_destruct implementation?
bool hasCxxDtor();
// Optimized calls to retain/release methods
id retain();
void release();
id autorelease();
// Implementations of retain/release methods
id rootRetain();
bool rootRelease();
id rootAutorelease();
bool rootTryRetain();
bool rootReleaseShouldDealloc();
uintptr_t rootRetainCount();
// Implementation of dealloc methods
bool rootIsDeallocating();
void clearDeallocating();
void rootDealloc();
private:
void initIsa(Class newCls, bool nonpointer, bool hasCxxDtor);
// Slow paths for inline control
id rootAutorelease2();
bool overrelease_error();
#if SUPPORT_NONPOINTER_ISA
// Unified retain count manipulation for nonpointer isa
id rootRetain(bool tryRetain, bool handleOverflow);
bool rootRelease(bool performDealloc, bool handleUnderflow);
id rootRetain_overflow(bool tryRetain);
bool rootRelease_underflow(bool performDealloc);
void clearDeallocating_slow();
// Side table retain count overflow for nonpointer isa
void sidetable_lock();
void sidetable_unlock();
void sidetable_moveExtraRC_nolock(size_t extra_rc, bool isDeallocating, bool weaklyReferenced);
bool sidetable_addExtraRC_nolock(size_t delta_rc);
size_t sidetable_subExtraRC_nolock(size_t delta_rc);
size_t sidetable_getExtraRC_nolock();
#endif
// Side-table-only retain count
bool sidetable_isDeallocating();
void sidetable_clearDeallocating();
bool sidetable_isWeaklyReferenced();
void sidetable_setWeaklyReferenced_nolock();
id sidetable_retain();
id sidetable_retain_slow(SideTable& table);
uintptr_t sidetable_release(bool performDealloc = true);
uintptr_t sidetable_release_slow(SideTable& table, bool performDealloc = true);
bool sidetable_tryRetain();
uintptr_t sidetable_retainCount();
#if DEBUG
bool sidetable_present();
#endif
};
- objc_class:我们在OC中使用的Class在runtime中对应objc_class,objc_class继承自objc_object,其中包括Class superclass、cache_t cache、class_data_bits_t bits等
struct objc_class : objc_object {
// Class ISA;
Class superclass;
cache_t cache; // formerly cache pointer and vtable
class_data_bits_t bits; // class_rw_t * plus custom rr/alloc flags
class_rw_t *data() {
return bits.data();
}
void setData(class_rw_t *newData) {
bits.setData(newData);
}
void setInfo(uint32_t set) {
assert(isFuture() || isRealized());
data()->setFlags(set);
}
void clearInfo(uint32_t clear) {
assert(isFuture() || isRealized());
data()->clearFlags(clear);
}
// set and clear must not overlap
void changeInfo(uint32_t set, uint32_t clear) {
assert(isFuture() || isRealized());
assert((set & clear) == 0);
data()->changeFlags(set, clear);
}
bool hasCustomRR() {
return ! bits.hasDefaultRR();
}
void setHasDefaultRR() {
assert(isInitializing());
bits.setHasDefaultRR();
}
void setHasCustomRR(bool inherited = false);
void printCustomRR(bool inherited);
bool hasCustomAWZ() {
return ! bits.hasDefaultAWZ();
}
void setHasDefaultAWZ() {
assert(isInitializing());
bits.setHasDefaultAWZ();
}
void setHasCustomAWZ(bool inherited = false);
void printCustomAWZ(bool inherited);
bool instancesRequireRawIsa() {
return bits.instancesRequireRawIsa();
}
void setInstancesRequireRawIsa(bool inherited = false);
void printInstancesRequireRawIsa(bool inherited);
bool canAllocNonpointer() {
assert(!isFuture());
return !instancesRequireRawIsa();
}
bool canAllocFast() {
assert(!isFuture());
return bits.canAllocFast();
}
bool hasCxxCtor() {
// addSubclass() propagates this flag from the superclass.
assert(isRealized());
return bits.hasCxxCtor();
}
void setHasCxxCtor() {
bits.setHasCxxCtor();
}
bool hasCxxDtor() {
// addSubclass() propagates this flag from the superclass.
assert(isRealized());
return bits.hasCxxDtor();
}
void setHasCxxDtor() {
bits.setHasCxxDtor();
}
bool isSwiftStable() {
return bits.isSwiftStable();
}
bool isSwiftLegacy() {
return bits.isSwiftLegacy();
}
bool isAnySwift() {
return bits.isAnySwift();
}
// Return YES if the class's ivars are managed by ARC,
// or the class is MRC but has ARC-style weak ivars.
bool hasAutomaticIvars() {
return data()->ro->flags & (RO_IS_ARC | RO_HAS_WEAK_WITHOUT_ARC);
}
// Return YES if the class's ivars are managed by ARC.
bool isARC() {
return data()->ro->flags & RO_IS_ARC;
}
#if SUPPORT_NONPOINTER_ISA
// Tracked in non-pointer isas; not tracked otherwise
#else
bool instancesHaveAssociatedObjects() {
// this may be an unrealized future class in the CF-bridged case
assert(isFuture() || isRealized());
return data()->flags & RW_INSTANCES_HAVE_ASSOCIATED_OBJECTS;
}
void setInstancesHaveAssociatedObjects() {
// this may be an unrealized future class in the CF-bridged case
assert(isFuture() || isRealized());
setInfo(RW_INSTANCES_HAVE_ASSOCIATED_OBJECTS);
}
#endif
bool shouldGrowCache() {
return true;
}
void setShouldGrowCache(bool) {
// fixme good or bad for memory use?
}
bool isInitializing() {
return getMeta()->data()->flags & RW_INITIALIZING;
}
void setInitializing() {
assert(!isMetaClass());
ISA()->setInfo(RW_INITIALIZING);
}
bool isInitialized() {
return getMeta()->data()->flags & RW_INITIALIZED;
}
void setInitialized();
bool isLoadable() {
assert(isRealized());
return true; // any class registered for +load is definitely loadable
}
IMP getLoadMethod();
// Locking: To prevent concurrent realization, hold runtimeLock.
bool isRealized() {
return data()->flags & RW_REALIZED;
}
// Returns true if this is an unrealized future class.
// Locking: To prevent concurrent realization, hold runtimeLock.
bool isFuture() {
return data()->flags & RW_FUTURE;
}
bool isMetaClass() {
assert(this);
assert(isRealized());
return data()->ro->flags & RO_META;
}
// NOT identical to this->ISA when this is a metaclass
Class getMeta() {
if (isMetaClass()) return (Class)this;
else return this->ISA();
}
bool isRootClass() {
return superclass == nil;
}
bool isRootMetaclass() {
return ISA() == (Class)this;
}
const char *mangledName() {
// fixme can't assert locks here
assert(this);
if (isRealized() || isFuture()) {
return data()->ro->name;
} else {
return ((const class_ro_t *)data())->name;
}
}
const char *demangledName(bool realize = false);
const char *nameForLogging();
// May be unaligned depending on class's ivars.
uint32_t unalignedInstanceStart() {
assert(isRealized());
return data()->ro->instanceStart;
}
// Class's instance start rounded up to a pointer-size boundary.
// This is used for ARC layout bitmaps.
uint32_t alignedInstanceStart() {
return word_align(unalignedInstanceStart());
}
// May be unaligned depending on class's ivars.
uint32_t unalignedInstanceSize() {
assert(isRealized());
return data()->ro->instanceSize;
}
// Class's ivar size rounded up to a pointer-size boundary.
uint32_t alignedInstanceSize() {
return word_align(unalignedInstanceSize());
}
size_t instanceSize(size_t extraBytes) {
size_t size = alignedInstanceSize() + extraBytes;
// CF requires all objects be at least 16 bytes.
if (size < 16) size = 16;
return size;
}
void setInstanceSize(uint32_t newSize) {
assert(isRealized());
if (newSize != data()->ro->instanceSize) {
assert(data()->flags & RW_COPIED_RO);
*const_cast(&data()->ro->instanceSize) = newSize;
}
bits.setFastInstanceSize(newSize);
}
void chooseClassArrayIndex();
void setClassArrayIndex(unsigned Idx) {
bits.setClassArrayIndex(Idx);
}
unsigned classArrayIndex() {
return bits.classArrayIndex();
}
};
- isa指针实际是一个联合体类型
- 在实例对象中,其isa指向为其class对象,调用实例方法在其class对象中查找
- 在类对象中,其isa指向为其metaclass(元类对象),类方法存储于metaclass中
union isa_t {
isa_t() { } // union 的构造函数
isa_t(uintptr_t value) : bits(value) { }
Class cls;
uintptr_t bits;
#if defined(ISA_BITFIELD)
struct {
ISA_BITFIELD; // defined in isa.h
};
#endif
};
- cache_t
- 是可增量扩展的哈希表结构
- 增量扩展:即当结构体存储的量增大的同时存储空间也跟随扩大以满足存储需要
- 是局部性原理的最佳应用
- 局部性原理:保存近期频繁被访问的主存单元数据,在此处即为对频繁调用方法的一个缓存以提高后期调用方法效率
- 用于快速查找方法执行的函数,当调用方法时会优先到该缓存中查找,同时调用过的方法也会被缓存到该结构中
- 是可增量扩展的哈希表结构
struct cache_t {
struct bucket_t *_buckets;
mask_t _mask;
mask_t _occupied;
public:
struct bucket_t *buckets();
mask_t mask();
mask_t occupied();
void incrementOccupied();
void setBucketsAndMask(struct bucket_t *newBuckets, mask_t newMask);
void initializeToEmpty();
mask_t capacity();
bool isConstantEmptyCache();
bool canBeFreed();
static size_t bytesForCapacity(uint32_t cap);
static struct bucket_t * endMarker(struct bucket_t *b, uint32_t cap);
void expand();
void reallocate(mask_t oldCapacity, mask_t newCapacity);
struct bucket_t * find(cache_key_t key, id receiver);
static void bad_cache(id receiver, SEL sel, Class isa) __attribute__((noreturn));
};
- class_data_bits_t
- 主要是对class_rw_t的封装
- class_rw_t代表了相关的类读写信息
- class_ro_t代表相关的只读信息
struct class_data_bits_t {
// Values are the FAST_ flags above.
uintptr_t bits;
private:
bool getBit(uintptr_t bit)
{
return bits & bit;
}
#if FAST_ALLOC
static uintptr_t updateFastAlloc(uintptr_t oldBits, uintptr_t change)
{
if (change & FAST_ALLOC_MASK) {
if (((oldBits & FAST_ALLOC_MASK) == FAST_ALLOC_VALUE) &&
((oldBits >> FAST_SHIFTED_SIZE_SHIFT) != 0))
{
oldBits |= FAST_ALLOC;
} else {
oldBits &= ~FAST_ALLOC;
}
}
return oldBits;
}
#else
static uintptr_t updateFastAlloc(uintptr_t oldBits, uintptr_t change) {
return oldBits;
}
#endif
void setBits(uintptr_t set)
{
uintptr_t oldBits;
uintptr_t newBits;
do {
oldBits = LoadExclusive(&bits);
newBits = updateFastAlloc(oldBits | set, set);
} while (!StoreReleaseExclusive(&bits, oldBits, newBits));
}
void clearBits(uintptr_t clear)
{
uintptr_t oldBits;
uintptr_t newBits;
do {
oldBits = LoadExclusive(&bits);
newBits = updateFastAlloc(oldBits & ~clear, clear);
} while (!StoreReleaseExclusive(&bits, oldBits, newBits));
}
public:
class_rw_t* data() {
return (class_rw_t *)(bits & FAST_DATA_MASK);
}
void setData(class_rw_t *newData)
{
assert(!data() || (newData->flags & (RW_REALIZING | RW_FUTURE)));
// Set during realization or construction only. No locking needed.
// Use a store-release fence because there may be concurrent
// readers of data and data's contents.
uintptr_t newBits = (bits & ~FAST_DATA_MASK) | (uintptr_t)newData;
atomic_thread_fence(memory_order_release);
bits = newBits;
}
#if FAST_HAS_DEFAULT_RR
bool hasDefaultRR() {
return getBit(FAST_HAS_DEFAULT_RR);
}
void setHasDefaultRR() {
setBits(FAST_HAS_DEFAULT_RR);
}
void setHasCustomRR() {
clearBits(FAST_HAS_DEFAULT_RR);
}
#else
bool hasDefaultRR() {
return data()->flags & RW_HAS_DEFAULT_RR;
}
void setHasDefaultRR() {
data()->setFlags(RW_HAS_DEFAULT_RR);
}
void setHasCustomRR() {
data()->clearFlags(RW_HAS_DEFAULT_RR);
}
#endif
#if FAST_HAS_DEFAULT_AWZ
bool hasDefaultAWZ() {
return getBit(FAST_HAS_DEFAULT_AWZ);
}
void setHasDefaultAWZ() {
setBits(FAST_HAS_DEFAULT_AWZ);
}
void setHasCustomAWZ() {
clearBits(FAST_HAS_DEFAULT_AWZ);
}
#else
bool hasDefaultAWZ() {
return data()->flags & RW_HAS_DEFAULT_AWZ;
}
void setHasDefaultAWZ() {
data()->setFlags(RW_HAS_DEFAULT_AWZ);
}
void setHasCustomAWZ() {
data()->clearFlags(RW_HAS_DEFAULT_AWZ);
}
#endif
#if FAST_HAS_CXX_CTOR
bool hasCxxCtor() {
return getBit(FAST_HAS_CXX_CTOR);
}
void setHasCxxCtor() {
setBits(FAST_HAS_CXX_CTOR);
}
#else
bool hasCxxCtor() {
return data()->flags & RW_HAS_CXX_CTOR;
}
void setHasCxxCtor() {
data()->setFlags(RW_HAS_CXX_CTOR);
}
#endif
#if FAST_HAS_CXX_DTOR
bool hasCxxDtor() {
return getBit(FAST_HAS_CXX_DTOR);
}
void setHasCxxDtor() {
setBits(FAST_HAS_CXX_DTOR);
}
#else
bool hasCxxDtor() {
return data()->flags & RW_HAS_CXX_DTOR;
}
void setHasCxxDtor() {
data()->setFlags(RW_HAS_CXX_DTOR);
}
#endif
#if FAST_REQUIRES_RAW_ISA
bool instancesRequireRawIsa() {
return getBit(FAST_REQUIRES_RAW_ISA);
}
void setInstancesRequireRawIsa() {
setBits(FAST_REQUIRES_RAW_ISA);
}
#elif SUPPORT_NONPOINTER_ISA
bool instancesRequireRawIsa() {
return data()->flags & RW_REQUIRES_RAW_ISA;
}
void setInstancesRequireRawIsa() {
data()->setFlags(RW_REQUIRES_RAW_ISA);
}
#else
bool instancesRequireRawIsa() {
return true;
}
void setInstancesRequireRawIsa() {
// nothing
}
#endif
#if FAST_ALLOC
size_t fastInstanceSize()
{
assert(bits & FAST_ALLOC);
return (bits >> FAST_SHIFTED_SIZE_SHIFT) * 16;
}
void setFastInstanceSize(size_t newSize)
{
// Set during realization or construction only. No locking needed.
assert(data()->flags & RW_REALIZING);
// Round up to 16-byte boundary, then divide to get 16-byte units
newSize = ((newSize + 15) & ~15) / 16;
uintptr_t newBits = newSize << FAST_SHIFTED_SIZE_SHIFT;
if ((newBits >> FAST_SHIFTED_SIZE_SHIFT) == newSize) {
int shift = WORD_BITS - FAST_SHIFTED_SIZE_SHIFT;
uintptr_t oldBits = (bits << shift) >> shift;
if ((oldBits & FAST_ALLOC_MASK) == FAST_ALLOC_VALUE) {
newBits |= FAST_ALLOC;
}
bits = oldBits | newBits;
}
}
bool canAllocFast() {
return bits & FAST_ALLOC;
}
#else
size_t fastInstanceSize() {
abort();
}
void setFastInstanceSize(size_t) {
// nothing
}
bool canAllocFast() {
return false;
}
#endif
void setClassArrayIndex(unsigned Idx) {
#if SUPPORT_INDEXED_ISA
// 0 is unused as then we can rely on zero-initialisation from calloc.
assert(Idx > 0);
data()->index = Idx;
#endif
}
unsigned classArrayIndex() {
#if SUPPORT_INDEXED_ISA
return data()->index;
#else
return 0;
#endif
}
bool isAnySwift() {
return isSwiftStable() || isSwiftLegacy();
}
bool isSwiftStable() {
return getBit(FAST_IS_SWIFT_STABLE);
}
void setIsSwiftStable() {
setBits(FAST_IS_SWIFT_STABLE);
}
bool isSwiftLegacy() {
return getBit(FAST_IS_SWIFT_LEGACY);
}
void setIsSwiftLegacy() {
setBits(FAST_IS_SWIFT_LEGACY);
}
};
- class_rw_t的结构体如下,其中包含class_ro_t *ro、method_array_t methods、property_array_t properties、 protocol_array_t protocols,其中list_array_t均为二维数组,其中存储的内容一般为Category中添加的内容
struct class_rw_t {
// Be warned that Symbolication knows the layout of this structure.
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;
#if SUPPORT_INDEXED_ISA
uint32_t index;
#endif
void setFlags(uint32_t set)
{
OSAtomicOr32Barrier(set, &flags);
}
void clearFlags(uint32_t clear)
{
OSAtomicXor32Barrier(clear, &flags);
}
// set and clear must not overlap
void changeFlags(uint32_t set, uint32_t clear)
{
assert((set & clear) == 0);
uint32_t oldf, newf;
do {
oldf = flags;
newf = (oldf | set) & ~clear;
} while (!OSAtomicCompareAndSwap32Barrier(oldf, newf, (volatile int32_t *)&flags));
}
};
- class_ro_t,其中存储了当前类在编译期就已经确定的属性、方法以及遵循的协议,在编译期间类的结构中的 class_data_bits_t data 指向的是一个 class_ro_t 指针
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;
}
};
- 函数的四要素:名称、返回值、参数、函数体,其中method_t的结构体如下
struct method_t {
SEL name; //名称
/*
类型,返回值和参数的组合,对应四要素中的返回值和参数
Type Encodings技术
规顺序则:返回值 | 参数1 | 参数2.... 参数n
eg: -(void)aMethod; v@:
*/
const char *types;
MethodListIMP imp; //无类型的函数指针,对应四要素中的函数体
struct SortBySELAddress :
public std::binary_function
{
bool operator() (const method_t& lhs,
const method_t& rhs)
{ return lhs.name < rhs.name; }
};
};
总体来说,iOS对象中内存分布如下图
对象、类对象、元类对象
- 类对象存储实例方法列表等信息
- 元类对象存储类方法列表等信息
- 类对象的isa指针指向元类,元类对象的isa指向根元类
- 任何元类对象的isa都指向根元类,根元类的superclass指向rootclass,其指向结构如下图
如图,当进行实例方法查找时会按照红线的走向在类对象中查找,进行类方法查找时会根据红线指向在元类中查找,如果在根元类中仍未找到对应的方法则会进行实例方法的查找
消息传递的机制?
- 在当前类对象中查找
- 查找cache中是否有该方法,由于存储是根据哈希方式存储的,所以查找也是哈希查找,如果没有命中则进行下一步操作
- 对于已排序好的列表,采用二分查找散发查找方法对应执行函数
- 对于没排序的列表采用一般遍历查找方法对应执行函数
- 到父类(或父类的元类)中查找该方法,如果没命中继续向父类查找
- 查找cache中是否有该方法,由于存储是根据哈希方式存储的,所以查找也是哈希查找,如果没有命中则进行下一步操作
- 对于已排序好的列表,采用二分查找散发查找方法对应执行函数
- 对于没排序的列表采用一般遍历查找方法对应执行函数
- 在当前类对象中查找
消息转发流程
void countFindMethod() {
NSLog(@"未找到实例函数实现");
}
static void countFindClassMethod() {
NSLog(@"未找到类函数实现");
}
+ (BOOL)resolveClassMethod:(SEL)sel
{
if ([NSStringFromSelector(sel) isEqualToString:@"unrealizeMethod"]) {
SEL aSel = NSSelectorFromString(@"unrealizeMethod");
//给方法添加
class_addMethod(objc_getMetaClass([NSStringFromClass(self) UTF8String]), aSel, countFindClassMethod, "v@");
return YES;
}
return NO;
}
//给开发者提供添加或调用其它方法的机会
+ (BOOL)resolveInstanceMethod:(SEL)sel
{
if ([NSStringFromSelector(sel) isEqualToString:@"unrealizeMethod"]) {
SEL aSel = NSSelectorFromString(@"unrealizeMethod");
//给方法添加
class_addMethod(self, aSel, countFindMethod, "v@");
return YES;
}
return NO;
}
//如果上面没有对消息进行处理,则进入该方法,该方法用于返回相应对象,如果不进行处理则进入methodSignatureForSelector:方法
- (id)forwardingTargetForSelector:(SEL)aSelector
{
// Student * std = [[Student alloc] init];
return nil;
}
//通过检查不是此方法本身的选择器并且不发送可能调用此方法的任何消息,请务必在必要时避免无限循环。aSelector,例如,如果您的代理只是将消息转发给名为的实例变量,它可以像这样实现:realObjectmethodSignatureForSelector:
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
return [realObject methodSignatureForSelector:aSelector];
}
- (void)forwardInvocation:(NSInvocation *)anInvocation
{
[anInvocation setTarget:realObject];
[anInvocation invoke];
}
//如果在上面的方法中仍未实现对消息的处理则会进入此步骤抛出错误
- (void)doesNotRecognizeSelector:(SEL)aSelector
{
}
- 方法交换
+ (void)load
{
Method method1 = class_getInstanceMethod(self, @selector(test1));
Method method2 = class_getInstanceMethod(self, @selector(test2));
method_exchangeImplementations(method1, method2);
}
- (void)test1
{
NSLog(@"test1函数");
}
- (void)test2
{
NSLog(@"test2函数");
}
@dynamic与@synthesize的最基本的理解
- @property有两个对应的词,一个是@synthesize,一个是@dynamic。如果@synthesize和@dynamic都没写,那么默认的就是@syntheszie var = _var;
- @synthesize的语义是如果你没有手动实现setter方法和getter方法,那么编译器会自动为你加上这两个方法。
- @dynamic告诉编译器,属性的setter与getter方法由用户自己实现,在编译时不需要自动生成。(当然对于readonly的属性只需提供getter即可)。假如一个属性被声明为@dynamic var,然后你没有提供@setter方法和@getter方法,编译的时候没问题,但是当程序运行到instance.var =someVar,由于缺setter方法会导致程序崩溃;或者当运行到 someVar = var时,由于缺getter方法同样会导致崩溃。编译时没问题,运行时才执行相应的方法,这就是所谓的动态绑定。
- 动态运行时语言将函数决议推迟到运行时,编译时语言在编译器进行函数决议(确定调用哪个函数),
- 能否给编译后的类添加实例变量
- 类在注册之前能添加内容,但是再编译后是无法修改的;但是可以在动态添加的类注册之前添加实例变量
//动态 添加类的名称
Class TestClass = objc_allocateClassPair([NSObject class], "LGClass", 0);
NSString * name = @"name";
//给类添加属性
class_addIvar(TestClass,name.UTF8String,sizeof(id),log2(sizeof(id)),@encode(id));
//注册类,在注册之前可以增加实例变量等内容,但是注册之后就无法添加实例变量了
objc_registerClassPair(TestClass);
id p = [TestClass alloc];
[p setValue:@"xiyangyag" forKey:@"name"];
NSLog(@"%@", [p valueForKey:@"name"]);