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 2 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.
Related
I am building a chat application using web-sockets and core-data.
Basically, whenever a message is received on the web-socket, the following happens:
check if the message exists by performing a core-data fetch using the id (indexed)
if 1. returns yes, update the message and perform a core-data save. if 1. returns no, create the message and perform a core-data save.
update table view, by updating or inserting new rows.
Here's my setup:
I have 2 default managed-object-contexts. MAIN (NSMainQueueConcurrencyType) and WRITER (NSPrivateQueueConcurrencyType). WRITER has a reference to the persisten store coordinator, MAIN does not, but WRITER is set as MAIN's parent.
TableView is connected to a NSResultsFetchController, connected to MAIN.
Fetches are all performed using temporary contexts ("performBlock:") that have MAIN as their parent. Writes look like this: Save temporary context, then save MAIN, then save WRITER.
Problem:
Because the updates come in via web-socket, in a busy chat-room, many updates happen in a short time. Syncs to fetch older messages can mean many messages coming in rapidly. And this locks up the UI.
I track the changes to the ui using fetched-results-controller's delegate like this:
// called on main thread
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller
{
NSLog(#"WILL CHANGE CONTENT");
[_tableView beginUpdates];
}
// called on main thread
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller
{
NSLog(#"DID CHANGE CONTENT");
[_tableView endUpdates];
}
and here's an example of what I see in the Log-file:
2014-07-14 18:46:20.630 AppName[4938:60b] DID CHANGE CONTENT
2014-07-14 18:46:22.334 AppName[4938:60b] WILL CHANGE CONTENT
That's almost 2 seconds per insert!
Is it simply a limitation I'm hitting here with tableviews? (I'm talking about 1000+ rows in some cases) But I can't imagine that's the case. UITableViews are super-optimized for that sort of operation.
Any obvious newbie-mistake I might be commiting?
This is not logical:
Writes look like this: Save temporary context, then save MAIN, then save WRITER.
If writer is a child context of main the changes are not persisted until the next save.
Ok I figured it out.
The problem is tableView:heightForRowAtIndexPath:. The fetches to calculate the height for the rows take time and each time tableView.endUpdates gets called, the UITableView needs the heights for ALL rows.
tableView:estimatedHeightForRowAtIndexPath: is a possible way to go (iOS7+), or I might opt for caching the heights myself (since the rows don't change) or just displaying fewer rows altog
I'd like to call a method
-(void) fooWithObject:(MyObject *)obj;
On a given time (NSDate instance)
without blocking the main thread.
What is the best way to go about this? I've seen NSTimer, performSelector and NSOperation but reading a bit of each just made me more confused.
Important:
Ability to pass in an object to the method I'm calling
A way to set time of execution
Non blocking
Don't need repeats
Cheers!
performSelector:withObject:afterDelay can be used for this. The delay is relative so you need to compute the difference between your desired date and the current time. Something like this (typed directly into answer on an iPad - E&OE):
- (void) fooWithObject:(MyObject *)obj onDate:(NSDate *)onDate
{
[self performSelector:#selector(fooWithObject:)
withObject:obj
afterDelay:MAX(0, [onDate timeIntervalSinceNow])
];
}
Note that MAX is used in case the passed in date is in the past - the delay will be 0 and the selector will therefore be performed "as soon as possible".
I am displaying information from a data model on a user interface. My current approach to doing so is by means of delegation as follows:
#protocol DataModelDelegate <NSObject>
- (void)updateUIFromDataModel;
#end
I am implementing the delegate method in my controller class as follows, using GCD to push the UI updating to the main thread:
- (void)updateUIFromDataModel {
dispatch_async(dispatch_get_main_queue(), ^{
// Code to update various UI controllers
// ...
// ...
});
}
What I am concerned about is that in some situations, this method can be called very frequently (~1000 times per second, each updating multiple UI objects), which to me feels very much like I am 'spamming' the main thread with commands.
Is this too much to be sending to the main thread? If so does anyone have any ideas on what would be the best way of approaching this?
I have looked into dispatch_apply, but that appears to be more useful when coalescing data, which is not what I am after - I really just want to skip updates if they are too frequent so only a sane amount of updates are sent to the main thread!
I was considering taking a different approach and implementing a timer instead to constantly poll the data, say every 10 ms, however since the data updating tends to be sporadic I feel that it would be wasteful to do so.
Combining both approaches, another option I have considered would be to wait for an update message and respond by setting the timer to poll the data at a set interval, and then disabling the timer if the data appears to have stopped changing. But would this be over-complicating the issue, and would the sane approach be to simply have a constant timer running?
edit: Added an answer below showing the adaptations using a dispatch source
One option is to use a Dispatch Source with type DISPATCH_SOURCE_TYPE_DATA_OR which lets you post events repeatedly and have libdispatch combine them together for you. When you have something to post, you use dispatch_source_merge_data to let it know there's something new to do. Multiple calls to dispatch_source_merge_data will be coalesced together if the target queue (in your case, the main queue) is busy.
I have been experimenting with dispatch sources and got it working as expected now - Here is how I have adapted my class implementation in case it is of use to anyone who comes across this question:
#implementation AppController {
#private
dispatch_source_t _gcdUpdateUI;
}
- (void)awakeFromNib {
// Added the following code to set up the dispatch source event handler:
_gcdUpdateUI = dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_ADD, 0, 0,
dispatch_get_main_queue());
dispatch_source_set_event_handler(_gcdUpdateUI, ^{
// For each UI element I want to update, pull data from model object:
// For testing purposes - print out a notification:
printf("Data Received. Messages Passed: %ld\n",
dispatch_source_get_data(_gcdUpdateUI));
});
dispatch_resume(_gcdUpdateUI);
}
And now in the delegate method I have removed the call to dispatch_async, and replaced it with the following:
- (void)updateUIFromDataModel {
dispatch_source_merge_data(_gcdUpdateUI, 1);
}
This is working absolutely fine for me. Now Even during the most intense data updating the UI stays perfectly responsive.
Although the printf() output was a very crude way of checking if the coalescing is working, a quick scrolling back up the console output showed me that the majority of the messages print outs had a value 1 (easily 98% of them), however there were the intermittent jumps to around 10-20, reaching a peak value of just over 100 coalesced messages around a time when the model was sending the most update messages.
Thanks again for the help!
If the app beach-balls under heavy load, then you've blocked the main thread for too long and you need to implement a coalescing strategy for UI updates. If the app remains responsive to clicks, and doesn't beach-ball, then you're fine.
Xcode's "thread list" pane shows English-like names for several special threads: com.apple.main-thread, com.apple.libdispatch-manager, com.dispatchfractal.opencl, com.dispatchfractal.opengl, com.apple.root.low-priority,... But for user-created threads that field is just blank.
Is there any way to set that "thread name" field programmatically from my application? For example, if I've got a thread devoted to network I/O, I'd like it to show up as "com.example.network-io" in the debugger; if I spawn five worker threads I'd like to be able to name them "worker A", "worker B", etc. Does Xcode pull its thread-names from some API that I could hook into myself? Maybe something like CFAssignDebuggerNameToCurrentThread? :)
Probably not exactly what you want but NSThread has setName: method that allows you to set thread's name, you can attach meaningful name to the thread so you'll get the following in debugger:
[[NSThread mainThread] setName:#"That is main thread!"];
Remember also that some apis (like grand central dispatch) operate with thread pools so you are not guaranteed on what thread your operation will be performed
Edit:
com.apple.main-thread, com.apple.libdispatch-manager etc are labels of corresponding dispatch queues. You can set label value when queue is created with dispatch_queue_create function and later get it from the queue using dispatch_queue_get_label function.
It seems there's no API to change label value of the existing dispatch queue and I would not advise to change labels of the system queues anyway.
If you can get a reference to the thread whose name you want to change, you can change it in the debugger console. Two ways to do that for the current thread:
(lldb) po [[NSThread currentThread] setName:#"foo"]
(lldb) expression (void)[(NSThread*)[NSThread currentThread] setName:#"foo"];
I'd guess you could do the same from a breakpoint that has an associated expression. If you have a method that you know will run in the thread that you're interested in, you could set a breakpoint containing one of the above commands and have it automatically continue after running the command. That'd have the effect of automatically setting the name of the thread every time you run the code, which might be handy for debugging.
I use the following code in Swift 5 to rename the current thread:
pthread_setname_np("myThreadName")
pesudo code for -[NSThread setName:]
- (void) setName:(NSString*)thname {
if (self == [NSThread currentThread])
{
pthread_setname_np([thname UTF8String]);
}
else { ... }
...
}
So, the easist way to set name is calling pthread_setname_np.
I'm attempting to implement custom termination behavior in a Cocoa application. Normally when my application exits gracefully, it performs final-runtime database cleanup and then exits. This occurs inside AppDelegate (delegate of NSApplication) whenever [NSApp terminate:aSender] is called:
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
{
// database cleanup...
return NSTerminateNow;
}
If an error occurs during runtime (e.g. the database file was deleted), I present the error to the user, and give them the option to Recover (put the file back and try again), or to Quit. If Quit is selected, I want to exit the app skipping database cleanup all-together since it's no longer possible. In essence, I'd like something like this:
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
{
BOOL gracefulTermination = ...;
if (gracefulTermination == YES)
{
// Database cleanup....
}
return NSTerminateNow;
}
The problem, of course, is getting the value for gracefulTermination.
Is there a way to pass a custom variable to NSApp when terminate: is called, such as an infoDict, and then receive it inside applicationShouldTerminate:?
If not, is there a better way to accomplish custom termination behavior?
As far as I know, when terminate: is called by some other object, this happens:
[NSApp terminate:self]; is called by foo (a.k.a. self).
NSApp sends its delegate: [aDelegate applicationShouldTerminate:self]; (self is NSApp, not foo).
aDelegate receives the message and executes applicationShouldTerminate: if implemented.
foo appears to disappear somewhere, and by the time aDelegate gets the message, it's gone for good and only NSApp appears as sender. This prevents me from passing an infoDict inside of foo, or just a plain infoDict, to aDelegate containing custom terminate: behavior.
I am aware that it's possible to exit without using [NSApp terminate:...] with something like exit(). Though from what I've read this is frowned down upon since it's not kosher for Cocoa. Plus it would also prevent any other cleanup operations from occurring inside applicationShouldTerminate:, operations which shouldn't be skipped even during a non-graceful exit.
The ideal solution would be to structure your app in such a way that the app delegate can tell whether it's allowed to terminate.
Assuming it isn't possible for your application delegate to access this information any other way (say, which object triggered termination affects whether it can happen), this seems like the simplest solution: Subclass NSApplication, give it a terminationInfo property and override terminate: to set this property and call super.