开发者

Updating UI in Cocoa from another .m file

开发者 https://www.devze.com 2023-02-08 10:05 出处:网络
I have a GUI app that has a main thread and then I use NSOperation to run 2 other threads once the user clicks the Start button. Now one thread calculates a certain value and updates it. What I want t

I have a GUI app that has a main thread and then I use NSOperation to run 2 other threads once the user clicks the Start button. Now one thread calculates a certain value and updates it. What I want thread 2 to do is to pick this value up and update the UI. How do I get a IBOutlet Textfield value to get updated on the UI from this second thread ?

eg: main.m --- handles the UI and has code to start the 开发者_如何学C2 threads when the user hits the Start Button.

thread1.m -- calculates a particular value and keeps doing it until the user hits stop.

thread2.m - Need to use this thread to update the UI in main.m with the the value that thread1.m calculates.

I am unable to accomplish the thread2.m task and update the UI. My issue is that how do I define a IBOutlet and update it with a value from thread2/1 so that the main.m has access to this value and updates the UI. I have access to the actual variable in main.m and can print it out using NSLog. Its just that I am getting stuck on how to update the UI with this value. As I need to have theIBOutlet in main.m to tie it with the UILabel in the app. Any ideas guys ? Thanks.


Could you add pointers to your thread1.m and thread2.m files? Then set them with either a constructor method or some accessor methods?

If I understand the situation you described in your example, and assuming what you are calculating is an int (you can modify as you need):

Add an accessor to thread1.m

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

Then add to 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]];
}

Presuming your main.m is something like the following:

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
}

Then just take care of setting everything and calling the methods in your threads.


Source code files don't matter. You could have all of this stuff in one file (not that that would be a good idea) and the problem would be unchanged. What matters are the classes.

Classes are not simply bags of code; you design them, you name them, and you define each class's area of responsibility. A class and/or instances of it do certain things; you define what those things are and aren't.

When writing NSOperation subclasses, don't worry about the threads. There's no guarantee they even will run on separate threads. Each operation is simply a unit of work; you write an operation to do one thing, whatever that may be.

eg: main.m --- handles the UI and has code to start the 2 threads —

operations

— when the user hits the Start Button.

thread1.m -- calculates a particular value and keeps doing it until the user hits stop.

That's not one thing; that's an indefinite sequence of things.

thread2.m - Need to use this thread to update the UI in main.m with the the value that thread1.m calculates.

You should not touch the UI from (what may be) a secondary thread. See the Threading Programming Guide, especially the Thread Safety Summary.

I don't see why this should even be threaded at all. You can do all of this much more easily with an NSTimer running on the main thread.

If it would be inappropriate to “calculate… a particular value” on the main thread, you could make that an operation. Your response to the timer message will create an operation and add it to your computation queue. When the user hits stop, that action will go through on the main thread; invalidate the timer and wait for the queue to finish all of its remaining operations.

With either solution, “thread2.m” goes away entirely. Your update(s) to the UI will (and must) happen entirely on the main thread. With the latter solution, you don't even have to wait until you're done; you can update the UI with current progress information every time you receive the timer message.

0

精彩评论

暂无评论...
验证码 换一张
取 消