The realization principle of weak in iOS

There are tens of thousands at the bottom, I pretended not to see...

 

Basic usage of weak

Weak is a weak reference, and the counter of the modified or referenced object with weak description will not increase by one, and will be automatically set to nil when the referenced object is released, which greatly avoids the situation that wild pointer accesses bad memory and causes a crash. Weak can also be used to resolve circular references.

Summary of weak principle

The weak table is actually a hash (hash) table, the Key is the address of the pointed object, and the Value is the address array of the weak pointer. What is the principle of the underlying implementation of weak?

Runtime maintains a weak table for storing all weak pointers to an object. The weak table is actually a hash table, the key is the address of the pointed object, and the value is the address of the weak pointer (the value of this address is the address of the pointed object pointer) array.
Why is value an array? Because an object may be pointed to by multiple weak reference pointers

Implementation steps of weak principle

The realization principle of weak can be summarized in three steps:

1. During initialization: runtime will call the objc_initWeak function to initialize a new weak pointer to the address of the object.

 

Initialization flowchart

2. When adding a reference: the objc_initWeak function will call the objc_storeWeak() function, and the function of objc_storeWeak() is to update the pointer to create the corresponding weak reference table.

Update pointer, create weak reference table

3. When releasing, call the clearDeallocating function. The clearDeallocating function first obtains an array of all weak pointer addresses according to the object address, then traverses the array and sets the data in it to nil, finally deletes the entry from the weak table, and finally clears the object's records.

The detailed process of weak implementation in three steps:

1. During initialization: runtime will call the objc_initWeak function, and the objc_initWeak function will initialize a new weak pointer to the address of the object.

Sample code:

 NSObject *obj = [[NSObject alloc] init];
 id __weak obj1 = obj;

When we initialize a weak variable, runtime will call the objc_initWeak function in NSObject.mm.

The declaration of this function in Clang is as follows:
id objc_initWeak(id *object, id value);

The implementation of the objc_initWeak() method is as follows:

id objc_initWeak(id *location, id newObj) {
// 查看对象实例是否有效,无效对象直接导致指针释放
    if (!newObj) {
        *location = nil;
        return nil;
    }
    // 这里传递了三个 bool 数值
    // 使用 template 进行常量参数传递是为了优化性能
    return storeWeakfalse/*old*/, true/*new*/, true/*crash*/>
    (location, (objc_object*)newObj);
}

Firstly, it is judged whether the class object pointed to by its pointer is valid, and the invalid is directly released and returned, and no further functions are called. Otherwise, object will be registered as a __weak object pointing to value through the bjc_storeWeak function.

Note: The objc_initWeak function has a prerequisite: object must be a valid pointer that is not registered as a __weak object. The value can be null or point to a valid object.

2. When adding a reference: the objc_initWeak function will call the objc_storeWeak() function, and the function of objc_storeWeak() is to update the pointer to create the corresponding weak reference table.

The function declaration of objc_storeWeak is as follows:

id objc_storeWeak(id *location, id value);

For the specific implementation of objc_storeWeak(), please refer to the method of weak reference implementation. The implementation here is very complicated, I didn't understand it.

3. When releasing, call the clearDeallocating function. The clearDeallocating function first obtains an array of all weak pointer addresses according to the object address, then traverses the array and sets the data in it to nil, finally deletes the entry from the weak table, and finally clears the object's records.

How to deal with the weak pointer when the object pointed to by the weak reference is released? When the object is released, the basic process is as follows:

1、调用objc_release
2、因为对象的引用计数为0,所以执行dealloc
3、在dealloc中,调用了_objc_rootDealloc函数
4、在_objc_rootDealloc中,调用了object_dispose函数
5、调用objc_destructInstance
6、最后调用objc_clear_deallocating,详细过程如下:
   a. 从weak表中获取废弃对象的地址为键值的记录
   b. 将包含在记录中的所有附有 weak修饰符变量的地址,赋值为   nil
   c. 将weak表中该记录删除
   d. 从引用计数表中删除废弃对象的地址为键值的记录

Expansion supplement

weak,__unsafe_unretained, unowned 与 assign区别

  • __unsafe_unretained: The object will not be retained. When the object is destroyed, it will still point to the previous memory space (wild pointer)

  • weak: The object will not be retained. When the object is destroyed, it will automatically point to nil

  • assign: essentially equivalent to __unsafe_unretained

  • Unsafe_unretained can also modify properties that represent simple data types, and weak cannot modify properties that represent simple data types.

  • Compared with weak, __unsafe_unretained has a price to use weak, because from the above principle, __weak needs to check whether the object has died, and in order to know whether it has died, it naturally also needs some information to track the usage of the object. For this reason, __unsafe_unretained is faster than __weak, so when the lifetime of the object is clearly known, choosing __unsafe_unretained will have some performance improvements, and this performance improvement is very small. But when it is clear that __unsafe_unretained is also safe, it is naturally faster. And when the situation is uncertain, __weak should be preferred.

  • Unowned is used in Swift and can be divided into weak and unowned. The meaning of unowned is similar to __unsafe_unretained. If you know the lifetime of the object clearly, you can also choose unowned.



Link: https://www.jianshu.com/p/3c5e335341e0

Guess you like

Origin blog.csdn.net/wangletiancsdn/article/details/99552081