I have a Cocoa app which launches a new NSThread (Thread A) from within applicationDidFinishLaunching.
Thread A successfully creates an RFCOMM connection then spawns another NSThread (Thread B), passing the established IOBluetoothRFCOMMChannel to Thread B.
Thread B creates a IOBluetoothRFCOMMChannelDelegate and calls setDelegate on IOBluetoothRFCOMMChannel with it and then runs its current NSRunLoop.
Thread A then waits for Thread B to signal a sync object.
The intent is that, when data arrives, Thread B's NSRunLoop will execute the delegate which copies the received data and signals Thread A to read it.
However, the delegate never gets called because Thread B's NSRunLoop has no input sources.
I imagined that setDelegate would create an input source on it.
The only way I can get the delegate called is if I have Thread A wait on its own NSRunLoop instead of wait on the sync object. In that case, the delegate gets executed.
But that arrangement will not work for me. Eventually, my code will just be a library that exposes a C API that is a standard and is only suitable as a procedurally flowing set of functions. Thread A will be someone else's Thread (maybe main maybe not) and will call into my library in a procedural way.
1) I thought that the thread/runloop which registered for a delegate callback (Thread B) was the one that would get the input source and execute the callback in its runloop. But Thread A's NSRunLoop gets the input source instead, Why? What's the expected relationship between these things?
2) How can I get Thread B to get the input source and be the thread that executes the delegates?
Thanks for any and all help.
My Thread B is below:
#implementation CBaiHardwareBluetoothEventThread
- (void) runEventThread: (IOBluetoothObjectID)deviceID
{
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
NSRunLoop* myRunLoop = [NSRunLoop currentRunLoop];
CallbackDelegate* cd = [[CallbackDelegate alloc] init];
IOBluetoothRFCOMMChannel* myOBJCChannel = [IOBluetoothRFCOMMChannel withObjectID:deviceID];
[myOBJCChannel setDelegate:cd];
do{
[myRunLoop runUntilDate:[NSDate distantFuture]];
cout << __FUNCTION__ << " this should not be returning but it is ???" << endl;
usleep(1000000);//avoid the unintentional hard loop that happens
}while(1); //forever for now
[pool release];
}
#end
IOBluetooth and threading is messy. You'll have to work this stuff out by trial and error. If it seems that the callbacks happen on the thread that opened the connection, then you'll have to open the connection on the thread where you need the callbacks. Also, this behavior often changes between OS releases...
Related
In a Cocoa application, running code like this:
NSDate* date = [NSDate dateWithTimeIntervalSinceNow:30.0];
while (date.timeIntervalSinceNow > 0) {
[NSRunLoop.currentRunLoop runMode:NSDefaultRunLoopMode beforeDate:date];
}
on the main thread appears to cause the main thread to hang for 30 seconds. I find this surprising because I would have thought the code would basically act as a message pump and allow for user interface events to actually be processed.
What explanations can people provide for why this causes the main thread to hang?
The main Cocoa application event loop is built on top of a run loop, but it's not just a run loop input source.
If you want a message pump, you should use the -nextEventMatchingMask:... and -sendEvent: methods of NSApplication or NSWindow.
But, what are you really trying to achieve? Why are you trying to run the event loop for 30 seconds? Can you achieve what you want with a timer or dispatch_after()?
I have an application in which I am repetitively calling a method in background. I implemented this by following below steps:
created a background thread,
called the appropriate method on the created thread,
called sleep method on the thread, and
again called the previously invoked method.
Below is the code which I used:
- (void) applicationDidFinishLaunching:(NSNotification *)notification
[NSApplication detachDrawingThread:#selector(refreshUserIdPassword) toTarget:self withObject:nil];
}
-(void)refreshUserIdPassword
{
[self getAllUserIdsPasswordsContinousely];
[NSThread sleepForTimeInterval:180];
[self refreshUserIdPassword];
}
I have read that NSThread is not the best way to perform background task, and there are other classes provided in cocoa, such as - NSOperationQueue and GCD, which should be preferred over NSThread to perform an asynchronous task. So I am trying to implement the above specified functionality using the alternative classes.
Problem is - though I am able to perform an asynchronous task using
these classes, I am unable to perform a repetitive task (as in my
case) using these classes.
Can someone throw some light on this and guide me towards the correct direction?
I think you'll get a stack overflow (no pun intended) using the code you've posted. -refreshUserIdPassword recurses infinitely...
How about using GCD?
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
// Insert code here to initialize your application
dispatch_source_t timerSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0));
dispatch_source_set_timer(timerSource, dispatch_time(DISPATCH_TIME_NOW, 0), 180*NSEC_PER_SEC, 10*NSEC_PER_SEC);
dispatch_source_set_event_handler(timerSource, ^{
[self getAllUserIdsPasswordsContinuously];
});
dispatch_resume(timerSource);
self.timer = timerSource;
}
You're looking in the wrong place. As you say, NSOperationQueue isn't suited for this type of task. NSTimer is Cocoa's solution to this problem.
As the question also has a grand-central-dispatch tag:
If you need to run something in the background based on a regular interval, you could also use a dispatch_source timer.
Apple provides a very extensive example in the Concurrency Programing Guide.
If you don't need a background thread, you could use NSTimer (as paulbailey mentioned) or even more simple:
NSObject's performSelector:withObject:afterDelay:
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.
I am a bit uncertain on how to do this:
I start a "worker-thread" that runs for the duration of my apps "life".
[NSThread detachNewThreadSelector:#selector(updateModel) toTarget:self withObject:nil];
then
- (void) updateModel {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
BackgroundUpdate *update = [[BackgroundUpdate alloc] initWithTimerInterval:5];
[[NSRunLoop currentRunLoop] run]; //keeps it going 'forever'
[update release];
[pool release];
}
Now the thread "wakes" up every 5 seconds(initWithTimerInterval) to see if
there are any tasks it can do. All the tasks in the BackGroundUpdate Class are only time dependent for now. I would like to have a few that were "event dependent". e.g. I would like to call the Background Object from my main thread and tell it to "speedUp", "slowDown", "reset" or any method on the object.
To do this I guess I need something like performSelectorOnThread but how to get a reference to the NSthread and the Background Object?
Direct answer: Instead of +[NSThread detachNewThreadSelector:toTarget:withObject:], use [[NSThread alloc] initWithTarget:selector:object:]. Don't forget to call -start!
Other thoughts:
Consider using NSOperation/NSOperationQueue instead. Easier and more efficient for most worker thread uses.
Consider whether you really need to do that periodic check on a background thread. Could you just do it on the main run loop, and then throw off work onto other threads as needed? Threads aren't free.
Consider whether polling is the best implementation, too. Look into NSCondition and/or NSConditionLock for more efficient ways to wake up threads when something happens (like adding work to a queue), no polling necessary.
I want to create a separate thread that runs its own window. Frankly, the documentation does not make sense to me.
So I create an NSThread with a main function. I start the thread, create an NSAutoreleasePool, and run the run loop:
// Global:
BOOL shouldKeepRunning = YES;
- (void)threadMain {
NSAutoreleasePool *pool = [NSAutoreleasePool new];
// Load a nib file, set up its controllers etc.
while (shouldKeepRunning) {
NSAutoreleasePool *loopPool = [NSAutoreleasePool new];
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate distantFuture]];
[loopPool drain];
}
[pool drain];
}
But since there is no registered port or observer, runUntilDate: exits immediately and CPU utilization goes to 100%.
All thread communication is handled by calls to performSelector:onThread:withObject:waitUntilDone:. Clearly, I am not using the API correctly. So, what am I doing wrong?
Much of AppKit is not thread-safe and will not work properly (1) when manipulated outside the main thread. You will find only pain and misery trying to ignore this fact.
What are you really trying to do that requires a different thread for this window? Are you merely trying to keep a responsive UI? If so, there're much better ways of doing it. See NSOperation / NSOperationQueue (where "units of work" and "queues" are the focus, not "this window shall run on this thread, etc.").
I'd recommend restating your question with your specific goal detailed clearly.
(1) For some classes, it takes a lot of careful work. For others, they are quite firmly off limits.