self.completionBlock = ^ {}と(void)(^ completeBlock)(void)= ^ {}の違い

arango_86

最近Appleのドキュメントに従った後

Appleデベロッパビデオのスクリーンショット 保持サイクルの問題を回避するために、次の規則を使用しました。

__weak __typeof(self) weak_self = self;
void(^completionBlock)(void) = ^(){

    __typeof(self) strong_self = weak_self;
    if (strong_self) {

        if (strong_self->_completion != NULL) {
            strong_self->_completion();
        }
    }
};

しかし、ブロックを呼び出す前に自己の割り当てが解除されているため、このコードはクラッシュしていることがわかりました。

私が以下を使用したとき、それは機能していることがわかりました。

__block __typeof(self) block_self = self;
void(^completionBlock)(void) = ^(){

     if (block_self->_completion != NULL) {
         block_self->_completion();
     }
};

__weak参照をいつ使用すべきか混乱しています。次の「self.completionBlock」の場合のみ

__weak __typeof(self) weak_self = self;
self.completionBlock = ^(){

     if (weak_self->_completion != NULL) {
         weak_self->_completion();
     }
};

この条件に関するどんな光も私にとって非常に役に立ちます。

私の実装コードを以下に示します。

=================================================

ファイルMyViewController

@implementation MyViewController

//starting point 
- (void)myPushMethod {
    __weak __typeof(self) weak_self = self;
    MyViewControllerTransitioning *delegateObj = [[MyViewControllerTransitioning alloc] initWithCompletion:^{

        //resetting the delegate
        __typeof(self) strong_self = weak_self;
        if (strong_self) {
            strong_self.navigationController.delegate = nil;
        }
    }];
    self.navigationController.delegate = delegateObj;
    [self.navigationController pushViewController:someViewController animated:_animated];
    //it is found that delegateObj is getting deallocated while reaches this point
}

@end

=================================================

ファイルMyViewControllerTransitioning

@implementation MyViewControllerTransitioning

- (instancetype)initWithCompletion:(completionHandler)completionHandler
{
    if(self = [super init])
    {
        if (completionHandler != NULL) {
            _completion  = completionHandler;
        }
    }
    return self;
}

- (id <UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController
                                   animationControllerForOperation:(UINavigationControllerOperation)operation
                                                fromViewController:(UIViewController *)fromVC
                                                  toViewController:(UIViewController *)toVC
{
    id<UIViewControllerAnimatedTransitioning> animationTransitioning = nil;

    //crashes here
    __block __typeof(self) block_self = self;
    void(^completionBlock)(void) = ^(){

        if (block_self->_completion != NULL) {
            block_self->_completion();
        }
    };

    //showing presentation-up animation if Push
    if (operation == UINavigationControllerOperationPush) {
        animationTransitioning = [[MyAnimator alloc] initWithAnimationCompletion:completionBlock];
    }
    return animationTransitioning;
}

- (void)dealloc{
//dealloc is called before invoking completionBlock
}

@end

=================================================

ファイルMyAnimator

@implementation MyAnimator

- (instancetype)initWithAnimationCompletion:(presentationUpCompletion)completionHandler
{
    if(self = [super init])
    {
        if (completionHandler != NULL) {
            _completion  = completionHandler;
        }
    }
    return self;
}

- (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext
{
    return my_duration;
}

- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext {

    //animation logic

    [UIView animateWithDuration:duration animations: ^{
        //animation logic
    } completion: ^(BOOL finished) {
        [transitionContext completeTransition:![transitionContext transitionWasCancelled]];
    }];
}

- (void)animationEnded:(BOOL) transitionCompleted {
    if (transitionCompleted && _completion != NULL) {
        _completion();
    }
}

@end
ロブ

In my original answer, below, I walk through the standard weakSelf pattern (and the weakSelf-strongSelf "dance"). My conclusion was that presentation slide you reference is absolutely correct regarding the weakSelf pattern (though that presentation is stylistically dated).

You subsequently provided a more complete code sample, and it turns out that it suffers from a different, unrelated problem. (Worse, it was a problem that only manifests itself when the strong reference cycles are resolved. lol.) Bottom line, the code sets the delegate of the navigation controller to a local object which falls out of scope. Because the navigation controller doesn't retain its delegate, you were ending up with a dangling pointer to this deallocated object.

If you keep your own strong reference to this delegate object (keeping it from being deallocated), the problem goes away.


My original answer is below.


You said:

used the following conventions to avoid retain cycle issues.

__weak __typeof(self) weak_self = self;

void(^completionBlock)(void) = ^(){
    __typeof(self) strong_self = weak_self;
    if (strong_self) {
        if (strong_self->_completion != NULL) {
            strong_self->_completion();
        }
    }
};

But this code is found to be crashing because self is getting deallocated before invoking the block.

No, this is a very common pattern (often jokingly called the "weak self, strong self dance"). There is nothing wrong with this. If it's crashing, it's for other reasons.

Sure, I'd use modern naming conventions (weakSelf and strongSelf rather than weak_self and strong_self). And I'd remove the __ at the start of __typeof. And I wouldn't be inclined to dereference and ivar, but rather use a property. So, I might end up with something like:

__weak typeof(self) weakSelf = self;

void(^completionBlock)(void) = ^(){
    typeof(self) strongSelf = weakSelf;
    if (strongSelf) {
        if (strongSelf.completion != NULL) {
            strongSelf.completion();
        }
    }
};

But, still, if that is crashing, you have some other problem. Frankly, you have a block calling a block so it's a little hard to guess where your problem rests, but the problem is not in the "weak self" pattern.

Later you go on to suggest using:

__block __typeof(self) block_self = self;

That does not do what you think it does. The goal of the "weak self" pattern is to break the strong reference cycle (formerly known as retain cycle), but in ARC, this __block reference does nothing to resolve that strong reference cycle. Note, in non-ARC code, this block_self pattern was used to break retain cycles, but it will not do the job in ARC.

Finally, you go on to suggest:

__weak __typeof(self) weak_self = self;
self.completionBlock = ^(){
     if (weak_self->_completion != NULL) {
         weak_self->_completion();
     }
};

これには2つの重大な問題があります。まず、弱い変数を間接参照しています。場合weak_selfだったnil、それがクラッシュしていました。次に、ivarを逆参照するのではなく、プロパティアクセサメソッドを使用して修正したとしても、ここで別の問題、つまり競合状態が発生します。


結論として、そのプレゼンテーションの「弱い自己」パターンは正しいです。同様に、最初の例の「弱い自己、強い自己ダンス」も正しいです。クラッシュする場合は、問題を再現するMCVE提供する必要があります。しかし、ARCコードでは、これは完全に有効なパターンです。

この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。

侵害の場合は、連絡してください[email protected]

編集
0

コメントを追加

0

関連記事

分類Dev

セッターメソッドのvoidとselfの違いは何ですか

分類Dev

C ++でのvoid(*)()とvoid(&)()の違い

分類Dev

(void)objとvoid(obj)の違い

分類Dev

decltype(...、void())とvoid_tの違い

分類Dev

decltype(void())とdecltype(void {})の違い

分類Dev

「void 0」と「undefined」の違い

分類Dev

AutoとVoidの違いは?

分類Dev

AutoとVoidの違いは?

分類Dev

void()とint()の解析の違い

分類Dev

Mono <Void>とMono.empty()の違い

分類Dev

Objective-C:idとvoidの違い*

分類Dev

「C ++ void Pointer」と「C#var」の違い

分類Dev

void inject(Activity activity)とSomeComponent getSomeComponent()の違い

分類Dev

Dart 2:Future <void>とFuture <Null>の違い

分類Dev

C ++:contructor()とconstructor(void)の違い

分類Dev

C ++のvoid関数と非void関数の違い

分類Dev

java.lang.Voidとvoidの違いは何ですか?

分類Dev

<T extends A> void foo(T t)とvoid foo(A a)の違い

分類Dev

void insertElementAt(Object obj、int index)とvoid set(int index、object o)の違い

分類Dev

__str __(self)とshow(self)の違い

分類Dev

なぜ `void * = 0`と` void * = nullptr`が違いを生むのですか?

分類Dev

(void *)と(void(*)(argument type))キャストの違いは何ですか?

分類Dev

void関数(stuct * s)とvoid関数(stuct s)の違いは何ですか?

分類Dev

public voidメソッドとvoidメソッドの違いは何ですか?

分類Dev

typescriptのneverとvoidの違いは何ですか?

分類Dev

typescriptのneverとvoidの違いは何ですか?

分類Dev

Cでのvoid関数とfloat関数の違い

分類Dev

C言語:関数のfloatとvoidの違い

分類Dev

`inline`と` template <class = void> `の実際的な違いは何ですか?

Related 関連記事

  1. 1

    セッターメソッドのvoidとselfの違いは何ですか

  2. 2

    C ++でのvoid(*)()とvoid(&)()の違い

  3. 3

    (void)objとvoid(obj)の違い

  4. 4

    decltype(...、void())とvoid_tの違い

  5. 5

    decltype(void())とdecltype(void {})の違い

  6. 6

    「void 0」と「undefined」の違い

  7. 7

    AutoとVoidの違いは?

  8. 8

    AutoとVoidの違いは?

  9. 9

    void()とint()の解析の違い

  10. 10

    Mono <Void>とMono.empty()の違い

  11. 11

    Objective-C:idとvoidの違い*

  12. 12

    「C ++ void Pointer」と「C#var」の違い

  13. 13

    void inject(Activity activity)とSomeComponent getSomeComponent()の違い

  14. 14

    Dart 2:Future <void>とFuture <Null>の違い

  15. 15

    C ++:contructor()とconstructor(void)の違い

  16. 16

    C ++のvoid関数と非void関数の違い

  17. 17

    java.lang.Voidとvoidの違いは何ですか?

  18. 18

    <T extends A> void foo(T t)とvoid foo(A a)の違い

  19. 19

    void insertElementAt(Object obj、int index)とvoid set(int index、object o)の違い

  20. 20

    __str __(self)とshow(self)の違い

  21. 21

    なぜ `void * = 0`と` void * = nullptr`が違いを生むのですか?

  22. 22

    (void *)と(void(*)(argument type))キャストの違いは何ですか?

  23. 23

    void関数(stuct * s)とvoid関数(stuct s)の違いは何ですか?

  24. 24

    public voidメソッドとvoidメソッドの違いは何ですか?

  25. 25

    typescriptのneverとvoidの違いは何ですか?

  26. 26

    typescriptのneverとvoidの違いは何ですか?

  27. 27

    Cでのvoid関数とfloat関数の違い

  28. 28

    C言語:関数のfloatとvoidの違い

  29. 29

    `inline`と` template <class = void> `の実際的な違いは何ですか?

ホットタグ

アーカイブ