Nano Hash - криптовалюты, майнинг, программирование

Можно ли что-то обновить в пользовательском интерфейсе при выполнении синхронных вызовов или других операций?

В некоторых точках моего проекта мне нужно выполнить несколько синхронных вызовов веб-службы или прочитать данные из CoreData. Выполнение этих операций может занять пару секунд, поэтому я создал класс LoadingView, который является подклассом UIView, который имеет простое сообщение и UIActivityIndicatorView. Для обычных UIButton я просто [myLoadingView setHidden:NO] на событии Touch Down и [myLoadingView setHidden:YES] на событии Touch Up Inside. Все это работает именно так, как я хочу.

Проблема в том, что я не могу понять, как это сделать с помощью клавиши Return на клавиатуре. Из того, что я могу сказать, есть только 1 метод, который вызывается, когда пользователь касается клавиши Return (UITextFieldDelegate protocol textFieldShouldReturn:), и мне нужно два метода, чтобы моя техника [myLoadingView setHidden:NO] -> [myLoadingView setHidden:YES] работала, так как цель- C не обновляет экран до самого конца метода, в отличие от постоянного обновления экрана, как в других языках.

Как я могу сделать так, чтобы мой экран загрузки отображался, как только пользователь коснется клавиши Return, выполнит некоторые операции и скроет экран загрузки после выполнения операций?


ИЗМЕНИТЬ:

Я пробовал использовать NSNotificationCenter, но, кажется, столкнулся с той же проблемой. Например, если у меня есть метод UIButton Touch Up Inside:

- (void) btnClick:(id) sender
{
    [[NSNotificationCenter defaultCenter] postNotificationName:@"Show Loading" object:nil];

    // Do stuff that takes a long time here

    [[NSNotificationCenter defaultCenter] postNotificationName:@"Hide Loading" object:nil];
}

Где в моем LoadingView.m у меня есть:

- (id) init
{
    self = [super init];
    if (self)
    {
        // Do normal init stuff here

        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(showLoading) name:@"Show Loading" object:nil];
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(hideLoading) name:@"Hide Loading" object:nil];
    }
    return self;
}

- (void) showLoading
{
    // Do stuff to set up the loading screen 

    [self setHidden:NO];
}

- (void) hideLoading
{
    [self setHidden:YES];
}

При такой настройке, когда я нажимаю кнопку, я никогда не вижу экран загрузки. Когда я публикую уведомление, оно выполняется и сразу же меняет экран? Если да, значит, я делаю что-то не так, возможно, в своих // Do stuff частях. Если это не так, я не думаю, что NSNotificationCenter мне чем-то поможет =(.


РЕДАКТИРОВАТЬ 2:

Я настроил быстрый тестовый проект, и я подтвердил, что уведомления НЕ обновляют экран сразу. Код btnClick, который я разместил в моем последнем EDIT, ведет себя точно так же, как простое выполнение

- (void) btnClick:(id) sender
{
    [loadingView setHidden:NO];

    // Do stuff that takes a long time here

    [loadingView setHidden:YES];
}

Так что это подтверждает, что ничто из того, что зависит от NSNotificationCenter, мне не поможет.

Действительно, похоже, что нет поддержки смены экрана во время синхронной работы, что очень разочаровывает. У меня нет идей на данный момент.


  • Вместо того, чтобы привязывать логику отображения/скрытия к потенциально большому количеству событий пользовательского интерфейса, как насчет привязки логики отображения/скрытия к процессу, который этого требует. Когда процесс начнется, запустите уведомление, которое может наблюдать, скажем, делегат вашего приложения, который затем покажет/скроет индикатор загрузки. Таким образом, логика находится в одном месте. Тот же сценарий, когда ваш процесс завершен. 09.12.2013
  • Я думаю, что понимаю, куда вы идете, но на самом деле есть много разных процессов, которые будут показывать/скрывать экран загрузки. Так что на самом деле я думаю, что логика будет во многих местах, несмотря ни на что. 09.12.2013
  • Показать/скрыть будет в одном месте, но да, вам нужно опубликовать уведомление для каждого процесса, которому нужна эта функция, что-то вроде [[NSNotificationCenter defaultCenter] postNotificationName:PROCESS_DID_BEGIN object:nil]. Предположим, вы решили изменить имя вашего метода showHide. Для этого вам придется выполнять поиск/замену по всему приложению, иначе вы можете просто перейти к объекту, единственной обязанностью которого является управление отображением индикатора загрузки. 09.12.2013
  • Просто пища для размышлений, поскольку я довольно широко использую это в своем приложении (8 веб-сервисов и ~ 50 сервисных методов). Предположим, у вас есть фоновый процесс, например, какой-то механизм фонового обновления, для которого требуется индикатор загрузки... у вас не будет привязки к какому-либо конкретному элементу пользовательского интерфейса. 09.12.2013
  • @Jeremy: Да, я думал об этом еще немного, и чем больше я думаю об этом, тем больше я думаю, что мне следует просто использовать NSNotificationCenter. Я хотел бы выполнить все настройки NSNotificationCenter в init для моего LoadingView, а затем postNotification из контроллеров представления, над которыми я хочу показать/скрыть экран загрузки, правильно? 09.12.2013
  • Да, это один из способов сделать это. 09.12.2013
  • @Jeremy: у меня проблемы с NSNotificationCenter - пожалуйста, посмотрите правку моего OP. У вас есть какие-нибудь мысли? 09.12.2013
  • Во-первых, не используйте пробелы в имени уведомления. Во-вторых, поместите некоторую трассировку в свои методы show/hide, чтобы увидеть, вызывались ли они когда-либо. 19.12.2013
  • @WillJenkins: я проверил, как вы предложили, см. РЕДАКТИРОВАТЬ 2 в моем ОП. 19.12.2013

Ответы:


1

Вам нужен обратный вызов от любых процессов, которые вы вызываете, чтобы сообщить вам, что они завершены. Когда срабатывает обратный вызов, вы можете скрыть экран загрузки.

09.12.2013
  • Я не думаю, что мне приходилось настраивать эти обратные вызовы раньше. Это встроенные методы, которые мне нужно вызывать? Или вы говорите об использовании NSNotificationCenter? 09.12.2013
  • И если процессы, которые я запускаю, выполняются синхронно, я увижу свой экран загрузки, чтобы показать, а затем скрыть, или он просто останется скрытым? 19.12.2013
  • Возможно, возможно нет. Однако вам действительно не следует делать такие вещи, как вызовы веб-служб синхронно. 19.12.2013
  • Веб-службы, которым я звоню, должны получать обновления данных. Если пользователь попытается продолжить во время обновления, он будет использовать старые данные. В моей отрасли использование старых данных является большим запретом. Так что мне безопаснее делать обновления синхронно. Мои пользователи понимают, что им потребуется обновление, и они знают, что не смогут использовать мое приложение, пока оно обновляется. Мне просто нужно показать мой экран загрузки, чтобы они знали, когда происходят обновления, и скрыть его, чтобы они знали, когда это будет сделано. 19.12.2013
  • Обновления пользовательского интерфейса происходят в основном потоке. Если вы делаете другие вещи в основном потоке, который блокируется до его завершения, то, естественно, ваш пользовательский интерфейс не будет обновляться между ними. Вот почему используются асинхронные вызовы — чтобы ваш пользовательский интерфейс мог обновляться и реагировать тем временем. Если вам нужно предотвратить взаимодействие пользователей со старыми данными, вы должны управлять этим самостоятельно, а не заставлять приложение зависать до тех пор, пока ваши данные не появятся. 23.12.2013

  • 2

    Конечно, вы также можете использовать событие didEndOnExit текстового поля, которое срабатывает при нажатии клавиши возврата.

    Вы можете начать показывать представление индикатора активности в этом методе, и когда загрузка завершится, вы можете использовать некоторый обратный вызов (в случае метода веб-службы — NSURLConnectionDataDelegate Protocol: connectionDidFinishLoading), чтобы скрыть представление индикатора.

    09.12.2013
  • Я просматривал Документы Apple, и я не смог найти ничего похожего на connectionDidFinishLoading. Он также не завершается автоматически, когда я пытаюсь добавить его в свой код. Может, это обесценилось? И есть ли что-то, что вызывается, когда CoreData заканчивает сохранение/загрузку? 09.12.2013
  • Если вы используете NSURLConnection для доступа к веб-сервисам, используйте протокол NSURLConnectionDataDelegate и его метод: - (void)connectionDidFinishLoading:(NSURLConnection *)connection. См.: developer.apple.com/library/ios/documentation/Foundation/: чтобы узнать, когда данные сохраняются в основных данных, вы можете использовать NSManagedObjectContextDidSaveNotification, добавив наблюдателя через NSNotificationCenter для этого уведомления. 10.12.2013

  • 3

    В итоге я использовал Grand Central Dispatch, чтобы справиться с этим. Самый простой способ -

    - (void) doStuff
    {
        // Show wait on start
        [myLoadingView setHidden:NO];
    
        dispatch_queue_t queue = dispatch_queue_create("com.myDomain.myApp",null);
        dispatch_async(queue, ^{
            // Code to execute
            {
                //... Do my time consuming stuff here ...
                // For testing purposes, I'm using
                int i = 0;
                while (i < 1000000000)
                {
                    i++;
                }
            }
            dispatch_async(dispatch_get_main_queue(), ^{
                // Hide Wait Screen on End
                // ... also need to do any other UI stuff here ...
                [myLoadingView setHidden:YES];
            });
        });
    }
    

    К сожалению для меня, мой реальный time consuming stuff имеет некоторые изменения в графическом интерфейсе (например, отображение предупреждений, предварительное формирование переходов, изменение меток и т. д.). Вместо того, чтобы переписывать все это, чтобы попытаться извлечь все элементы графического интерфейса, я обнаружил, что, вложив все это в другой dispatch_async, я все еще могу получить экран ожидания, отображаемый во время выполнения операций, и все другие элементы графического интерфейса, которые выполняются. в time consuming stuff обновится, когда это будет сделано (после того, как экран ожидания исчезнет).

    - (void) doStuff
    {
        // Show wait on start
        [myLoadingView setHidden:NO];
    
        dispatch_queue_t queue = dispatch_queue_create("com.myDomain.myApp",null);
        dispatch_async(queue, ^{
            dispatch_async(dispatch_get_main_queue(), ^{
                // Double nesting the dispatches seems to allow me to do UI changes as part of 'Code to execute' below.
                // If I do not double nest like this, GUI behavior in "time consuming stuff" will be erratic
                dispatch_queue_t queue2 = dispatch_queue_create("com.myDomain.myApp",null);
                dispatch_async(queue2, ^{
                    dispatch_async(dispatch_get_main_queue(), ^{
    
                        // Code to execute
                        {
                            //... Do my time consuming stuff here - GUI changes will appear when all the code has finished running ...
                            // For testing purposes, I'm using
                            int i = 0;
                            while (i < 1000000000)
                            {
                                i++;
                            }
                        }
    
                        // Hide Wait Screen on End
                        [myLoadingView setHidden:YES];
                    });
                });
            });
        });
    }
    

    Обратите внимание, что если doStuff необходимо вернуть значение, вам, вероятно, потребуется немного изменить его, чтобы использовать «блок завершения», подробности в принятом ответе здесь.

    31.01.2014
    Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

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

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

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

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..