У меня есть NSURLConnection (два из них), и они работают в неправильном порядке.
Вот мой метод:

- (void)loginToMistarWithPin:(NSString *)pin password:(NSString *)password {

    NSURL *url = [NSURL URLWithString:@"https://mistar.oakland.k12.mi.us/novi/StudentPortal/Home/Login"];

    //Create and send request
    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];

    [request setHTTPMethod:@"POST"];

    NSString *postString = [NSString stringWithFormat:@"Pin=%@&Password=%@",
                            [self percentEscapeString:pin],
                            [self percentEscapeString:password]];
    NSData * postBody = [postString dataUsingEncoding:NSUTF8StringEncoding];
    [request setHTTPBody:postBody];

    [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error)
     {
         // do whatever with the data...and errors
         if ([data length] > 0 && error == nil) {
             NSError *parseError;
             NSDictionary *responseJSON = [NSJSONSerialization JSONObjectWithData:data options:0 error:&parseError];
             if (responseJSON) {
                 // the response was JSON and we successfully decoded it

                 NSLog(@"Response was = %@", responseJSON);
             } else {
                 // the response was not JSON, so let's see what it was so we can diagnose the issue

                 NSString *loggedInPage = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
                 NSLog(@"Response was not JSON (from login), it was = %@", loggedInPage);
             }
         }
         else {
             NSLog(@"error: %@", error);
         }
     }];


    //Now redirect to assignments page

    NSURL *homeURL = [NSURL URLWithString:@"https://mistar.oakland.k12.mi.us/novi/StudentPortal/Home/PortalMainPage"];
    NSMutableURLRequest *requestHome = [[NSMutableURLRequest alloc] initWithURL:homeURL];
    [request setHTTPMethod:@"POST"];

    [NSURLConnection sendAsynchronousRequest:requestHome queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *homeResponse, NSData *homeData, NSError *homeError)
     {
         // do whatever with the data...and errors
         if ([homeData length] > 0 && homeError == nil) {
             NSError *parseError;
             NSDictionary *responseJSON = [NSJSONSerialization JSONObjectWithData:homeData options:0 error:&parseError];
             if (responseJSON) {
                 // the response was JSON and we successfully decoded it

                 NSLog(@"Response was = %@", responseJSON);
             } else {
                 // the response was not JSON, so let's see what it was so we can diagnose the issue

                 NSString *homePage = [[NSString alloc] initWithData:homeData encoding:NSUTF8StringEncoding];
                 NSLog(@"Response was not JSON (from home), it was = %@", homePage);
             }
         }
         else {
             NSLog(@"error: %@", homeError);
         }
     }];

}

- (NSString *)percentEscapeString:(NSString *)string
{
    NSString *result = CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault,
                                                                                 (CFStringRef)string,
                                                                                 (CFStringRef)@" ",
                                                                                 (CFStringRef)@":/?@!$&'()*+,;=",
                                                                                 kCFStringEncodingUTF8));
    return [result stringByReplacingOccurrencesOfString:@" " withString:@"+"];
}

Итак, два NSURLConnection добавляются к [NSOperationQueue mainQueue]. Мои результаты показывают, что второй NSURLConnection выполняется раньше первого. Поэтому он пытается перейти на страницу, где я загружаю данные до того, как я вхожу в систему, поэтому (очевидно) возвращает ошибку «Вы не вошли в систему». Как мне запланировать их по очереди?

1
AndrewSB 22 Мар 2014 в 08:26

2 ответа

Лучший ответ

Проблема, как я подозреваю, вы уже поняли, заключается в том, что вы выполняете асинхронные сетевые запросы (что хорошо; вы не хотите блокировать основную очередь), поэтому нет уверенности в том, в каком порядке они завершатся.

Самый быстрый и простой ответ - просто поместить вызов второго запроса внутри блока завершения первого, а не после него. Вы не хотите делать вторую, если первая все равно не удалась.

Чтобы ваш код не стал громоздким, отделите логин от запроса на главную страницу. И вы можете использовать шаблон блока завершения, который является общим для асинхронных методов. Вы добавляете параметр в loginToMistarWithPin, который указывает, что он должен делать после завершения запроса. У вас может быть один обработчик блока завершения для успеха и один для отказа:

- (void)loginToMistarWithPin:(NSString *)pin password:(NSString *)password success:(void (^)(void))successHandler failure:(void (^)(void))failureHandler {

    NSURL *url = [NSURL URLWithString:@"https://mistar.oakland.k12.mi.us/novi/StudentPortal/Home/Login"];

    //Create and send request
    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];

    [request setHTTPMethod:@"POST"];

    NSString *postString = [NSString stringWithFormat:@"Pin=%@&Password=%@",
                            [self percentEscapeString:pin],
                            [self percentEscapeString:password]];
    NSData * postBody = [postString dataUsingEncoding:NSUTF8StringEncoding];
    [request setHTTPBody:postBody];

    [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error)
     {
         // do whatever with the data...and errors
         if ([data length] > 0 && error == nil) {
             NSError *parseError;
             NSDictionary *responseJSON = [NSJSONSerialization JSONObjectWithData:data options:0 error:&parseError];
             if (responseJSON) {
                 // the response was JSON and we successfully decoded it

                 NSLog(@"Response was = %@", responseJSON);

                 // assuming you validated that everything was successful, call the success block

                 if (successHandler)
                     successHandler();
             } else {
                 // the response was not JSON, so let's see what it was so we can diagnose the issue

                 NSString *loggedInPage = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
                 NSLog(@"Response was not JSON (from login), it was = %@", loggedInPage);

                 if (failureHandler)
                     failureHandler();
             }
         }
         else {
             NSLog(@"error: %@", error);

             if (failureHandler)
                 failureHandler();
         }
     }];
}

- (void)requestMainPage {

    //Now redirect to assignments page

    NSURL *homeURL = [NSURL URLWithString:@"https://mistar.oakland.k12.mi.us/novi/StudentPortal/Home/PortalMainPage"];
    NSMutableURLRequest *requestHome = [[NSMutableURLRequest alloc] initWithURL:homeURL];
    [requestHome setHTTPMethod:@"GET"]; // this looks like GET request, not POST

    [NSURLConnection sendAsynchronousRequest:requestHome queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *homeResponse, NSData *homeData, NSError *homeError)
     {
         // do whatever with the data...and errors
         if ([homeData length] > 0 && homeError == nil) {
             NSError *parseError;
             NSDictionary *responseJSON = [NSJSONSerialization JSONObjectWithData:homeData options:0 error:&parseError];
             if (responseJSON) {
                 // the response was JSON and we successfully decoded it

                 NSLog(@"Response was = %@", responseJSON);
             } else {
                 // the response was not JSON, so let's see what it was so we can diagnose the issue

                 NSString *homePage = [[NSString alloc] initWithData:homeData encoding:NSUTF8StringEncoding];
                 NSLog(@"Response was not JSON (from home), it was = %@", homePage);
             }
         }
         else {
             NSLog(@"error: %@", homeError);
         }
     }];

}

Затем, когда вы захотите войти в систему, вы можете сделать что-то вроде:

[self loginToMistarWithPin:@"1234" password:@"pass" success:^{
    [self requestMainPage];
} failure:^{
    NSLog(@"login failed");
}];

Теперь измените эти параметры блока successHandler и failureHandler, чтобы они включали все данные, которые вам нужно передать, но, надеюсь, это иллюстрирует идею. Используйте короткие и сжатые методы и используйте параметры блока завершения, чтобы указать, что должен делать асинхронный метод, когда он будет выполнен.

1
Rob 22 Мар 2014 в 09:22
Это может работать, но не уверен. Как мне загрузить HTML-содержимое https://mistar.oakland.k12.mi.us/novi/StudentPortal/Home/PortalMainPage изнутри блока? Я попытался просто напечатать homeData из sendAsynchronousRequest, но это ничего мне не дало.
 – 
AndrewSB
22 Мар 2014 в 09:27
Мне очень жаль, я не реализовал ваши изменения (из-за моего идиотизма) это работает идеально, большое спасибо
 – 
AndrewSB
22 Мар 2014 в 09:34
Теперь я собираюсь добавить еще один блок успеха внутри этого блока успеха, будет ли это разумно или я должен сделать это как-то иначе? Потому что теперь мне нужно POST некоторые данные в PortalMainPage
 – 
AndrewSB
22 Мар 2014 в 09:35
Используйте этот шаблон блока завершения везде, где вы хотите, чтобы код, вызывающий ваш метод, мог указать блок кода, который должен вызываться после успешного (или неудачного) завершения асинхронного запроса. Итак, в итоге, не стесняйтесь использовать его везде, где это уместно.
 – 
Rob
22 Мар 2014 в 09:37

Можете ли вы проверить ссылку ниже. Речь идет о том, чтобы заставить одну операцию ждать другой.

NSOperation - Принуждение операции к динамическому ожиданию других

Надеюсь это поможет.

0
Community 23 Май 2017 в 15:05