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

Run 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