22

EDIT2:

いいえ。提案された回答は、非同期呼び出しに関するものです。通常の標準的な再帰呼び出しのように、同期呼び出しが必要です。

編集:

その間

__unsafe_unretained void (^unsafe_apply)(UIView *, NSInteger) ;

警告やエラーなしでコンパイルすると、実行時に失敗し、unsafe_apply に NULL が格納されます。

ただし、これ:

- (void) applyToView: (UIView *) view {

    UIColor * (^colorForIndex)(NSInteger) = ^(NSInteger index) {
        return [UIColor colorWithHue: ((CGFloat) index / 255.0f)
                          saturation: 0.5f
                          brightness: 0.5f
                               alpha: 1.0f] ;
    } ;

    void (^applyColors) (UIView *, NSInteger index) = ^(UIView * view, NSInteger index) {
        view.backgroundColor = colorForIndex(index) ;
    } ;

    void (^__block recurse_apply)(UIView *, NSInteger) ;

    void (^apply)(UIView *, NSInteger) = ^(UIView * view, NSInteger level) {
        applyColors(view, level) ;
        [view.subviews enumerateObjectsUsingBlock:^(UIView * subview, NSUInteger idx, BOOL *stop) {
            recurse_apply(subview, 1+level) ;
        }] ;
    } ;

    recurse_apply = apply ;

    apply(view, 0) ;
}

警告なしでコンパイルされますが、さらに重要なことは、実際に実行されることです。

しかし、これはとても醜いです!


考慮してください(目的を公開するために、ビュー階層に色を付けます...)

- (void) applyToView: (UIView *) view {

    UIColor * (^colorForIndex)(NSInteger) = ^(NSInteger index) {
        return [UIColor colorWithHue: ((CGFloat) (index * 10.0f) / 255.0f)
                          saturation: 0.5f
                          brightness: 0.5f
                               alpha: 1.0f] ;
    } ;

    void (^applyColors) (UIView *, NSInteger index) = ^(UIView * view, NSInteger index) {
        view.backgroundColor = colorForIndex(index) ;
    } ;

    void (^apply)(UIView *, NSInteger) = ^(UIView * view, NSInteger level) {
        applyColors(view, level) ;
        [view.subviews enumerateObjectsUsingBlock:^(UIView * subview, NSUInteger idx, BOOL *stop) {
            apply(subview, 1+level) ;
        }] ;
    } ;

    apply(view, 0) ;
}

次の警告が表示されます。

/Users/verec/Projects/solotouch/SoloTouch/BubbleMenu.m:551:42:Block pointer variable 'apply' is uninitialized when captured by block

提案された修正を適用すると:Maybe you meant to use __block 'apply'

void (^__block apply)(UIView *, NSInteger) = ^(UIView * view, NSInteger level) {

/Users/verec/Projects/solotouch/SoloTouch/BubbleMenu.m:554:13:Capturing 'apply' strongly in this block is likely to lead to a retain cycle

コードを改ざんしてそれらの警告を取り除くためにさまざまな方法を試しました

__weak typeof (apply) wapply = apply ;
if (wapply) {
    __strong typeof (wapply) sappy = wapply ;
    wapply(subview, 1+level) ;
}

しかし、事態はさらに悪化し、エラーに変わります。

私はこれで終わった:

__unsafe_unretained void (^unsafe_apply)(UIView *, NSInteger) ;

void (^apply)(UIView *, NSInteger) = ^(UIView * view, NSInteger level) {
    applyColors(view, level) ;
    [view.subviews enumerateObjectsUsingBlock:^(UIView * subview, NSUInteger idx, BOOL *stop) {
        unsafe_apply(subview, 1+level) ;
    }] ;
} ;

unsafe_apply = apply ;

apply(view, 0) ;

ここでしなければならなかったように、ブロック内からすべてを行うことができ、恐ろしいバックパッチを適用する必要がない、より良い解決策は誰にもありますか?

これらのSO の質問はキャプチャに関するものselfであり、これらのSOの 質問には満足のいく答えがないことに注意してください。

4

3 に答える 3

1

ARC 警告を回避し、@newacct の回答に基づいて構築するために、保持ブロック内に弱いブロックを設定すると機能することがわかりました。

//a block definition
typedef void (^CompletionType)(NSDictionary * __nullable response, NSError * __nullable error);


//a block calling itself without the ARC retain warning
__block CompletionType completionBlock = nil;
__block __weak CompletionType weakCompletionBlock = nil;
completionBlock = ^(NSDictionary *response, NSError *error) {
    weakCompletionBlock = completionBlock;

        weakCompletionBlock();

    });
};
于 2016-07-06T10:24:36.867 に答える
0

答えはノーだ。

__block 修飾子を使用するよりも良いことはないようです。

__block void(^strawberryFields)();
strawberryFields = ^{ strawberryFields(); };
strawberryFields();

ブロックに関するBill Bumgarnerの記事に感謝します。


編集:

__block __weak void(^strawberryFields)();

ARCの下で好ましい方法のようです。

于 2013-11-10T02:23:22.283 に答える