Objective-c: анимация UIView + блок + рекурсия

    #import "ViewController.h"

    typedef  void (^myBlock)(int );

    @interface ViewController ()

    @property (strong, nonatomic) IBOutlet UIView *testView;

    @end

    @implementation ViewController

    - (IBAction)blockTest:(id)sender
    {
        [self blockRecursion:0];
    }

    - (void)blockRecursion:(NSInteger)n
    {
        __weak myBlock __block block = ^(int bn)
        {
            NSLog(@"%d", bn);
            if(bn < 10)
            {
                [self getData:block num:++bn];
            }
        };

        block(0);
    }


    - (void)getData:(myBlock)block num:(NSInteger)bn
    {
        self.testView.alpha = 1;
        [UIView animateWithDuration:0.5 delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
            self.testView.alpha = 0;
        } completion:^(BOOL finished) {
            block(bn);
        }];
    }

    @end

Выполнить Crash: ошибка: адрес не содержит раздел, который указывает на раздел в объектном файле

__weak myBlock __block block = ^(int bn);
//Changed to 
myBlock __block block = ^(int bn);

Показывать предупреждение: сильный захват «блока» в этом блоке может привести к циклу удержания.

Как решить эту проблему?


person lofocus    schedule 08.11.2013    source источник


Ответы (1)


Проблема с вашим кодом в том, что нет строгой ссылки на блочный объект. block — слабая ссылка. Таким образом, после оператора, в котором создается блочный объект, блочный объект потенциально может быть освобожден, что установит __weak переменную block в nil. Вызов блока с указателем блока nil приводит к сбою.

Когда вы удаляете __weak, вы создаете цикл сохранения — блок сохраняет сильную ссылку на себя.

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

    myBlock blockStrong;
    __block __weak myBlock blockWeak;
    blockWeak = blockString = ^(int bn)
    {
        NSLog(@"%d", bn);
        if(bn < 10)
        {
            [self getData:blockWeak num:++bn];
        }
    };
person newacct    schedule 08.11.2013
comment
Не приведет ли обращение к себе внутри этого блока и здесь к циклу сохранения? - person danielbeard; 09.11.2013
comment
@danielbeard: нет, потому что self нигде не сохраняет этот блок. где ты видишь цикл? - person newacct; 09.11.2013