Принятие себя в качестве аргумента в блоке не вызывает циклическую ссылку, но внешняя ссылка на себя делает - PullRequest
0 голосов
/ 12 июня 2019

Кто подскажет, почему следующий код вызывает разные результаты, когда параметр теста и переменная testMember указывают на один и тот же адрес

@interface TestClass : NSObject

@property (nonatomic, copy) void (^testBlock)(TestClass *test);

@end

@implementation TestClass

- (void)viewDidLoad {
    [super viewDidLoad];
    self.testBlock(self);
}

@end

@implementation OtherClass

- (void)viewDidLoad {
    [super viewDidLoad];

    TestClass *testMember = [[TestClass alloc] init];

    // Case 1
    testMember.testBlock = ^(TestClass *test) {
        NSLog(@"%@",test); // This does not create circular references
    };

    // Case 2
    testMember.testBlock = ^(TestClass *test) {
        NSLog(@"%@",testMember); // This creates circular references
    };
}

@end

1 Ответ

0 голосов
/ 12 июня 2019

Для случая 1 переменная test является просто параметром локальной функции, блок не сохранил никаких других переменных извне.

Для случая 2 объект testMember происходит изблок снаружи при определении блока, блок сохраняет свой счетчик ссылок.Поскольку testBlock определяется как свойство класса TestClass, то testMember принадлежит testBlock.Итак, testMember и testBlock сохраняют друг друга, то есть циклические ссылки .

Чтобы исправить проблему циклического сохранения в случае 2, используйте это:

__weak TestObject *weakMember = testMember;

testMember.testBlock = ^(TestClass *test) {
    __strong TestObject *strongMember = weakMember;
    NSLog(@"%@", strongMember);
};

Поскольку переменная weakMember не увеличивает счетчик ссылок реального объекта testMember, то же самое произошло и с testBlock.При запуске выполнения testBlock, strongMember пытается сохранить объект weakMember (который может получить значение nil, зависит от вашей логической схемы) и уменьшить счетчик ссылок при завершении блока.

...