NSURLConnection sendSynchronousRequest кажется висеть

Этот HTTP-вызов, кажется, висит, и я не понимаю, почему. Строка ведения журнала после вызова никогда не запускается.

Я почти наверняка делаю что-то очень глупое, но если кто-нибудь может понять, что это такое, я был бы благодарен. Насколько я вижу, мой код эквивалентен документам.

Кажется, что не имеет значения, какой URL я использую, и HTTP-запрос никогда не регистрируется сервером (если указано на нем).

NSURLRequest *req = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.google.com/"]];

NSURLResponse *res = nil;
NSError *err = nil;

NSLog(@"About to send req %@",req.URL);

NSData *data = [NSURLConnection sendSynchronousRequest:req returningResponse:&res error:&err];

NSLog(@"this never runs");

Любые идеи?

Обновление

Спасибо всем, кто выложил до сих пор. Все еще видя проблему. Немного подробнее:

  • Код тестируется на устройстве
  • Другие HTTP-вызовы работают нормально, поэтому, если это проблема сети, это нетривиальная функция
  • Код провалился за обычный таймаут. Я знаю, что он висит более 20 минут. Я убил его в тот момент, но я предполагаю, что он будет продолжать висеть.
  • В настоящее время я не использую делегат и не планирую, см. ниже.
  • В других местах приложения я использую sendAynchronousRequest, но в этом случае мне нужно передать возвращаемое значение (и я не в основном потоке), поэтому sendSynchronousRequest - единственный параметр, который я знаю.
  • В случае, если это имеет значение, контекст заключается в том, что я реализую протокол NSURLCache, в частности метод cachedResponseForRequest, для которого требуется вернуть NSCachedURLResponse

Ответ 1

Этот код работает в других контекстах, поэтому он ясно, что это происходит, потому что вызов выполняется из метода cachedResponseForRequest для NSURLCache. Запуск его в другом месте отлично работает.

Поскольку это предназначалось для включения прокси между вызовами AJAX во встроенном UIWebView и сервере (для того, чтобы не переписывать код подписи API-кода в JS), я работал вокруг него, используя класс Marcus Westin WebViewProxy, который работает с удовольствием.

Ответ 2

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

 dispatch_queue_t myQueue = dispatch_queue_create("myQueue", NULL);

    // execute a task on that queue asynchronously
    dispatch_async(myQueue, ^{
NSURLRequest *req = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.google.com/"]];

NSURLResponse *res = nil;
NSError *err = nil;

NSLog(@"About to send req %@",req.URL);

NSData *data = [NSURLConnection sendSynchronousRequest:req returningResponse:&res error:&err];

    });

Ответ 3

Добавить делегат <NSURLConnectionDataDelegate>

NSURL *url = [[NSURL alloc]initWithString:[NSString stringWithFormat:@"Your string here"];
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    NSURLConnection *connection = [NSURLConnection connectionWithRequest:request delegate:self];
    [connection start];//It will start delegates


-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
    [received_data setLength:0];//Set your data to 0 to clear your buffer 
}

-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{

    [received_data appendData:data];//Append the download data..
}

-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    //Use your downloaded data here
}

Этот метод более удобен для загрузки данных. Он не будет использовать основной поток, поэтому приложение не будет зависать. Надеюсь, это будет более полезно для вас.

Ответ 4

Когда ваш запрос удастся с ответом, ваш NSLog будет выполняться, потому что метод sendSynchronousRequest работает в основном потоке.

Ответ 5

Его метод a synchronous - то есть он работает в главном потоке . Поэтому ваше приложение будет зависать - и он будет ждать загрузки данных.

Чтобы предотвратить это: используйте метод sendAsynchronousRequest. Он будет запускать этот процесс в фоновом потоке и не будет нарушать ваше приложение или просто - не заставит его зависать.

Здесь, как использовать sendAsynchronousRequest:

NSURL *url = [NSURL URLWithString:@"YOUR_URL_HERE"];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];

[NSURLConnection sendAsynchronousRequest:urlRequest queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error)
{
    //the NSData in the completion handler is where your data is downloaded.
}];

Учитывая все обстоятельства, я думаю, что проблема существует из-за вашего объявления делегата. Поэтому объявите <NSURLConnectionDataDelegate> и объявите объект NSMutableData: myData и NSURLConnection: urlConnection как свойства. Теперь используйте это:

NSURL *url = [NSURL URLwithString : @"YOUR_URL_HERE"];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
*urlConnection = [NSURLConnection connectionWithRequest:urlRequest delegate:self];


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

-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{

    [myData appendData:data];
}

-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    //You can use the complete downloaded data - NSMutableData here.
}