1

以前にも似たような質問をしたことがありますが、今回は少し状況が異なります。

1 つには、今回は ARC を使用しています (まったく新しい問題の世界を招きます)。2番目: 私が持っているコードは基本的に機能しますが、より少ないコードでできるかどうか疑問に思っています。

現在、私のコードは次のようになっています。

__weak CustomType *Object;
void (^doAverage)(CustomType *, int, int) = ^(CustomType *Trigger, int Val1, int Val2) {
    //Calculations with Trigger
}

CustomType *(^Add)(int, CustomType *) = ^(int Val1, CustomType *NewObject) {
    //Checks prerequisites, and returns either the passed object after adding it to 
    //an array or nil, if the prerequisites haven't been met.
}

今、さらに下に、私はこれをやっています:

Object = Add(-1, [CustomType makeObjectWithParameters]);
[Object addCallback:^{ doAverage(Object, 56, 57); }];

内部addCallbackでは、 への呼び出しで渡されたブロックにメッセージdoAverageが送信さcopyれ、後で実行するために保存されます。

これは機能し、保持サイクルはありません。オブジェクトの割り当てが解除されると、コールバックは折りたたまれます。

しかし、それは私が望むほど「エレガント」ではありません。

私が望むのは、次のようなものです。

__block __weak CustomType *Object;

CustomType *(^Add)(int, CustomType *) = ^(int Val1, CustomType *NewObject) {
    //Checks prerequisites, and returns either the passed object after adding it to 
    //an array or nil, if the prerequisites haven't been met.
    Object = NewObject;
}

そしてさらに下に:

[Add(-1, [CustomType makeObjectWithParameters]) addCallback:^{ doAverage(Object, 56, 57); }];

ただし、このようにするObjectと、コールバックに渡されたAddものが最後に呼び出したものに変更されますが、これは私が望んでいるものではありません。

基本的に、参照を変数自体に渡すのではなく、ブロック内setの値を取得してから、その参照をパラメーターとして渡す必要があります。Objectcopy

Objectさらに、2 番目のステップとして、そもそもパラメーターを渡す必要がなく、ブロックで使用できれば、ほぼ完璧です。しかし、それを行うと、ブロックが最終的に呼び出されたときに、ブロック内の変数はデフォルトで nil になります (定義されたスコープの有効期限をかなり過ぎています)。

したがって、代わりに:

void (^doAverage)(CustomType *, int, int) = ^(CustomType *Trigger, int Val1, int Val2) {
    //Calculations with Trigger
}

私は使用したい:

void (^doAverage)(int, int) = ^(int Val1, int Val2) {
    //Calculations with Object
}

Objectその時点でどのような値(弱い参照) があったとしても。

2つのどちらかがどういうわけか可能ですか?

どうもありがとうございました。

編集:

以下の提案に従って、コードを次のようにリファクタリングしました。

typedef BOOL (^stackBlock_t)();
typedef BOOL (^CallBlock_t)(__weak id Object);

-(void) addCallback(CallBlock_t)B {
    stackBlock_t stackBlock = ^{
        __weak id Object = self;
        return B(Object);
    };

    Callback = [stackBlock copy];
}

私はこのコンストラクトを次のように呼び出そうとしています:

[Add(-1, CustomType makeObjectWithParameters]) addCallBack:^{ doAverage(Object, 56, 57); }];

ただし、何らかの理由でブロックに対してObject定義されてdoAverageいません。その理由はよくわかりません。結局、これは type のブロックであり、 typeと nameCallBlock_tのパラメーターを取ります。それでは、変数について「知っている」べきではありませんか?idObjectObject

編集2:少しいじくり回した後(つまり、実際の型などを使用して)、別のエラーメッセージが表示されるようになりました: Incompatible block pointer types sending 'void (^)(void)' to parameter of type 'CallBlock_t'、私はそうではありません。BOOLそのブロックに a を返して引数を取ってもらいたいObject...何が間違っているのですか?

編集3:私はそれを見つけたかもしれません。addCallback通話に何かが欠けていました。まだテストしていませんが、次のように呼び出す必要があるようです。

[Add(-1, CustomType makeObjectWithParameters]) addCallBack:^(CustomObject *Object){ doAverage(Object, 56, 57); }];

考えてみれば、理にかなっている...目には恐ろしいですが、理にかなっています。そして、それは魅力のように機能します。型の余分な変数はもう必要ありません__block

4

2 に答える 2

1

ブロックはストレージの場所への参照 (強いまたは弱い) をキャプチャしているだけなので、そのインスタンス数と有効期間はそのストレージの場所に関連付けられています (ただし、ブロックが最初にコピーされたときにスタック ポインターがヒープに割り当てられ、参照が更新されました)。

したがって、Object が常に同じ値である理由は明らかです。コピーされたすべてのブロックは、スタック割り当て値を使用して単一の関数内でこれらすべてを行ったかのように、キャプチャされた同じ場所を指します。

addCallback では、次のことができます。

- (void)addCallback:(void^(CustomType*))action {
   void(^stackBlock)(void) = ^{
      __weak CustomType *localObj = Object;
      action(localObj);
   };
   self.callback = [stackBlock copy];
}

これにより、 addCallback が呼び出された時点の現在の値が何であれ、要求した最初の部分と一致する必要があります。

すべてがセットアップされている方法を考えると、2番目の部分は不可能だと思います。addCallback だけが Object の特定の時点の値を取得します。パラメーターを使用しないと、それを doAverage に渡す方法がありません。呼び出している関数がわからないためです。残念ながら、動的ブロック ディスパッチを行うクリーンで簡単な方法はありません。それ以外の場合は、addCallback でブロックと varargs パラメータ リストを取得し、オブジェクトと指定されたパラメータでブロックを呼び出すことができます。

于 2013-06-24T05:15:17.313 に答える
0

「個別のローカル変数に作用するコードを保持できるもの」は、クラスのインスタンスのように見えます。

于 2013-12-02T11:51:46.153 に答える