2

ので、私は持っています:

@interface testAppControl : NSObject
{
    NSString *s;
}

そして、私のブロックでやりたいこと

[SendAPI setGroupWithName:groupName completionHandler:^(NSArray *errors) {
    s = @"something";
}];

NSLog(@"%@", s); //<--- s is null

"something"そのため、ブロックを離れた後も値を保持したいと考えています。これはARCで可能ですか?

4

4 に答える 4

3

変数として宣言すると__block、ブロック外で使用し、ブロック内で変更できます。

__block NSString *s = nil;

void(^block)(void) = ^ {
    s = @"something";
};
block();
NSLog(@"%@", s);

s = @"blah";
NSLog(@"%@", s);

block();
NSLog(@"%@", s);
于 2013-05-02T21:02:13.893 に答える
3

が存在するだけで、それが非同期メソッドcompletionHandlerであると論理的に推測される可能性があります。setGroupWithNameこれは iOS 開発における一般的なプログラミング パターンです。時間のかかるプロセスをフォアグラウンドで実行するのではなく (その間にユーザー インターフェイスがフリーズします)、バックグラウンドで非同期に実行しますが、この場合はブロックを渡しますcompletionHandler。非同期プロセスが完了したときに何が起こるべきかを特定できます。

この場合、バックグラウンド スレッド/キューで を呼び出しているように見えますが、それがsetGroupWithName起こっている間はメイン スレッド (この場合はそのNSLogステートメント) を続行し、アプリの応答性を維持することを理解しています。その遅い操作が完了している間。しかし、その非同期バックグラウンド操作setGroupWithNameが完了すると、 によって表されるコードのブロックが実行さcompletionHandlerれます (この場合、stoの設定@"something")。

に設定しているブロックNSLog内にステートメントを配置すると、 の呼び出し後にある既存のステートメントのかなり後にそれが発生していることがわかります。completionHandlers@"something"NSLogsetGroupWithName


completionHandler例を説明するために、パラメータを持つ標準的な Cocoa メソッド、つまりNSURLConnectionクラス メソッドの例を次に示しますsendAsynchronousRequest

問題は、遅い操作を実行する方法ですが、遅いインターネット操作を待たずに応答性の高いユーザー インターフェイスを維持する方法です。

したがって、次のコードを検討してください。

- (void)performSearch:(NSString *)term
{
    NSLog(@"%s start: array has %d items", __FUNCTION__, [self.array count]);

    // prepare to do search (the details here are not relevant)

    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"http://search.twitter.com/search.json?q=%@", term]];
    NSURLRequest *request = [NSURLRequest requestWithURL:url];

    // submit an Internet search that will be performed in the background

    [NSURLConnection sendAsynchronousRequest:request
                                       queue:queue
                           completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {

                               // in the background, when the Twitter search is done,
                               // and when it's done, we'll make an array of the results

                               self.array = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
                               NSLog(@"%s: after background query, array now has %d items", __FUNCTION__, [self.array count]);
                           }];

    // in the meantime, let's immediately carry on while that search is taking place

    NSLog(@"%s end: array still has %d items", __FUNCTION__, [self.array count]);
}

このコードの詳細はそれほど重要ではありませんが、基本的な考え方は、何か遅いこと (インターネットで Twitter 検索を実行すること) を行っているということですが、すぐにメイン スレッドでコードを実行し続け、バックグラウンド スレッドを独自のペース。

NSLogさまざまなステートメントのタイムスタンプは、これらすべてのタイミングを示しています。

2013-05-02 20:42:58.922 myapp[81642:c07] -[ViewController performSearch:] 開始: 配列に 0 項目があります
2013-05-02 20:42:58.923 myapp[81642:c07] -[ViewController performSearch:] end: 配列にはまだ 0 個の項目があります
2013-05-02 20:42:59.798 myapp[81642:1303] __32-[ViewController performSearch:]_block_invoke: バックグラウンド クエリの後、配列には 11 項目が含まれるようになりました

「開始」から「終了」までの経過時間は約 1 ミリ秒ですが、バックグラウンドでの Twitter 検索の完了にはほぼ 1 秒かかりました。設計原則は、これを非同期で行わなかったcompletionHandler場合 (この場合は を使用)、アプリのユーザー インターフェイスがその 1 秒間フリーズするというものです。しかし、非同期プログラミング手法を使用することで、アプリは良好で応答性に優れたままになりましたが、バックグラウンドで低速な操作が実行されました。

私はあなたのsetGroupWithName方法に精通していませんが、おそらく同じ種類の非同期操作を実行しています。したがって、直後に値を見ようとする試みは、そのメソッドが完了すると変更される値を反映しません (私の例の「終了」NSLog ステートメントが、発生する変更を反映していないという事実のようなものです。 2 番目以降)。

于 2013-05-02T23:32:38.837 に答える
0

非同期操作を実行しているように見えますが、完了ブロックが呼び出されると、s定義された関数/スコープをすでに離れています。

「グローバル」スコープ (クラス変数やプロパティなど) で宣言sすることを検討すると、クラス インスタンスが生きている限り、ブロックによって設定された結果を読み取ることができます。

インスタンス保持の割り当てが解除された場合のメモリアクセスの悪さを避けるために、プロパティを使用し、ブロック内の「弱い自己」ポインターをキャプチャすることをお勧めしsます。

于 2013-05-02T21:02:02.750 に答える
0

なぜ、何をしたいのか完全に明確ではないので、3つのオプションを提供します。

  • ブロックの外側で変数を宣言するsと、ブロックの内側に自動的にコピーされます
  • その値を変更し、 __block指定子を使用してブロックの外で宣言する必要がある場合は、非同期プロセスでその変数を変更している場合、ブロックの後の値はおそらく役に立たないことに注意してください
  • ブロックへの各呼び出し中にその値を保持して変更したい場合は、ブロックstatic内でのみブロック内で「表示」されます。
于 2013-05-02T20:57:16.387 に答える