Почему на счет сохранения объекта может влиять @synchronized? - PullRequest
0 голосов
/ 31 декабря 2018

Я обнаружил, что количество сохраненных объектов, созданных внутри блока @synchronized, будет отличаться от тех, которые созданы за пределами блока @synchronized.

Случай 1: создать внутри блока @synchronized, количество сохранений наблюдателя равно 2:

- (NSUInteger)mv_observeKeyPath:(NSString *)keyPath
                  withBlock:(MVKVOBlock)block
                    options:(NSKeyValueObservingOptions)options {
    @synchronized (lock) {
        MVKVOProxy *observer = [MVKVOProxy observerWithTarget:self keyPath:keyPath block:block];
        // po [observer performSelector:@selector(retainCount)] is 2
        [self addObserver:observer forKeyPath:keyPath options:options context:NULL];
        return observer.observerID;
    }
}

Случай 2: создать вне блока @synchronized, сохранить счет наблюдателяравно 1:

- (NSUInteger)mv_observeKeyPath:(NSString *)keyPath
                  withBlock:(MVKVOBlock)block
                    options:(NSKeyValueObservingOptions)options {
    MVKVOProxy *observer = [MVKVOProxy observerWithTarget:self keyPath:keyPath block:block];
    @synchronized (lock) {
        // po [observer performSelector:@selector(retainCount)] is 1
        [self addObserver:observer forKeyPath:keyPath options:options context:NULL];
        return observer.observerID;
    }
}

Я знаю, что объект, возвращаемый методом, будет заключен в objc_retainAutoreleasedReturnValue и objc_autoreleaseReturnValue.Он используется для оптимизации, чтобы исключить бесполезные вызовы функций: [[obj autorelase] retain].

Определение метода objc_retainAutoreleasedReturnValue:

id objc_retainAutoreleasedReturnValue(id obj)
{
    if (acceptOptimizedReturn() == ReturnAtPlus1) return obj;

    return objc_retain(obj);
}

Я отладил и вошел в код сборки и обнаружил, что, только в случае 2, objc_retain вызываться не будет.

Метод objc_autoreleaseReturnValue of:

id objc_autoreleaseReturnValue(id obj)
{
    if (prepareOptimizedReturn(ReturnAtPlus1)) return obj;

    return objc_autorelease(obj);
}

В обоих случаях будет вызываться objc_autorelease.

Следовательно, в случае 1 стек вызовов методов равен [[observer autorelaase] retain], в случае 2 - стек вызовов методов [observer autorelaase].

Разве это не странно?Почему @synchronized влияет на ARC?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...