Обновление пользовательского интерфейса в Какао из другого файла .m - PullRequest
0 голосов
/ 05 февраля 2011

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

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

thread1.m - вычисляет конкретное значение и продолжает делать это, пока пользователь не нажмет стоп.

thread2.m - необходимо использовать этот поток для обновления пользовательского интерфейса в main.m значением, которое вычисляет thread1.m.

Я не могу выполнить задачу thread2.m и обновить пользовательский интерфейс. Моя проблема заключается в том, как определить IBOutlet и обновить его значением из thread2 / 1, чтобы main.m имел доступ к этому значению и обновлял пользовательский интерфейс. У меня есть доступ к фактической переменной в main.m и могу распечатать ее с помощью NSLog. Просто я застрял на том, как обновить пользовательский интерфейс с этим значением. Поскольку мне нужно иметь theIBOutlet в main.m, чтобы связать его с UILabel в приложении. Есть идеи, ребята? Спасибо.

Ответы [ 2 ]

0 голосов
/ 05 февраля 2011

Файлы исходного кода не имеют значения. Вы можете иметь все эти вещи в одном файле (не то, чтобы это было бы хорошей идеей), и проблема не изменится. Что важно, так это классы.

Классы - это не просто пакеты с кодом; Вы разрабатываете их, называете их и определяете зону ответственности каждого класса. Класс и / или его экземпляры делают определенные вещи; Вы определяете, что это за вещи, а какие нет.

При написании подклассов NSOperation не беспокойтесь о потоках. Там нет никакой гарантии, что они даже будут работать в отдельных потоках. Каждая операция - это просто единица работы; вы пишете операцию, чтобы сделать одну вещь, какой бы она ни была.

Например: main.m --- обрабатывает пользовательский интерфейс и имеет код для запуска 2 потоков -

Операция

- когда пользователь нажимает кнопку «Пуск».

thread1.m - вычисляет конкретное значение и продолжает делать это, пока пользователь не нажмет стоп.

Это не одно; это неопределенная последовательность вещей.

thread2.m - необходимо использовать этот поток для обновления пользовательского интерфейса в main.m значением, которое вычисляет thread1.m.

Не следует прикасаться к интерфейсу пользователя (что может быть) из вторичного потока. См. Руководство по программированию потоков , в особенности резюме по безопасности потоков.

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

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

При любом решении «thread2.m» полностью исчезает. Ваше обновление пользовательского интерфейса будет (и должно) происходить исключительно в главном потоке. С последним решением вам даже не нужно ждать, пока вы закончите; вы можете обновлять интерфейс с информацией о текущем прогрессе каждый раз, когда получаете сообщение таймера.

0 голосов
/ 05 февраля 2011

Не могли бы вы добавить указатели в ваши файлы thread1.m и thread2.m?Затем установите их либо с помощью метода конструктора, либо с помощью некоторых методов доступа?

Если я понимаю ситуацию, которую вы описали в своем примере, и предположите, что вы вычисляете int (вы можете изменить, как вам нужно):

Добавьте средство доступа к thread1.m

-(int)showCurrentCalcValue
{
     //Assume that you get calculatedValue from whereever else in your thread.
     return calculatedValue;
}

Затем добавьте к thread2.m

NSTextField *guiTextField;
Thread1 *thread1;

-(void) setThread: (Thread1 *aThread)
{
    self.thread1 = aThread;
}

-(void) setGuiTextField: (NSTextField *aTextField)
{
    self.guiTextField = aTextField;
}

-(void) updateGUI()
{
     [guiTextField setStringValue: [thread1 showCurrentCalcValue]];
}

Предположим, что ваш main.m выглядит примерно так:

IBOutlet NSTextField *outputDisplay

-(void) setUpThreads()
{
    Thread1 *thread1 = [[Thread1 alloc] init];
    Thread2 *thread2 = [[Thread2 alloc] init];

    [thread2 setGuiTextField: outputDisplay];
    [thread2 setThread: thread1];
    //Whatever else you need to do
}

Тогда просто позаботьтесь о настройке всего и вызове методов в ваших потоках.

...