Objective-C создает слабый блок для проверки освобождения памяти - PullRequest
0 голосов
/ 21 октября 2018

Я прочитал, что если вы назначите новый объект для слабого свойства, объект будет освобожден после назначения.Даже предупреждение от компилятора одинаково.

@interface RetainCycleObjCViewController ()
{
}
@property (nonatomic, weak) void (^weakBlock)(void);
@end

@implementation RetainCycleObjCViewController
- (void)viewDidLoad {
    [super viewDidLoad];

 _weakBlock = ^void{
        NSLog(@"Execution inside a weakBlock");
    };

_weakBlock();
}
@end

Я получаю то же предупреждение для слабого блока: Назначение литерала блока слабой переменной;объект будет освобожден после присваивания

Но когда я выполняю _weakBlock () в следующей строке, он все равно печатает инструкцию.Как это возможно?потому что недавно созданный объект блока должен был быть удален из памяти, учитывая количество ссылок 0?

1 Ответ

0 голосов
/ 21 октября 2018

Вы фактически не выделяете блок в этом коде.Тело блока - все статическое содержание;после компиляции ничего не изменится.

Если вы сделаете это:

    _weakBlock = ^void{
        NSLog(@"Execution inside a weakBlock");
    };
    NSLog(@"%@", [_weakBlock class]);

Вы увидите это:

2018-10-21 09:33:48.827423-0500 kdkdkdkds[9367:1777827] __NSGlobalBlock__

Компилятор распознал, что блок ничего не захватываетэто может измениться во время выполнения и, соответственно, создать глобальный статический блок, который никогда не будет выделен.

Как сказал @Brandon в комментарии, если вы объявили локальную переменную в своей области и вызвали блок стекавыделено, что не уйдет до конца объема.

@autoreleasepool {
    void __weak (^_weakBlock)(void);
    int k = 2;
    _weakBlock = ^void{
        NSLog(@"Execution inside a weakBlock (%d)", k);
    };
    NSLog(@"C; %@", [_weakBlock class]);
    NSLog(@"P; %p", _weakBlock);
}
2018-10-21 09:36:31.585458-0500 kdkdkdkds[9392:1780803] C; __NSStackBlock__
2018-10-21 09:36:31.586291-0500 kdkdkdkds[9392:1780803] P; 0x7ffeefbff4c0

Теперь назначение переменной экземпляра немного меняет правила, поскольку вы назначаете вне области действия.

@interface SpongeBob:NSObject
@end

@interface SpongeBob ()
{
}
@property (nonatomic, weak) void (^weakBlock)(void);
@end

@implementation SpongeBob
- (instancetype)init
{
    self = [super init];
    if (self) {
        int k = 2;
        _weakBlock = ^void{
            NSLog(@"Execution inside a weakBlock (%d)", k);
        };
        NSLog(@"C; %@", [_weakBlock class]);
        NSLog(@"P; %p", _weakBlock);
    }
    return self;
}
@end


int main(int argc, const char * argv[]) {
    @autoreleasepool {
        [[SpongeBob alloc] init];
    }
    return 0;
}

2018-10-21 09:43:39.518545-0500 kdkdkdkds[9480:1787889] C; __NSStackBlock__
2018-10-21 09:43:39.518883-0500 kdkdkdkds[9480:1787889] P; 0x7ffeefbff488

Подождите.Какие?Если это значение действительно присваивается ивару, то это бомба замедленного действия.Итак, давайте попробуем кое-что:

Если мы добавим:

- (void)squarePants
{
    NSLog(@"C; %@", [_weakBlock class]);
    NSLog(@"P; %p", _weakBlock);
}

И затем назовем это:

    SpongeBob *bob = [[SpongeBob alloc] init];
    [bob squarePants];

Это происходит сбой, как и ожидалось, потому что блок стекабольше не действительны как init область

(Это кажется довольно значительным. С другой стороны, если вы устраните предупреждение, сбой исчезнет.)

Теперь, если вы скопируете блокпри назначении, затем немедленное освобождение при назначении делает вкл:

    _weakBlock = [^void{
        NSLog(@"Execution inside a weakBlock (%d)", k);
    } copy];

2018-10-21 09:48:04.295762-0500 kdkdkdkds[9510:1792549] C; (null)
2018-10-21 09:48:04.296167-0500 kdkdkdkds[9510:1792549] P; 0x0
...