2

iOSアプリで認証システムを作成しようとしています。これにより、ユーザーはログインでき、アカウントをまだ持っていない場合は登録できます。昨日、ログインシステムを完全に稼働させましたが、登録システム用にコードを設定すると、コードはサーバーにpingを送信しませんでした。次に、ログインシステムを再度テストしようとしましたが、コードはサーバーにpingを送信しません。

RegistrationTableViewControllerの関連コード(一部のセルにテキストフィールドを含むカスタムTVCです。たとえば、ビューを考えて新しいカレンダーイベントを作成します)。

- (IBAction)signUpButtonPressed { 
    // Get the values out of the text fields that the user has filled out.
    NSString *email = self.emailTextField.text;
    NSString *firstName = self.firstNameTextField.text;
    NSString *lastName = self.lastNameTextField.text;
    NSString *password = self.passwordTextField.text;
    // Assuming that sign-up could potentially take a noticeable amount of time, run the
    // process on a separate thread to avoid locking the UI.
    dispatch_queue_t signUpQueue = dispatch_queue_create("sign-up authenticator", NULL);
    dispatch_async(signUpQueue, ^{
        // self.brain refers to a SignUpBrain property. See the code for the class below.
        [self.brain signUpUsingEmail:email firstName:firstName lastName:lastName  
          andPassword:password];  
        dispatch_async(dispatch_get_main_queue(), ^{  
            [self performSegueWithIdentifier:@"ShowMainFromSignUp" sender:self];  
        });  
    });  
    dispatch_release(signUpQueue);  
}

SignUpBrainの関連コード:

- (void)signUpUsingEmail:(NSString *)email firstName:(NSString *)firstName
                lastName:(NSString *)lastName andPassword:(NSString *)password {
    self.email = email;
    self.firstName = firstName;
    self.lastName = lastName;
    self.password = password;

    // Handle sign-up web calls.
    NSMutableURLRequest *signUpRequest = [[NSMutableURLRequest alloc] initWithURL:[NSURL 
      URLWithString:@"URL GOES HERE"]]; // obviously there's an actual URL in real code
    NSString *postString = [NSString stringWithFormat:@"uname=%@&pw=%@&fname=%@&lname=%@", 
      email, password, firstName, lastName];
//NSLog(postString);
    [signUpRequest setHTTPMethod:@"POST"];
    [signUpRequest setHTTPBody:[postString dataUsingEncoding:NSUTF8StringEncoding]];
    NSURLConnection *signUpConnection = 
      [NSURLConnection connectionWithRequest:signUpRequest delegate:self];
    [signUpConnection start];

    // Store any user data.
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
    self.signUpResponse = data;
    NSError *error;
    NSDictionary *jsonLoginResults = [NSJSONSerialization JSONObjectWithData:data 
      options:0 error:&error];
    if (error) {
        NSLog(error.description);
    }
    NSLog(jsonLoginResults.description);

    // Return whether the user has successfully been registered.
    // If success is 1, then registration has been completed successfully. 0 if not.
    if ([jsonLoginResults objectForKey:@"status"]) {
        NSLog(@"Success!");
    }
}

また、UIWebViewでこれらの同じWeb呼び出しを使用するテストを作成し、正常に機能することにも注意してください。

何かを明確にする必要がある場合、またはコードをさらに含める必要がある場合は、お知らせください。前もって感謝します。

4

4 に答える 4

1

通常の状況では、ネットワーク操作を別のスレッドで実行する必要はありません。

避ける必要があるのは、メイン スレッドでの同期操作です。これにより、ネットワーク転送がビジーである間はイベントへの応答が停止するため、iOS はアプリケーションを強制終了します。

Apple の提案は、別のスレッドでの同期操作ではなく、メイン スレッドでの非同期操作を使用することです。

非同期操作を使用すると、ネットワーク自体がバックグラウンドで実行されます。これは Apple の専用スレッドと考えることができます。デリゲート メソッドは、iOS が適切であると判断したネットワークに追いつくために、メイン スレッドで正しい順序で呼び出されます。

NSURLConnection の使用

NSURLConnectionApple はURL Loading System Programming Guide のUsing NSURLConnectionに使用方法の例を含めています。これは短い記事で、簡単なコード例が満載です。これを読むには数分かかります。

ざっくり言うと以下のパターンです。

  • NSMutableData応答データ用に を保持します。
  • NSMutableDataのコンテンツインスタンスをクリアしますdidReceiveResponse。(リダイレクトされたときに複数のdidReceiveResponseイベントを受け取る場合がありますが、最後のイベントからのデータのみを使用する必要があります。)
  • から受け取ったデータを に追加しdidReceiveDataますNSMutableData。すぐに処理しようとしないでください。通常didReceiveData、1 回の転送で複数のイベントを受け取ります。
  • connectionDidFinishLoading、データが完成しました。ここで、あなたはそれで何かをすることができます。

すべてのデータを取得したら、それを別のスレッドに送信するか、(はるかに簡単に)dispatch_asyncメイン スレッドで実行されていないキューに送信できます。URL ローディング システム プログラミング ガイドのリスト 5「connectionDidFinishLoading の例: 実装」を参照してください。

ここでの考え方は、 でデータの蓄積を開始 (または再開) しdidReceiveResponse:、 でデータを追加しdidReceiveData:、実際に でデータを処理するというものですconnectionDidFinishLoading:

もちろん、別のスレッドで実行すること可能です。NSURLConnectionそのスレッドは、実行ループを使用してネットワークからデリゲート イベントを受信する必要があります。ただし、別のスレッドが必要な理由がない限り、非同期ネットワークを使用することが Apple の解決策です。

を使用NSURLConnectionするには、転送されたデータをクラス メンバーが蓄積する必要があります。つまり、複数の同時転送を行う場合は、より複雑なものが必要になります。おそらく を駆動するラッパー クラスNSURLConnectionであり、各応答を個別に保持します。このラッパー クラスを作成する頃にはAFHTTPRequestOperation、AFNetworking の一部である の単純なバージョンを作成している可能性があります。

一度に 1 つの転送しか行わないと仮定すると、コードは次のようになります。

- (void)signUpUsingEmail:(NSString *)email firstName:(NSString *)firstName
                lastName:(NSString *)lastName andPassword:(NSString *)password {

    // set up your connection here, but don't start it yet.

    receivedData = [[NSMutableData alloc] init]; // receivedData should be a class member
    [signUpConnection start];
}

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
    [receivedData setLength:0];
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
    [receivedData appendData:data];
}

- (void)connection:(NSURLConnection *)connection
  didFailWithError:(NSError *)error {
    // do something with error here
    // if you're not using ARC, release connection & receivedData here
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
    dispatch_async(someQueue, ^{
        // do something that takes a long time with receivedData here
        dispatch_async( dispatch_get_main_queue(), ^{
            // go back to your main screen here
        });
    });
    // if you're not using ARC, release connection & receivedData here
}

AFネットワーキングの使用

これらすべてを説明したので、別の方法を提案します。AFNetworkingを使用したほうがよい場合があります。

AFNetworking は、オープン ソースのサード パーティ ライブラリです。その最も基本的なクラスは でラップNSURLConnectionされますNSOperation(したがって、 に追加できるものNSOperationQueue)。AFNetworking は、私が説明したこれらのイベントを自動的に処理します。代わりに、完了ブロックを記述します。このブロックを取得すると、転送が成功または失敗したことになります。失敗した場合、エラーはAFHTTPRequestOperationインスタンスで利用できます。成功すると、AFHTTPRequestOperationインスタンスでデータを使用できます。

(注:AFHTTPRequestOperation実際には別のスレッドから接続を実行すると思います。しかし、それはよく書かれ、十分にテストされたコードです。これを行うことに「問題」はありません。実行するのが難しく、通常は不要です。しかし、ライブラリが実行する場合それはあなたのためです、なぜですか?)

AFNetworking は提供NSURLConnectionしない HTTP ロジックをいくつか提供します。AFNetworking では、 a を使用しAFHTTPRequestOperationて完了ブロックを設定するだけです。上記はすべて次のようになります。

HTTPOperation = [[AFHTTPRequestOperation alloc] initWithRequest: URLRequest];
HTTPOperation.completionBlock = ^{
    dispatch_async(someQueue, ^{
        // get possible error or content from HTTPOperation
    }
};
[HTTPOperation start];

過去に、私は NSURLConnection を直接使用して書きました。しかし最近は、AFNetworking をより頻繁に使用しています。他のいくつかのライブラリとは異なり、NSURLConnection と根本的に異なる形状ではありません。実際、これは NSOperation にラップされた NSURLConnection を使用しています (うまくいけば、Apple はどのリリースでも取得できるでしょう)。少なくとも検討する価値はあります。

于 2012-05-29T20:08:29.383 に答える
1

私は数年前にこの正確な問題についてブログ投稿を書いたので、少し古くなっているかもしれません: http://www.sortedbits.com/nsurlconnection-in-its-own-thread

NSURLConnection は実際には正しく起動しますが、デリゲート呼び出しは受信されないことを知っておくとよいでしょう。そこに NSRunLoop を配置すると、そのスレッドで接続が範囲外にならないようにします。

于 2012-05-25T23:06:45.813 に答える
0

Every thread has an associated runloop. NSURLConnection for its delegate methods to get fired requires runloop.

In your - (void)signUpUsingEmail:... method after [signUpConnection start]; schedule URL connection to run on that thread(created and managed by GCD) runloop like this -

[signUpConnection scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];

[[NSRunLoop currentRunLoop] run];
于 2012-05-25T23:39:57.607 に答える
0

NSURLConnection には、デフォルトではセカンダリ スレッドでは使用できない実行ループが必要です。セカンダリ スレッドで接続を作成する必要がある場合は、NSDefaultRunLoopMode で実行される実行ループを追加します。

NSURLConnection オブジェクトを作成する前に、次のコードを使用します。"finished" は BOOL タイプの iVar で、接続のロードが完了すると YES に更新されます。

    do {
        [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
    } while (!finished);

お役に立てれば。

于 2012-05-24T21:31:10.617 に答える