Mobile Development 19 min read

Understanding the Implementation of weak Pointers in the Objective‑C Runtime

This article explains how Objective‑C implements weak pointers using a hash‑based weak table, SideTables, ExplicitInit, and various low‑level C++ template functions such as storeWeak, weak_register_no_lock, and weak_clear_no_lock to ensure automatic nil‑assignment and safe deallocation.

Sohu Tech Products
Sohu Tech Products
Sohu Tech Products
Understanding the Implementation of weak Pointers in the Objective‑C Runtime

In Objective‑C projects the weak pointer is used to avoid crashes by automatically setting the pointer to nil after the referenced object is deallocated, because sending a message to nil is a no‑op.

The implementation relies on a global hash table named weak_table_t that stores every object referenced by a weak pointer. Each entry in this table is a SideTable containing a weak_table and a reference‑count table. The function SideTables() returns a static StripedMap<SideTable> which maps each object to its corresponding SideTable .

SideTables is defined as: static StripedMap<SideTable>& SideTables() { return SideTablesMap.get(); } The underlying storage is provided by the template class ExplicitInit : template <typename Type> class ExplicitInit { alignas(Type) uint8_t _storage[sizeof(Type)]; public: template <typename... Ts> void init(Ts &&... Args) { new (_storage) Type(std::forward<Ts>(Args)...); } Type &get() { return *reinterpret_cast<Type *>(_storage); } };

The SideTable structure holds the spin lock, a reference‑count map, and the weak_table_t : struct SideTable { spinlock_t slock; RefcountMap refcnts; weak_table_t weak_table; };

The weak_table_t itself is a hash table of weak_entry_t entries: struct weak_table_t { weak_entry_t *weak_entries; size_t num_entries; uintptr_t mask; uintptr_t max_hash_displacement; }; Each weak_entry_t contains the referent object and either an inline array of up to four weak_referrer_t pointers or a dynamically allocated array when more references exist: 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 { weak_referrer_t inline_referrers[WEAK_INLINE_COUNT]; }; };

The type weak_referrer_t is defined as a disguised pointer to hide the actual address: typedef DisguisedPtr<objc_object *> weak_referrer_t; The DisguisedPtr template converts a pointer to a negated integer and back, preventing accidental leaks detection: template <typename T> class DisguisedPtr { uintptr_t value; static uintptr_t disguise(T* ptr) { return -(uintptr_t)ptr; } static T* undisguise(uintptr_t val) { return (T*)-val; } public: DisguisedPtr() {} DisguisedPtr(T* ptr) : value(disguise(ptr)) {} operator T*() const { return undisguise(value); } /* other operators omitted for brevity */ };

When a weak pointer is created (e.g., via __weak or a property), the compiler emits a call to objc_initWeak , which forwards to the templated storeWeak function: id objc_initWeak(id *location, id newObj) { if (!newObj) { *location = nil; return nil; } return storeWeak<DontHaveOld, DoHaveNew, DontCrashIfDeallocating>(location, (objc_object*)newObj); } storeWeak handles four cases controlled by the template parameters haveOld , haveNew , and crashIfDeallocating . It retrieves the old and new SideTable entries, registers the new weak reference with weak_register_no_lock , and unregisters any old reference with weak_unregister_no_lock .

The registration function adds the weak reference to the appropriate weak_entry_t : id weak_register_no_lock(weak_table_t *weak_table, id referent_id, id *referrer_id, bool crashIfDeallocating) { /* checks omitted */ weak_entry_t *entry = weak_entry_for_referent(weak_table, referent); if (entry) { append_referrer(entry, referrer); } else { weak_entry_t new_entry(referent, referrer); weak_grow_maybe(weak_table); weak_entry_insert(weak_table, &new_entry); } return referent_id; } When an object is deallocated, rootDealloc eventually calls clearDeallocating , which invokes weak_clear_no_lock to walk the weak table entry and set every stored weak pointer to nil : void weak_clear_no_lock(weak_table_t *weak_table, id referent_id) { objc_object *referent = (objc_object *)referent_id; weak_entry_t *entry = weak_entry_for_referent(weak_table, referent); if (!entry) return; weak_referrer_t *referrers; size_t count = entry->out_of_line() ? TABLE_SIZE(entry) : WEAK_INLINE_COUNT; referrers = entry->out_of_line() ? entry->referrers : entry->inline_referrers; for (size_t i = 0; i < count; ++i) { objc_object **referrer = referrers[i]; if (referrer && *referrer == referent) *referrer = nil; } weak_entry_remove(weak_table, entry); } Scope‑based destruction of a weak variable calls objc_destroyWeak , which simply invokes storeWeak<DoHaveOld, DontHaveNew, DontCrashIfDeallocating> with a nil new object, causing the weak pointer to be unregistered. Unregistration removes the reference from the entry via remove_referrer and, if the entry becomes empty, deletes it from the global hash table: void weak_unregister_no_lock(weak_table_t *weak_table, id referent_id, id *referrer_id) { objc_object *referent = (objc_object *)referent_id; objc_object **referrer = (objc_object **)referrer_id; weak_entry_t *entry = weak_entry_for_referent(weak_table, referent); if (!entry) return; remove_referrer(entry, referrer); bool empty = true; if (entry->out_of_line() && entry->num_refs != 0) empty = false; else for (size_t i = 0; i < WEAK_INLINE_COUNT; ++i) if (entry->inline_referrers[i]) { empty = false; break; } if (empty) weak_entry_remove(weak_table, entry); } Overall, the Objective‑C weak pointer mechanism combines a hash‑based weak table, disguised pointers, and careful registration/unregistration logic to guarantee that weak references become nil safely without race conditions.

Memory ManagementRuntimeObjective-CC++ templatesweak pointer
Sohu Tech Products
Written by

Sohu Tech Products

A knowledge-sharing platform for Sohu's technology products. As a leading Chinese internet brand with media, video, search, and gaming services and over 700 million users, Sohu continuously drives tech innovation and practice. We’ll share practical insights and tech news here.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.