2016-05-27 2 views
0

версии Xcode: 7.2.1, IOS версии: 9.1+UIAlertController не показывает сразу

Я пытаюсь отобразить предупреждающее сообщение UIAlertController на IPad, который показывает «Загрузка ... Пожалуйста, подождите» сообщение без каких-либо на нем. Я представляю UIAlertController перед началом длительной операции, а затем после продолжительной операции я отклоняю UIAlertController. Однако, что происходит, UIAlertController НЕ появляется сразу. Он только вспыхивает кратковременно ПОСЛЕ завершения более длинной операции, а затем он отклоняется.

Ниже приводится общая структура кода:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 

    UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Loading" message:@"Please wait...\n\n\n" preferredStyle:UIAlertControllerStyleAlert]; 
    [self presentViewController:alert animated:YES completion:nil]; 

    /// Perform long operation here... 
    /// (Basically, a message is being sent to a server, a long operation happens on 
    /// the server, and then the server returns a response to the iPad client.) 

    [alert dismissViewControllerAnimated:YES completion:nil]; 
} 

Я попробовал несколько вариантов, как с помощью dispatch_async так, что предупреждающее сообщение может отображаться одновременно в то время длительной эксплуатации происходит:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 

    UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Loading Dataset" message:@"Please wait...\n\n\n" preferredStyle:UIAlertControllerStyleAlert]; 
    [self presentViewController:alert animated:YES completion:nil]; 

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{   

     /// Perform long operation here... 

     dispatch_async(dispatch_get_main_queue(), ^{ 

      [alert dismissViewControllerAnimated:YES completion:nil]; 
     }); 
    }); 
} 

Я пробовал использовать UIAlertView (который я знаю, устарел в iOS 8), как в одиночку, так и с отправкой, но это тоже не работает.

Я пробовал обернуть длинный код операции в сообщении performSelector, но безрезультатно.

В прошлом использование UIAlertView с dispatch_queue без проблем работало в этой ситуации.

Любая помощь приветствуется.

Edit:

одна интересная вещь, чтобы отметить: В коде dispatch_async, если добавить USleep (250000) перед вызовом длинного кода операции, около 80% времени, предупредительное сообщение UIAlertController Будет отображаться в правильное время: ПЕРЕД началом длительной операции. Однако это не в 100% случаев и не является устойчивым решением. Вызов спящего с меньшим числом не работает.

Обратите внимание, что для параметра DISPATCH_QUEUE_PRIORITY_DEFAULT, я также пытался: DISPATCH_QUEUE_PRIORITY_HIGH, DISPATCH_QUEUE_PRIORITY_LOW и DISPATCH_QUEUE_PRIORITY_BACKGROUND

И я попробовал следующее тоже:

dispatch_queue_t myQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_CONCURRENT); 

dispatch_async(myQueue, ^{ 
    /// Perform long operation here... 
    dispatch_async(dispatch_get_main_queue(), ^{ 
     [alert dismissViewControllerAnimated:YES completion:nil]; 
    }); 
}); 
+0

Вашего вторым вариантом является правильным, вы должны разместить больше коды о вашей длительной эксплуатации. Возможно, что вы блокируете основной поток где-то внутри длинной операции. Это вызовет именно эту проблему. – Sulthan

+0

@Sulthan Да, в длинном коде операции я использую TCP-сокеты для ** отправки ** и ** recv ** данных. Функция ** recv ** socket блокируется до тех пор, пока она не получит свои данные с сервера. – silverness

+0

Вы делаете это в фоновом потоке (во второй версии), так что это не должно быть проблемой. Я думаю, вы каким-то образом также блокируете основной поток. – Sulthan

ответ

0

В оригинальном посте я отметил в качестве ответа (31 мая), там было несколько случаев, когда сообщение AlertViewController просто вешают бы потому, что метод dismissViewController не дозвонились , (Возможно, какое-то состояние гонки в разных потоках ... Я не уверен.) Итак, что я, наконец, нашел надежно работать и, по-видимому, является более чистым решением, заключается в использовании комбинации блока завершения AlertViewController и вызова dispatch_after.

Подробнее о завершении вызова от iOS reference: «Обработчик завершения вызывается после вызова метода viewDidAppear: на представленном контроллере представления».

(This post была помощь.)

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 

    // Initialize the alert view controller. 
    UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Loading Dataset" message:@"Please wait...\n\n\n" preferredStyle:UIAlertControllerStyleAlert]; 

    // Present the alert view controller. 
    [self presentViewController:alert animated:YES completion:^{ 

     /// Perform long operation here... 

     dispatch_after(0, dispatch_get_main_queue(), ^{ 

      // Dismiss the alert message. 
      [loadAlertController dismissViewControllerAnimated:YES completion:nil]; 

      /// Execute rest of code INDSIDE the dispatch code block INSTEAD of after it... 
     }); 
    }]; 
} 
0

Попробуйте положить CFRunLoopWakeUp (CFRunLoopGetCurrent()) просто ниже, когда вы представляете контроллер предупреждения.

+0

Спасибо за предложение. Я просто попробовал это для обоих случаев (с отправкой и без отправки), но это не сработало ... оно проявляет такое же поведение. – silverness

+0

Я предложил этот ответ, потому что возможно, что вы не в основном потоке, поэтому есть задержка. –

0

В результате работа была сочетанием кода отправки и вызова CFRunLoopWakeUp (предложенный @Bhavuk Jain). То, что мне также нужно было сделать, - это переместить код, который был первоначально после блока отправки (который я не показывал в исходном сообщении), чтобы НАСТРОИТЬ блок отправки. Таким образом, следующее работает до сих пор:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 

    // Initialize and present the alert view controller. 
    UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Loading Dataset" message:@"Please wait...\n\n\n" preferredStyle:UIAlertControllerStyleAlert]; 
    [self presentViewController:alert animated:YES completion:nil]; 

    // Force wake up the run loop. 
    CFRunLoopWakeUp(CFRunLoopGetCurrent()); 

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{   

     /// Perform long operation here... 

     dispatch_async(dispatch_get_main_queue(), ^{ 

      [alert dismissViewControllerAnimated:YES completion:nil]; 

      /// Execute rest of code INDSIDE the dispatch code block INSTEAD of after it... 
     }); 
    }); 
}