Как среда выполнения Objective C может узнать, жив ли объект со слабой ссылкой?
С появлением ARC стали доступны некоторые новые функции, позволяющие разработчикам поиграться со объектами со слабыми ссылками. id objc_loadWeak(id *location)
это один из них. Эта функция получает соответствующий параметр в определенном месте в памяти, где хранился слабый объект, и возвращает этот объект, если он еще жив или nil
если бы это было освобождено.
Кажется, что когда объект obj
хранится как weak
в месте location
с id objc_storeWeak(id *location, id obj)
, obj
помещается в "слабую карту", с location
в качестве ключа. Однако для того, чтобы получить obj
, objc_loadWeak
можно не только использовать location
в качестве ключа и вернуть значение, которое соответствует obj
, Он также должен проверить, obj
еще жив, чтобы вернуться nil
если это больше не так.
Тем не мение, objc_loadWeak
не может попытаться прочитать счет удержания объекта, потому что объект, возможно, был освобожден. Более того, хотя слабая карта, objc_storeWeak
, objc_loadWeak
и NSObject
класс реализован в одном файле ( NSObject.mm), NSObject
"s dealloc
Метод не сообщает слабой карте, что объект, который освобождается, исчезает.
Итак, как во время выполнения Objective-C выяснить, является ли weak
объект еще жив?
1 ответ
Метод dealloc NSObject не сообщает слабой карте, что объект, который был освобожден, исчезает.
Оно делает.
- [NSObject dealloc]
звонки
_objc_rootDealloc(self);
что в свою очередь вызывает
object_dispose()
который в свою очередь вызывает
objc_destructInstance()
который, наконец, вызывает
objc_clear_deallocating()
Эта последняя функция выглядит так:
void
objc_clear_deallocating(id obj)
{
assert(obj);
assert(!UseGC);
SideTable *table = SideTable::tableForPointer(obj); /* *** THIS LINE *** */
// clear any weak table items
// clear extra retain count and deallocating bit
// (fixme warn or abort if extra retain count == 0 ?)
OSSpinLockLock(&table->slock);
if (seen_weak_refs) {
arr_clear_deallocating(&table->weak_table, obj); /* *** THIS LINE *** */
}
table->refcnts.erase(DISGUISE(obj)); /* *** THIS LINE *** */
OSSpinLockUnlock(&table->slock);
}
Три выделенные линии делают волшебство. SideTable
это класс C++, реализованный в NSObject.mm
из которых refcnts
Переменная-член делает именно то, что звучит, как и она: она содержит количество ссылок.