2

ブロックをコンストラクターに渡す目的の C オブジェクトがあります。完全にロードされたときにビューコントローラーでそのブロックを起動したいのは特別なケースです。ただし、そのブロックでは、ブロックを渡すオブジェクトも参照したいと考えています。次の例を検討してください。

typedef void (^MyBlock)();

//constructor of my object
-(id)initMyObjectWithBlock:(MyBlock)block{
    self = [super init];
    if(self){
        myivar = block; //to be used later
    }
}

//somewhere else in my app
MyObject *obj = [[MyObject alloc] initMyObjectWithBlock:^{
   [obj doSomething];
}];

その[obj doSomething]行で、「ブロックによってキャプチャされたときに変数が初期化されていません」という警告が表示されますが、これは理にかなっています。そのブロックでは、「親」オブジェクト (objこの場合) への参照が必要です。これを達成する方法はありますか?私は特定の問題の回避策とパターンを知っていますが、そのような参照が可能かどうか知りたいと思っていました.

4

3 に答える 3

3
typedef void (^MyBlock)(MyObject*);

//constructor of my object
-(id)initMyObjectWithBlock:(MyBlock)block{
    self = [super init];
    if(self){
        myivar = block;
    }
}

//somewhere else in app
MyObject *obj = [[MyObject alloc] initMyObjectWithBlock:^(MyObject* myObj){
   [myObj doSomething];
}];

//and somewhere else in app
obj.myivar(obj);
于 2014-03-09T00:49:34.613 に答える
0

次のようにインスタンスを作成する前にオブジェクトを単純に設定するnilと、警告が処理されます。

__block TestClass *obj = nil;
obj = [[TestClass alloc] initMyObjectWithBlock:^{
    [obj doSomething];
}];

オブジェクトに関しては、イニシャライザ内でブロックを呼び出していないため、終了しますinitMyObjectWithBlock

上記のコードは機能しますが、ジョシュが述べたように、保持サイクルがあります。保持サイクルを回避するには、次のようなことができます。

TestClass *obj = nil;
__block __weak TestClass *objWeak = nil;

obj = [[TestClass alloc] initMyObjectWithBlock:^{
    TestClass *newObj = objWeak;

    [newObj doSomething];
}];

objWeak = obj;

ブロックに渡すダミー変数を作成するだけです。

于 2014-03-09T00:15:18.033 に答える
0

これは、Cy-4AH の回答への追加です。それをコメントに入れるのは長すぎました。

まず第一に、「回避策」に遭遇するのはコードの匂いです。それには 2 つの理由が考えられます。

A.MyObjectは 2 つの異なるタスクの共生です。2. 発火したら 1) で何かをする。侵入MyObjectMyObject1MyObject2助けることができます。しかしもちろん、もっと情報が必要です。

B. 多くの場合、1 つのオブジェクトが発火したときに、このオブジェクトに何かが発生するという概念が含まれています。(より多くの情報を取得する、状態を変更する、…) この場合、パターンは非常に簡単です:selfブロックに渡します:

Cy-4AH より:

typedef void (^MyBlock)(MyObject*);

//constructor of my object
-(id)initMyObjectWithBlock:(MyBlock)block{
    self = [super init];
    if(self){
        myivar = block;
    }
    return self; // Added this line for obvious reasons
}

//somewhere else in app
MyObject *obj = [[MyObject alloc] initMyObjectWithBlock:^(MyObject* myObj){
   [myObj doSomething];
}];

少し変更します。

の中MyObjectで、ブロックを呼び出しているとき

self.myivar( self );

__block __unsafe_unretained __weakCy-4AH が言ったように、概念上の問題をカバーするためにすべてのゴミは必要ありません。

于 2014-03-09T11:39:32.443 に答える