Weak is almost everywhere in Objective-C. This keyword is often used when defining IVar. The weak variable is automatically set to nil after the object is released. How does it do that? Before we dive into it, there are a few words worth knowing.
keywords
SideTable
The SideTable is a structure with three main members. The weak table is used to manage the weak table of the object.
Struct SideTable {// spinlock_t slock; // Hash table RefcountMap refcnts; Weak_table_t Weak_table; // Hash table to store object weak reference pointer. . }Copy the code
Weak_table is the core data structure to realize the weak function. In fact, it can be understood that SideTable is a encapsulation of Weak_table, which is convenient for better use and access to weak table.
Weak table
The weak table is a hash table that stores information about weak references and all associated weak references. Key is the address of the object, and value is the address array of weak Pointers to the object.
/**
* The global weak references table. Stores object ids as keys,
* and weak_entry_t structs as their values.
*/
struct weak_table_t {
weak_entry_t *weak_entries;
size_t num_entries;
uintptr_t mask;
uintptr_t max_hash_displacement;
};
Copy the code
A more abstract way of thinking about it is as follows:
F (address of object) = array of weak pointer addresses to the object
weak_entry_t
Weak_entries are also a hash structure that stores the addresses of all weak Pointers to bound weak reference objects.
/**
* The internal structure stored in the weak references table.
* It maintains and stores
* a hash set of weak references pointing to an object.
* If out_of_line_ness != REFERRERS_OUT_OF_LINE then the set
* is instead a small inline array.
*/
#define WEAK_INLINE_COUNT 4
// out_of_line_ness field overlaps with the low two bits of inline_referrers[1].
// inline_referrers[1] is a DisguisedPtr of a pointer-aligned address.
// The low two bits of a pointer-aligned DisguisedPtr will always be 0b00
// (disguised nil or 0x80..00) or 0b11 (any other address).
// Therefore out_of_line_ness == 0b10 is used to mark the out-of-line state.
#define REFERRERS_OUT_OF_LINE 2
struct weak_entry_t {
DisguisedPtr<objc_object> referent;
union {
struct {
weak_referrer_t *referrers;
uintptr_t out_of_line_ness : 2;
uintptr_t num_refs : PTR_MINUS_2;
uintptr_t mask;
uintptr_t max_hash_displacement;
};
struct {
// out_of_line_ness field is low bits of inline_referrers[1]
weak_referrer_t inline_referrers[WEAK_INLINE_COUNT];
};
};
...
};
Copy the code
Weak implementation principle
Initialize the
- ① The Runtime is invoked during initialization
objc_initWeak
The weak function initializes a new weak pointer to the address of the object. - 2.
objc_initWeak
The function will callstoreWeak
Function. Update pointer pointer to create weak reference table. - ③ If the weak pointer previously referred to a weak reference object, the weak pointer is called
weak_unregister_no_lock
The function touches the binding of this object to the weak pointer. - ④ If the weak pointer needs to point to a new weak-referenced object, the weak pointer is called
weak_register_no_lock
The weak function implements binding by adding the weak pointer address to the weak reference table with the address of the object as the key.
The release of
- (1) Called when the object is released
release
Function. - (2) then
_objc_rootRelease
Function. - (3) then the
rootRelease
Function. - ④ If the reference count is 0, run the command
dealloc
Function. - (5) then
_objc_rootDealloc
Function. - 6 then adjustable
rootDealloc
Function. - 7 then adjustable
object_dispose
Function. - ⑧ Next call
objc_destructInstance
Function. - ⑨ Then comes an important function
clearDeallocating
. - ⑩ Call
clearDeallocating_slow
Function.
ClearDeallocating has two branches. The reality determines whether the object has an optimized ISA reference count, and if it doesn’t, it needs to clean up the reference count data stored in the SideTable. Isa.has_sidetable_rc) or weak (ISa.Weakly_referenced). Weak (ISa.weakly_referenced) Call the clearDeallocating_slow method.
- The final call is critical
weak_clear_no_lock
Function. Get the weak reference table from the table by releasing the address of the weak pointer, then assign all the values pointed to by the weak pointer to nil, and delete the record from the table.
conclusion
The main implementation of the weak function is to maintain a hash table through the Runtime, which stores the address of the object and the address of all the weak Pointers to it. When the storage object is released, weak_clear_NO_lock function is used to iterate through the array storing the weak pointer address and empty the weak pointer, so as to avoid the problem of wild pointer. (Because objects are usually allocated to a block of memory on the heap, if a subsequent allocation of memory happens to be allocated to this address, the program will crash; The basic data type is usually allocated on the stack, and the stack memory will be handled automatically by the system itself.
reference
- Objective-C Automatic Reference Counting (ARC)
- Underlying principle of iOS: weak implementation principle
- The implementation principle of iOS low-level parsing weak (including initialization, reference and release analysis of weak objects)
- Weak basic implementation principle of iOS