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 initializationobjc_initWeakThe weak function initializes a new weak pointer to the address of the object.
  • 2.objc_initWeakThe function will callstoreWeakFunction. Update pointer pointer to create weak reference table.
  • ③ If the weak pointer previously referred to a weak reference object, the weak pointer is calledweak_unregister_no_lockThe 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 calledweak_register_no_lockThe 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 releasedreleaseFunction.
  • (2) then_objc_rootReleaseFunction.
  • (3) then therootReleaseFunction.
  • ④ If the reference count is 0, run the commanddeallocFunction.
  • (5) then_objc_rootDeallocFunction.
  • 6 then adjustablerootDeallocFunction.
  • 7 then adjustableobject_disposeFunction.
  • ⑧ Next callobjc_destructInstanceFunction.
  • ⑨ Then comes an important functionclearDeallocating.
  • ⑩ CallclearDeallocating_slowFunction.

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 criticalweak_clear_no_lockFunction. 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