The Objc object of this present life

The Objc object of this present life

Preface

In object – oriented programming, we create objects every day, describing the whole world with objects, but how does the object come into being?

Catalog

  • 1 breeding object
  • The birth of 2 objects
  • 3 the growth of the object
  • 4 destruction of objects
  • 5 Summary
Breeding object
The Objc object of this present life

Every day we are developing alloc objects, and the alloc method to do?

(ID) alloc {return _objc_rootAlloc (self);}

All object alloc calls this root method

ID _objc_rootAlloc (Class CLS) {return callAlloc (CLS, false/*checkNil*/, true/*allocWithZone*/);}

This method will call the callAlloc method

Static ALWAYS_INLINE ID callAlloc (Class CLS, bool checkNil, bool allocWithZone=false) {if (checkNil & & return nil; CLS!) #if __OBJC2__ if (cls->); ISA (->!); hasCustomAWZ (alloc/allocWithZone implementation.) {/ / No Go straight to the allocator. fixme store hasCustomAWZ in the Non-meta / / class / / and add it to canAllocFast's summary if (cls->); canAllocFast (No) {/ / ctors, raw ISA, etc. Go straight to the metal. bool dTOR = cls-> hasCxxDtor (ID); obj = (ID) calloc (1, cls->); (bits.fastInstanceSize); if (obj!) return callBadAllocHandler (CLS); obj-> initInstanceIsa (CLS, dTOR); return obj else;} Ctor or raw {/ / Has isa or something. Use the slower path. ID obj = class_createInstance (CLS, 0); if (obj!) return callBadAllocHandler (CLS); return obj;}} / / #endif No shortcuts available. if (allocWithZone) return [cls allocWithZone:nil]; return [cls alloc];}

CheckNil = false, so it will not return nil.

Bool hasCustomAWZ () {return! Bits.hasDefaultAWZ ())}
The Objc object of this present life

In this picture, we can see that in the data segment data of the object, class_rw_t has a flags.

Bool hasDefaultAWZ () {return (data) -> flags RW_HAS_DEFAULT_AWZ;} #define RW_HAS_DEFAULT_AWZ (1< < & 16)

RW_HAS_DEFAULT_AWZ this is used to indicate whether the current class or superclass has a default alloc/allocWithZone. It is worth noting that this value is stored in the metaclass.

HasDefaultAWZ () method is used to determine whether the current class default allocWithZone.

If cls-&gt (ISA) (-&gt); hasCustomAWZ () return to YES, means that there is a default allocWithZone method, then directly to the class allocWithZone, to apply for memory space.

If (allocWithZone) return [cls allocWithZone:nil];

AllocWithZone will call rootAllocWithZone

(ID) allocWithZone: (struct _NSZone *) zone {return _objc_rootAllocWithZone (self, (malloc_zone_t *) zone);}

Then take a closer look at the specific implementation of _objc_rootAllocWithZone

ID _objc_rootAllocWithZone (Class CLS, malloc_zone_t *zone) {ID obj; #if __OBJC2__ under __OBJC2__ ignores the / / allocWithZone zone parameter (void) zone; obj = class_createInstance (CLS, 0); #else if (zone ||! UseGC) {obj = class_createInstance (CLS, 0);} else {obj = class_createInstanceFromZone (CLS 0, zone);} #endif (if! Obj) obj = callBadAllocHandler (CLS); return obj;}

In __OBJC2__, call class_createInstance (CLS, 0); method to create object.

ID class_createInstance (Class CLS, size_t extraBytes) {return _class_createInstanceFromZone (CLS, extraBytes, Nil);}

_class_createInstanceFromZone method on the basis of the first detailed analysis, the following detailed analysis, the first clear program context.

In the old version of the objc in the first to see whether there is space zone, whether to use a garbage collection, if there is no space, or by the garbage collection, it will call the class_createInstance (CLS, 0) method to acquire the object, otherwise the call class_createInstanceFromZone (CLS, 0, zone); object.

ID class_createInstanceFromZone (Class CLS, size_t extraBytes, void *zone) {return _class_createInstanceFromZone (CLS, extraBytes, zone);}

As you can see, the function that the final object is called is _class_createInstanceFromZone, regardless of whether the objc version is new or old.

If successful, objc is returned, and the callBadAllocHandler method is called if the creation fails.

Static ID callBadAllocHandler (Class CLS add re-entrancy protection) {/ / fixme in case allocation fails inside handler return (*badAllocHandler) (CLS);} static (*badAllocHandler) ID (Class) = & defaultBadAllocHandler; static ID defaultBadAllocHandler (Class CLS) {_objc_fatal ("attempt to allocate object of class'%s'failed, cls-> (nameForLogging));}

Failed to create an object that will eventually call the _objc_fatal output “attempt to object of class failed” to create an object failed.

This completes the callAlloc in hasCustomAWZ () returns to YES. So hasCustomAWZ () function returns NO, the situation is like?

If (cls-> ISA)! (->); hasCustomAWZ (alloc/allocWithZone implementation.) {/ / No Go straight to the allocator. fixme store hasCustomAWZ in the Non-meta / / class / / and add it to canAllocFast's summary if (cls->); canAllocFast (No) {/ / ctors, raw ISA, etc. Go straight to the metal. bool = dTOR cls-> hasCxxDtor (ID); obj = (ID) calloc (1, cls->); (bits.fastInstanceSize); if (obj!) return callBadAllocHandler (CLS); obj-> initInstanceIsa (CLS, dTOR); return obj;} else {/ / Has ctor or raw isa or something. Use the slower path. id = obj class_createInstance (CLS, 0); if (obj return!) CallBadAllocHandler (CLS); return obj;}}

This section is hasCustomAWZ () to return to the NO, the current class is no default allocWithZone.

In the absence of the default allocWithZone, it is also necessary to determine whether the current class supports fast alloc. If you can, call the calloc function directly, apply for 1 bits.fastInstanceSize () the size of the memory space, if the creation fails, it will call the callBadAllocHandler function.

If successful, initialize the Isa pointer and dtor.

Bool hasCxxDtor (data) {return (->); flags & RW_HAS_CXX_DTOR or;} / / class superclass has.Cxx_destruct implementation #define RW_HAS_CXX_DTOR (1< < 17)

DTOR is used to determine whether the current class or superclass.Cxx_destruct function.

If the current class does not support fast alloc, then go to class_createInstance (CLS, 0) to create a new object.

Summary:

The Objc object of this present life

After a series of judgments, the object of the birth process eventually fell on the _class_createInstanceFromZone function.

Static __attribute__ ((always_inline)) ID _class_createInstanceFromZone (Class CLS, size_t extraBytes, void *zone, bool cxxConstruct = true, size_t = *outAllocatedSize Nil) {if (CLS!) return nil; assert (cls-> isRealized) (); / / Read class's info bits all at once for performance bool hasCxxCtor (hasCxxCtor = cls-> bool); hasCxxDtor = cls-> hasCxxDtor (bool); fast = cls-> canAllocIndexed (size_t); size = cls-> instanceSize (extraBytes); if (outAllocatedSize) *outAllocatedSize = size; ID obj; if (UseGC! & & zone & & fast! = obj) {(ID) calloc (1, size); if (obj return nil!); obj-> initInst AnceIsa (CLS, hasCxxDtor);} else {#if SUPPORT_GC if (UseGC) {obj = (ID) auto_zone_allocate_object (gc_zone, size, AUTO_OBJECT_SCANNED, 0, 1);} else #endif if (zone) {obj = (ID) malloc_zone_calloc ((malloc_zone_t) zone, 1, size) {else}; obj = (ID) calloc (1, size);} if (obj!) return nil Use non-indexed isa on; / / the assumption that they might be doing something weird with the zone / or RR. obj-> initIsa (CLS);} if (cxxConstruct & & hasCxxCtor) {obj = _objc_constructOrFree (obj return obj, CLS);};}

What are ctor and dTOR respectively?

Bool (hasCxxCtor) addSubclass (propagates) {/ / this flag from the superclass. assert (isRealized) (return); bits.hasCxxCtor (bool) (hasCxxCtor);} {return (data) -> flags & RW_HAS_CXX_CTOR #define;} RW_HAS_CXX_CTOR (1< < 18)

Ctor is to determine whether the current class or superclass.Cxx_construct construction method.

Bool (hasCxxDtor) addSubclass (propagates) {/ / this flag from the superclass. assert (isRealized) (return); bits.hasCxxDtor (bool) (hasCxxDtor);} {return (data) -> flags & RW_HAS_CXX_DTOR #define;} RW_HAS_CXX_DTOR (1< < 17)

DTOR is to judge whether the current class or superclass has the.Cxx_destruct structure method.

Size_t instanceSize (size_t extraBytes) {size_t = alignedInstanceSize (size + extraBytes); / / CF requires all objects be at least 16 bytes. if (size < 16) size = 16; return size; uint32_t alignedInstanceSize) {return} (word_align (unalignedInstanceSize) (uint32_t);} unalignedInstanceSize {assert (isRealized (() return (data))); -> ro-> instanceSize;}

The instance size instanceSize will be stored in the isa_t structure of the class, and then returned after alignment.

Note: Core Foundation requires that all objects must be greater than or equal to 16 bytes in size.

After getting the size of the object, call the calloc function directly to allocate memory space for the object.

About calloc function

The calloc (function) contiguously allocates enough space for count objects that are size bytes of memory each and returns a pointer to the allocated memory. The allocated memory is filled with bytes of value zero.

This function is also the reason why we apply the initial value is 0 or nil. Because the calloc () function will default to the application space is initialized to 0 or nil.

After applying for memory space, you need to initialize the Isa pointer.

Obj-> initInstanceIsa (CLS, hasCxxDtor); obj-> initIsa (CLS);

Initialize the Isa pointer with the above two functions.

Inline void objc_object:: initInstanceIsa (Class CLS, bool hasCxxDtor) {assert (UseGC!); assert (cls-> requiresRawIsa) (!); assert (hasCxxDtor = = cls-> (hasCxxDtor)); initIsa (CLS, true, hasCxxDtor);} inline void objc_object:: initIsa (Class CLS) {initIsa (CLS false, false);}

From the above source, we can see that the final call is the initIsa function, but into the different parameters.

Inline void objc_object:: initIsa (Class CLS, bool indexed, bool hasCxxDtor) {assert (! IsTaggedPointer ()); if (! Indexed) {isa.cls = CLS;} else {assert (DisableIndexedIsa!); isa.bits = ISA_MAGIC_VALUE; / / isa.magic is part of ISA_MAGIC_VALUE isa.indexed is part of ISA_MAGIC_VALUE / / isa.has_cxx_dtor = hasCxxDtor; isa.shiftcls = (uintptr_t) CLS > > 3;}}

The initialization process is the process of initializing the isa_t structure.

If __arm64__ define ISA_MASK 0x0000000ffffffff8ULL # # # define ISA_MAGIC_MASK 0x000003f000000001ULL define ISA_MAGIC_VALUE 0x000001a000000001ULL struct uintptr_t # {indexed: 1; uintptr_t: 1; has_assoc: 1; uintptr_t has_cxx_dtor uintptr_t shiftcls: 33; / / MACH_VM_MAX_ADDRESS 0x1000000000 uintptr_t magic uintptr_t: 6; weakly_referenced: 1; uintptr_t: 1; deallocating: 1; uintptr_t has_sidetable_rc uintptr_t extra_rc: 19 # define; RC_ONE (1ULL< < 45) # define RC_HALF (1ULL< < 18)};

For specific initialization, please refer to the first day of admission to the Objective-C hospital in Runtime, ISA and Class

The main reason is the current address right three bits for the Class pointer in useless after the three removal reduces memory consumption, because the pointer to the byte aligned memory (8 bits), the three pointer is meaningless 0. Most of
machine architecture is all byte-addressable, but the memory address of the object must be aligned to byte multiples, which can improve the performance of the code running in iPhone5s, the virtual address is 33 bits, so for the last three bit aligned to 000, we will say only that the address of an object with 30 of them to.

At this point, the process of breeding object is completed.

Two. The birth of the object

The Objc object of this present life

Once we call the init method, the object will be born.

- (ID) init {return _objc_rootInit (self);}

Init calls the _objc_rootInit method.

ID _objc_rootInit (ID obj) {/ / In practice, it will be hard to rely on this function. classes do not properly / / Many chain -init calls. return obj;}

The _objc_rootInit method is simply to return the current object.

Three. Growth of objects

The Objc object of this present life

The object of the growth, in fact, is to talk about the object initialization, access to its attributes and methods, they look like in memory.

#import < Foundation/Foundation.h> @interface; Student: NSObject @property (strong, nonatomic) NSString + *name (void); study; run; @end - (void) #import "Student.h" @implementation + Student (void study) {NSLog (@ Study) - (void);} run {NSLog (@ "Run" @end});

Here we create a new Student class to illustrate. This class is simple, with only one name attribute, plus a class method, and an instance method.

Student *stu = [[Student alloc]init]; NSLog (@ Student's class is, [stu class]% @ "); NSLog (" Student's meta class is% @ @ object_getClass ([stu, class])); NSLog ("Student's meta class's superclass is @% @", object_getClass (object_getClass ([stu class]))); Class currentClass = [Student class]; for (int i = 1; I 5; < i++) {NSLog ("Following the ISA pointer @%d times gives%p, I, currentClass% @", currentClass); currentClass = object_getClass (currentClass);} NSLog (@ NSObject's class is%p, [NSObject NSLog (@ class]); "NSObject's meta class is%p", object_getClass ([NSObject class]));

Write the above code and analyze the structure.

The output is as follows:

Student's class is Student Student's meta class is Student Student's meta class's superclass is NSObject Following the ISA pointer times gives 0x100004d90 Student Following the 1 isa pointer 2 times gives 0x100004d68 Student Following the ISA pointer times gives 0x7fffba0b20f0 NSObject Following the 3 isa pointer 4 times gives 0x7fffba0b20f0 NSObject NSObject's class is 0x7fffba0b2140 NSObject's meta class is 0x7fffba0b20f0

After the print results above, we can know that the ISA of an instance of a class is a class that points to it:

The Objc object of this present life

An example of the class, the dotted line to the gray area, the gray area is a Class pair, which contains two things, one is the class, and the other is meta-class. Class isa points to meta-class. Since student is inherited from NSObject, so Student’s class meta-class is NSObject superclass.

In order to figure out what is stored in the 3 items, we print some more information.

+ (NSArray *) instanceVariables int outCount Ivar {unsigned; *ivars = class_copyIvarList ([self, class], & outCount); NSMutableArray *result = [NSMutableArray array]; for (unsigned int i = 0; I < outCount; i++) {NSString type = [NSString * decodeType:ivar_getTypeEncoding (ivars[i])]; NSString *name = [NSString stringWithCString:ivar_getName (ivars[i] encoding:NSUTF8StringEncoding]; NSString *ivarDescription) = [NSString stringWithFormat:@ "% @% @" type, [result, name]; addObject:ivarDescription];} free (Ivars); return result.count [result copy] nil;}?

From the previous print information we can know that 0x100004d90 is the class address. 0x100004d68 is the address of the meta-class class.

Po [0x100004d90 Po [0x100004d68 instanceVariables] instanceVariables]

Print out:

< __NSSingleObjectArrayI 0x100302460> (NSString* _name) nil

As you can see, the attributes are stored in the class.

The following is about the understanding of class methods and instance methods.

In fact, there is no concept of the number and number method in memory. Do a test:

+ (NSArray * ClassMethodNames) {NSMutableArray * array = [NSMutableArray array]; unsigned int methodCount = 0; methodList = Method * class_copyMethodList ([self class], & methodCount); unsigned int i; for (I = 0; I < methodCount i++; [array addObject: NSStringFromSelector (method_getName) {(methodList[i])})]; free (methodList); return array;}
Po [0x100004d90 Po [0x100004d68 ClassMethodNames] ClassMethodNames]

Print out:

< __NSArrayM 0x100303310> (.Cxx_destruct, name, setName:, run) < __NSArrayM 0x100303800> (Study)

0x100004d90 is a class object, which is stored in the number method, there are 3 other methods, getter, setter, and.Cxx_destruct method

0x100004d68 is meta-class, which is stored in the + method.

Of course, there is a special meta-class in runtime, that is NSObject meta-class, its superclass is itself. In order to prevent the minus NSObject protocol inside the method call may appear collapse, such as copy – method, so in the NSObject meta-class to + all NSObject methods are to achieve again, is to deliver the message to intercept here again. So the general NSObject protocol method has the same method + + and – number method.

It is worth noting that, class and meta-class are single cases.

About the object, all the objects in the memory inside there is a ISA, ISA is a small “radar”, with it, you can send a message to an object under runtime.

So the essence of the object: the object in the Objc is a variable that points to the ClassObject address, that is ID obj = & ClassObject.

On the nature of the object is, void *ivar = & obj + offset (N)

NSString @ *myName = "halfrost"; NSLog (@ myName address =%p, size =%lu ", & myName, sizeof (myName)); ID CLS = [Student class]; NSLog Student class =% @ (@ address =%p, size =%lu", CLS, & CLS, sizeof (CLS void)); *obj = & CLS; NSLog ("Void *obj = @% @ address =%p, size =%lu", obj, & obj, sizeof (obj)); NSLog (@ "% @%p" ((__bridge * Student) obj (__bridge).Name (Student * obj).Name));

output

MyName address = 0x7fff562eeaa8, class = Student size = 8 Student address = 0x7fff562eeaa0, size = 8 Void *obj = < Student: = 0x7fff562eeaa0> 0x7fff562eea98 address, size = 8 halfrost 0x10a25c068

From this example, the object is the essence to the class object address variables, from the above example we can see that ID obj, obj = & ClassObject, CLS is a Student class object, so obj is a Student object.

Class objects are loaded into memory before the main function is executed, executable files and all symbols of the dynamic library (Class, Protocol, Selector, IMP,…) Have been successfully loaded into the memory format, the runtime management, and then after that, those methods of runtime (dynamic add Class, Swizzle, etc.)

Specific can see this article iOS program main function before what happened

Or return to the example, about object properties, is the obj address and the offset, you can access to the above example, the obj address is 0x7fff562eea98, down 8 to offset, class address, 0x7fff562eeaa0, to offset 8, went to the name attribute of the 0x7fff562eeaa8 address. Stored in the name is the first address of the string, according to the print information is also seen, the store is a pointer, pointing to the 0x10a25c068 address.

If we print this address:

The Objc object of this present life

We’ll find that there’s a string.

The Objc object of this present life

A summary of the above is the picture, each object of the ISA is stored in the Class memory address, Class is in the main function before the implementation of the load into memory, and by the Runtime management. So only need to construct a pointer to Class, that is, ISA, can be an object.

The property of an object is the offset on the first address of the object. As shown above, when you know that the first address of the object is 0x7fff562eea98, then the 8 byte offset to the ISA, and then offset the 8 bytes to the name attribute. The property of an object is the process of offset addressing in memory.

Four. Destruction of objects

The Objc object of this present life

The destruction of the object is called the dealloc method.

- (void) dealloc {_objc_rootDealloc (self);}

The dealloc method calls the _objc_rootDealloc method

Void _objc_rootDealloc (ID obj) {assert (obj); obj-> rootDealloc; void objc_object: (inline)} (rootDealloc) {assert (UseGC!); if (isTaggedPointer) (return); if (isa.indexed & & isa.weakly_referenced; & &!! isa.has_assoc & isa.has_cxx_dtor & &! & isa.has_sidetable_rc) {assert (!!) (sidetable_present); free (this);} else {object_dispose (this (ID));}}

If it is TaggedPointer, direct return.

Indexed is on behalf of whether to open the ISA pointer optimization. Weakly_referenced represents the weak point of an object that is pointed to or once pointed to a ARC. Has_assoc represents an object that contains or has been associated with a reference. Has_cxx_dtor mentioned it before. It’s a destructor. Has_sidetable_rc determines whether the reference count of the object is too large.

ID object_dispose (ID obj) {if (obj!) return nil; objc_destructInstance (obj); #if SUPPORT_GC if (UseGC) {auto_zone_retain (gc_zone, obj); / / GC free expects rc==1 #endif free} (obj); return nil;}

Object_dispose will call objc_destructInstance.

/*********************************************************************** * objc_destructInstance * Destroys an instance without freeing memory. Calls C++ destructors. * Calls * ARR Ivar cleanup. * Removes associative references. * Returns `obj`. Does nothing if `obj` is nil. warned that GC DOES * Be NOT CALL THIS. If you edit this also edit finalize. CoreFoundation and other clients do call * this under void * objc_destructInstance (GC. **********************************************************************/ ID obj if (obj)) {{/ / Read all of the flags at once for performance. bool cxx = obj-> bool = assoc (hasCxxDtor); UseGC & &!; obj-> hasAssociatedObjects; bool (dealloc = UseGC); Order is important. / / This if (cxx) object_cxxDestruct (obj); if (Assoc) _object_remove_assocations (obj); if (dealloc) obj-> clearDeallocating (return obj);};}

An object is destroyed by the underlying C++ destructor. You also need to remove the associative reference.

Followed by a detailed look at the destruction of the object of the 3 methods.

1.object_cxxDestruct
Void object_cxxDestruct (ID obj) {if (obj!) (return; if obj-> isTaggedPointer (return)); object_cxxDestructFromClass (obj, obj->); ISA (static void);} object_cxxDestructFromClass (ID obj, Class CLS) {void (*dtor) (ID); / / Call cls's dTOR first, then superclasses's dtors. (for; CLS; CLS = cls-> superclass) {if (cls-> hasCxxDtor)! (return); dTOR = (void (*) (ID)) lookupMethodInClassAndLoadCache (CLS, SEL_cxx_destruct); if (dTOR! = (void (*) (ID) _objc_msgForward_impcache)) {if {_objc_inform (PrintCxxCtors) ("CXX: calling C++ destructors for class%s, cls-> nameForLogging);}; () (*dtor) (obj); }}

From the start along the inheritance chain has been to find the parent class, to search for SEL_cxx_destruct
the selector, find the function (void (*) (ID) (function pointers) and execute.

The following is a reference to the contents of the dealloc process and.Cxx_destruct under ARC:

From this article:

ARC actually creates -.cxx_destruct to handle instance This method was originally created for calling C++ destructors automatically when an method object was destroyed. variables. freeing a

As mentioned in “Effective Objective-C 2”:

When the compiler that an contained C++ objects, it would a called.Cxx_destruct. ARC on this method and emits the required cleanup piggybacks code within it. saw method generate

It can be learned that the.Cxx_destruct method was originally designed for the C++ object, ARC borrowed this method to insert code to achieve automatic memory release work.

In ARC, the dealloc method is called after the last release, but at this time the instance variable (Ivars) is not released, the parent class’s dealloc method will be called automatically after the subclass dealloc method returns. The ARC instance variable objects under the release of [NSObject in the root dealloc] (usually root class is NSObject), the release order of various uncertain variables (uncertain, a class within the superclass and subclass is uncertain, that is not the care release order)

After the study of the @sunnyxx text:
1.ARC objects under the member variables in the compiler insert.Cxx_desctruct method automatically released.
2.ARC under the [super dealloc] method is automatically inserted by the compiler.

As for the realization of the.Cxx_destruct method, but also look at the detailed analysis of the article @sunnyxx.

2._object_remove_assocations
Void _object_remove_assocations (ID object) {vector< ObjcAssociation, ObjcAllocator< ObjcAssociation> > elements; manager AssociationsHashMap {AssociationsManager; & associations ((manager.associations)); if (associations.size) (return = = 0); disguised_ptr_t disguised_object = DISGUISE (object); AssociationsHashMap:: iterator I = associations.find (disguised_object); if (I ()! = associations.end) {/ / copy all of the associations that need to be removed. ObjectAssociationMap *refs = i-> second; for (ObjectAssociationMap:: iterator = J refs-> begin (end = refs->), (end);; J! = end; ++j) {elements.push_back (j-> second); Remove the secondary table. delete} / / refs; associations.erase (I);}} / / the calls to (releaseValue) happen outside of the lock. for_each (elements.begin), elements.end (ReleaseValue), (());}

When remove the associated object object, will be the first to determine the object isa_t has_assoc for a second bit value, when the presence of object and object-> (hasAssociatedObjects) value is 1 when to call the _object_remove_assocations method to.

The purpose of the _object_remove_assocations method is to delete second ObjcAssociationMap tables, that is, delete all the associated objects. Delete second tables, you need to traverse the first AssociationsHashMap table search. Here will be second ObjcAssociationMap table of all the ObjcAssociation objects are stored in an array of elements inside, and then call associations.erase () to delete the table second. Finally traverse the elements array, the ObjcAssociation object in turn release.

The way to remove this is exactly the same as the remove method in the Associated Object associated object.

3.clearDeallocating ()
Inline void (objc_object:: clearDeallocating) {if (! Isa.indexed path for raw) {/ / Slow pointer isa. sidetable_clearDeallocating (else);} if (isa.weakly_referenced || isa.has_sidetable_rc path for non-pointer) {/ / Slow isa with weak refs and/or side table data. (clearDeallocating_slow);} assert (sidetable_present);} (!)

Here are 2 clear functions, the next one to see.

Void: sidetable_clearDeallocating (objc_object:) {SideTable& table = SideTables ([this]); / / clear any weak table items extra retain count and deallocating / / clear / / bit (fixme warn or abort if extra retain count = = 0?) table.lock (RefcountMap:); iterator: it = table.refcnts.find (this); if (it = table.refcnts.end! ()) {if (it-> second & SIDE_TABLE_WEAKLY_REFERENCED) {weak_clear_no_lock (& table.weak_table, this (ID) table.refcnts.erase (it));};}} (table.unlock);

Traverse SideTable, loop call weak_clear_no_lock function.

Weakly_referenced represents the weak point of an object that is pointed to or once pointed to a ARC. Has_sidetable_rc determines whether the reference count of the object is too large. If one of them is YES, the clearDeallocating_slow () method is called.

Path of (clearDeallocating) / / Slow / / for objects with indexed isa that were ever weakly / / referenced / / or whose retain count ever overflowed to the side table. NEVER_INLINE void (objc_object:: clearDeallocating_slow) {assert (isa.indexed & amp; & (isa.weakly_referenced ||; isa.has_sidetable_rc; SideTable& table)) = SideTables (table.lock ([this]);); if (isa.weakly_referenced) {weak_clear_no_lock (& table.weak_table, this (ID));} if {table.refcnts.erase (isa.has_sidetable_rc) (this) (table.unlock);}};

ClearDeallocating_slow will eventually call the weak_clear_no_lock method.

By dealloc Nils / * * * Called out all weak pointers; that point to the object so that they * provided can no longer be used. @param weak_table * * * @param referent The object being deallocated. / void weak_clear_no_lock (weak_table_t *weak_table, ID referent_id) {objc_object *referent = (objc_object * referent_id); weak_entry_t (weak_table = weak_entry_for_referent, *entry referent); if (entry = = Nil) {/ / / XXX shouldn't happen, but does with mismatched CF/objc //printf ("XXX no entry for clear deallocating%p/n", referent); return;} / / zero out references weak_referrer_t *referrers; size_t count; if (entry-> out_of_line) {referrers = entry-> referrers; Count = TABLE_SIZE (entry);} else {referrers = entry-> inline_referrers; count = WEAK_INLINE_COUNT;} for (size_t I = 0; I < count; ++i) {objc_object **referrer = referrers[i]; if (referrer) {if (*referrer = = referent) {*referrer = nil; if (*referrer) {else} _objc_inform ("__weak variable at%p holds%p instead of%p." This "is probably incorrect" objc_storeWeak use of "(and) (objc_loadWeak)." "Break on objc_weak_error to debug./n", referrer (void*) *referrer, (void*) referent); Objc_weak_error ();}} weak_entry_remove (weak_table, entry);}

This function clears the reference count table in the weak_table and clears the weak reference table, referring all weak references to nil.

summary

The Objc object of this present life

This article detailed analysis of the objc object from birth to ultimate destruction, it’s all in this present life. Also please a lot of pointing.