0

ブロック内の int の値を変更しようとしています。(このコード例では、SLRequest 自体は完全なアプリからのコンテキスト設定のみであり、ここで動作することは期待されていません。int の設定をテストできるように、コンパイルして実行するだけです。このためには、Socialframework をプロジェクトに含める必要があります。コンパイルする例。出力は以下に含まれています。)

#import "MainViewController.h"
#import <Social/Social.h>

@interface MainViewController ()

@end

@implementation MainViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    // This SLRequest stuff is just to provide the context for the block in question below
    NSString * theURLstr = @"http://someurl";
    NSURL * theNSURL = [[NSURL alloc] initWithString:theURLstr];
    SLRequest *theRequest = [SLRequest requestForServiceType: SLServiceTypeFacebook requestMethod:SLRequestMethodGET URL:theNSURL parameters:nil];
    [theRequest setAccount:nil]; // 

    // This is our test value.  We expect to be able to change it inside the following block
    __block int test = 44;
    NSLog(@"(BEFORE block) test is: %d", test);

    [theRequest performRequestWithHandler:
     ^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error2)
     {
         // We get here late.
         test = 27;
         NSLog(@"(INSIDE block) test is: %d", test);

     }];
    // We get here fine, but test isn't changed
    NSLog(@"(AFTER block) test is: %d", test); 
}

// --- 出力:

2013-02-10 19:13:53.283 debugExp1[92743:c07] (BEFORE block) test is: 44
2013-02-10 19:13:53.285 debugExp1[92743:c07] (AFTER block) test is: 44
2013-02-10 19:13:53.312 debugExp1[92743:1303] (INSIDE block) test is: 27

順不同の出力行に注意してください。中間を実行する前に開始および終了します。どうすればこれを修正できますか? その場所の int 値を変更し、ブロックの外で使用できるようにしたいだけです。

===更新===

この質問の複数の接線バージョンをオンラインで見つけていますが、私の目的には使用できない形式になっています。だから多分私は答えられない方法で私の質問を提起しています. コンテキストを追加してみましょう。

私のアプリは、Twitter で指定されたさまざまな種類の複数の Twitter API 呼び出しからデータを収集しています。表示用のテーブルを作成していません。ivar 内のデータと、最終的に管理対象オブジェクトが必要なだけです。アプリは Twitter データを取得するだけでなく、多くのことを行う必要があるため、ある時点で返されたデータにアクセスできるようにするためだけに、1 つの performRequestWithHandler ブロック内にアプリの構造をあまり多く入れたくありません。私にとって、ネットからデータを取得することはユーティリティ操作であり、アプリの設計を決定する唯一の要因ではありません。一部の API 呼び出しは、以前に特定の順序で実行された他のタイプの API 呼び出しから収集されたデータに特に依存しています。

データ オブジェクトから設定した ivar 値を使用できるように、以前の呼び出しがいつ終了したかを知る必要があります。

つまり、API 呼び出し #1 を作成し、さまざまな戻りデータを ivar に割り当て、performRequestWithHandler ブロックの外側で ivar を使用して他のことを行い、呼び出し #1 に基づいて API 呼び出し #2 および #3 を作成する方法が必要です。および後続の API 呼び出しが返され、最終的に他の viewController にシャッフルして、複数の API 呼び出しの戻り値から処理されたデータをさまざまな方法で表示します。

performRequestWithHandler が未指定のスレッドで実行され、いつ実行されるかわかりません。非常に短い待機時間を指定するつもりなので、同期されたネットワーク アクセスの遅延による UI の長い待機については心配していません。遅いネットワーク接続を待つためにユーザーを座らせるつもりはありません! 接続が遅い場合は、アクティビティ インジケーターを短時間表示し、アラートが表示されるまですぐに待つことをあきらめます。アプリのその部分は、ここで焦点を当てた私の課題ではありません。

私の課題は、複数の performRequestWithHandler 呼び出しから返されたデータを、それらの一部またはすべてが終了した後で 1 か所に集めることです。

performRequestWithHandler は、必要な種類の同期制御とデータ アクセスを実現するには高レベルの呼び出しである可能性があるように思えます。知らない。

上記のコード例は、コンパイルする簡単な方法で問題を分離して実証するために考えられる最も簡単な方法にすぎません。私は多くの変種を試しましたが、今のところ喜びはありません.

これが、私が取り組んでいるデザインのアイデアを明確にするのに役立つことを願っています.

あなたが提供できるかもしれない特定の助け、手がかり、またはアイデアをありがとう。ごくわずかな作業コード サンプルは、現時点では天の恵みですが、引き続き作業を続け、見つけた場合は解決策を投稿します。

4

3 に答える 3

3

ご覧のとおり、ブロックが実行される前に __block 変数を (2 回) 読んでいるという点で、あなた自身の質問に答えたと思います。

これは、呼び出している非同期メソッドです。viewDidLoadが戻ってからしばらくすると完了します。そのため、ログ出力の順序がまったく乱れているわけではありません。あなたが見ているのは、これらの呼び出しがどのように展開されるかという現実です。

設計について考え、このリクエストが完了するまでに時間がかかる可能性があることを認識する必要があります。特に、ユーザーが低速のネットワークを使用している場合などはそうです。そのため、リクエストの進行中にユーザーに何を提示するかを決定する必要があります。 、そしてリクエストが最終的に完了したときにユーザーを更新する方法。

編集

あなたのコメントから、うまくいけばあなたが立ち往生しないように、小さな例を挙げてみましょう。可能な同時実行性、メモリ管理、および設計への影響をすべて考慮した、完全に機能する例をここに書くことは必ずしもできません。ただし、開始する簡単な方法の 1 つは、View Controller の一部のプロパティを更新するだけのブロックをスケジュールすることです (View Controller が、リクエストが完了するか失敗するのに十分な時間存在していると仮定します!)

[theRequest performRequestWithHandler:
 ^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error2)
 {
     int test = 27;
     NSLog(@"(INSIDE block) test is: %d", test);

     // now schedule a block on the main queue which will update our UI with this
     // new data "27"
     dispatch_async(dispatch_get_main_queue(), ^{
         // here we are on the main queue, ready to read our test and do something with it.
         NSLog(@"(updating the UI) test is: %d", test);

         // now that we know we can read the data, we can save that data, update the UI, do
         // whatever is appropriate for your app
         // maybe this is as simple as:
         self.someProperty = test;

         // yes, there is a possible retain cycle here. Worry about that after
         // you have the basic mechanics of this understood.

     });

 }];

それがあなたを正しい方向に向けてくれることを願っています。これ以外にも、モバイル開発 (AndroidまたはiOS)にとって非常に重要なこれらの基本的な概念を理解するのに役立つ、優れたコース (無料および有料) がたくさんあることをお勧めします。非同期のメソッドとイベントを処理することは、モバイル デバイス上の "hello world" を超えたあらゆるものにとって現実です。

別の編集

あなたの質問に対するあなたの新しい編集を見ました。これは、ここでのコンテキストを説明するのに本当に役立ちます。さまざまな非同期呼び出しが多数発生している場合は、おそらくこれをビュー コントローラーから取り出して、このすべての作業を行い、結果を組み立てるデータ コントローラーに入れたいと思うでしょう。その場合、同じ基本原則が適用されます。より多くの呼び出しとより多くの順序付けについて考える必要があります。

于 2013-02-11T03:30:04.380 に答える
1

これは、NSNotificationに関するFirozeの提案に基づいて私が思いついた1つの解決策です。このバージョンでは int の代わりに文字列を使用していますが、テスト目的では同じ違いです。NSNotification は、実際には私が望んでいたよりも優れています! あるスレッドから別のスレッドにオブジェクトを転送する機能は非常に役立ちますが、ここでは nil のみを使用します。出力は以下です。

- (void)viewDidLoad
{
[super viewDidLoad];

// Test SLRequest wireframe
NSString * theURLstr = @"http://someurl";
NSURL * theNSURL = [[NSURL alloc] initWithString:theURLstr];
SLRequest *theRequest = [SLRequest requestForServiceType: SLServiceTypeFacebook requestMethod:SLRequestMethodGET URL:theNSURL parameters:nil];
[theRequest setAccount:nil];

// Set default
self.myNewTestStr = @"default";
NSLog(@"In viewDidLoad, self.myNewTestStr DEFAULT is %@", self.myNewTestStr);

// Listen on "weGotOurValue"
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(gotOurValue) name:@"weGotOurValue" object:nil];
// [ActivityAlert presentWithText:@"Please wait"];

// Pretend to get some data from the net
[theRequest performRequestWithHandler:
 ^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error2)
 {
     // Not sure I need this dispatch, btw
     dispatch_async(dispatch_get_main_queue(), ^{

         // Change the ivar
         self.myNewTestStr = @"changed";

         // Post notification "weGotOurValue" 
         [[NSNotificationCenter defaultCenter] postNotificationName:@"weGotOurValue" object:nil];
         // [ActivityAlert dismiss];
     });
 }];
}

// Called by NSNotificationCenter when it receives
// a postNotificationName:@"weGotOurValue" message
- (void) gotOurValue {
    NSLog(@"In gotOurValue, self.myNewTestStr is %@", self.myNewTestStr);
}

出力:

2013-02-12 17:44:52.300 debugExp1[5549:c07] In viewDidLoad, self.myNewTestStr DEFAULT is default
2013-02-12 17:44:52.354 debugExp1[5549:c07] In gotOurValue, self.myNewTestStr is changed
于 2013-02-13T02:08:47.117 に答える
-1

-(void)reloadProfile {

// 1

SLRequest *request = [SLRequest
                      requestForServiceType:SLServiceTypeFacebook
                      requestMethod:SLRequestMethodGET
                      URL:[NSURL URLWithString:@"https://graph.facebook.com/me"]
                      parameters:@{ @"fields" : @"id,first_name,last_name,gender,birthday,email,picture"}];

// 2
request.account = [FacebookController sharedFacebookController].facebookAccount;
// 3
__block NSDictionary *jsonDictD;
[request performRequestWithHandler:^(NSData *responseData,
                                     NSHTTPURLResponse *urlResponse, NSError *error) {
    if (error)
    {
        // 4
        [AppHelper showAlertViewWithTag:123 title:APP_NAME message:@"There was an error reading your Facebook account." delegate:nil cancelButtonTitle:@"Ok" otherButtonTitles:nil];
    }
    else
    {
        // 5
        NSString *decodedString = [[[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding] autorelease];
        // NSLog(@"%@",decodedString);
        jsonDictD = [decodedString JSONValue];
        NSLog(@"%@",jsonDictD);
        if (jsonDictD)
        {
            [AppHelper saveToUserDefaults:[jsonDictD objectForKey:@"email"] withKey:@"email"];
            [AppHelper saveToUserDefaults:[jsonDictD objectForKey:@"id"] withKey:@"facebook_id"];


            [userImage setImageWithURLRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:[[[jsonDictD objectForKey:@"picture"] objectForKey:@"data"] objectForKey:@"url"]]]
                             placeholderImage:[UIImage imageNamed:@"DefaultPic.png"] success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image)
             {

                 userImage.image=image;
                 dummyImg=image;
                 [dummyImg retain];

             }
            failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error)
             {

             }];

            self.firstNameTextField.text=[jsonDictD objectForKey:@"first_name"];
            self.lastNameTextField.text=[jsonDictD objectForKey:@"last_name"];
            self.emailTextField.text=[jsonDictD objectForKey:@"email"];

            self.dobTextField.text=[jsonDictD objectForKey:@"birthday"];

            if ([[jsonDictD objectForKey:@"gender"] isEqualToString:@"male"])
            {
                gender=@"Male";
            }
            else
            {
                gender=@"Female";
            }
            //  [[NSNotificationCenter defaultCenter] postNotificationName:@"Get FB" object:nil];
            dispatch_async(dispatch_get_main_queue(), ^{
                [self.tableView reloadData];
                [[DubitAppDelegate getAppDelegate] hideActivityViewer];


            });
        }
    }
}];

}

于 2013-07-23T20:01:24.887 に答える