I keep crashing when doing:
[NSWindow orderFront:nil]
From a thread I spawned in my app. Is working with UI elements from thread not possible like GTK+?
Edit:
oh goodness just found this:
https://stackoverflow.com/a/11900929/1828637
So apparently I cant use NSWindow from another thread, so objc is out, is it possible to do multi thread window stuff with CoreFoundation instead? I have to do from thread so Im looking for alternative way
You can only work with UI elements on the main thread.
I use GCD to ensure all UI activities are running on the correct thread:
dispatch_sync(dispatch_get_main_queue(), ^{
// Do your UI updates!
});
See why:
In Cocoa Touch, the UIApplication i.e. the instance of your application is attached to the main thread because this thread is created by UIApplicatioMain(), the entry point function of Cocoa Touch. It sets up main event loop, including the application’s run loop, and begins processing events. Application's main event loop receives all the UI events i.e. touch, gestures etc.
UI interaction always has to be done on the main thread.
You can simply dispatch the code in question with GCD on the main thread:
dispatch_async( dispatch_get_main_queue(), ^(void)
{
[NSWindow orderFront:nil];
});
Related
I'm a windows developer and I'm having a hard time understanding the right way to run code in the
NSApplication's main thread.
Most of my code is running in a cvdisplaylink thread (it's an opengl app)
THe problem is that I can't call things like NSOpenPanel from it - it crashes the app and warns about only running stuff like this from the main thread.
It's fine, but the main thread is completely opaque as far as I understand, and I can only make it do things with events. The NSApp sendAction method sounded promising - because I could explicitly specify which method to call. But it didn't 'send' any thing, it just called this method directly from the same thread.
Am I understanding this right? Do I have to push some sort of a custom event (perhaps NSEventTypeApplicationDefined) to the main thread queue for this to work properly?
And if so, how to I respond to custom events like that?
Like this:
dispatch_async(dispatch_get_main_queue(), ^{
// do whatever
});
If what you want to do is to call a method of an Obj C object, the old school Cocoa way (which still works) is to use performSelectorOnMainThread:withObject:waitUntilDone:
E.g. to hide a window by calling its "orderOut:" method you would do this.
[theWindow performSelectorOnMainThread:#selector(orderOut:)
withObject:nil
waitUntilDone:NO];
I have a notification which can be posted on a background thread. This notification eventually leads to calling setTitle:forSegmentAtIndex:, which is UISegmentedControl, part of the UIKit.
Should it be assumed that I need to wrap this setTitle:forSegmentAtIndex: call with a async call to main thread, or will some lower lying Cocoa code automatically dispatch anything like setTitle:forSegmentAtIndex: to the main thread?
Always dispatch code that modifies a UI control to the main queue. Always.
I have 2 windows in my cocoa app. Main window opens a sub window. On click of OK on the sub window, I invoke a deligate on main form which will tell that OK button is clicked on the sub window.
Now, I need to run a long running process on the main window "in the background" so that the window will not become unresponsive. I also have progress bar which should show progress of this long running process.
Please let me know, what is the best way to achieve this.
You should start with Apple's Concurrency Programming Guide.
Specially the section about NSOperationQueue.
You can use Grand Central Dispatch for this. First you create a dispatch queue which will contain operations you want to perform on another thread. Each operation is represented as a Objective-C block (closure).
First you get a queue to put the task you want to run on another thread.
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
Then you place a block representing the work you want to do on this queue:
dispatch_async(queue, ^{
// this happens on separate thread
NSImage *image = produceImageFromSomeReallySlowOperation()
dispatch_async(dispatch_get_main_queue(), ^{
// this happens on main thread
[myView setImage:image];
});
});
The dispatch_get_main_queue() function returns the queue which is used for operations on the main thread (where the GUI is executed). This means that [myView setImage:image] will be executed on the main thread. You can place your update of the progress bar here. Just dispatch on the main queue to update the progress at every point in your algorithm where it makes sense to do so.
All of this can also be performed with NSOperation which provides a higher level Objective-C interface to the same functionality. But using GCD directly is sometimes easier. It depends on what you want to do.
I haven't used GCD or much threading in my apps but I've run into a situation where I need to run a method or two off another thread. Once this method completes I need to call another method using the main thread from a callback. I've been searching around to see how to detect when a thread has finished the operation but still not too clear on the subject.
I created a test app and just used the viewDidLoad method for a quick example.
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
NSLog(#"viewDidLoad called");
sleep(5); // simulating a thread being tied up for 5 seconds
dispatch_async(dispatch_get_main_queue(), ^{
[self callbackMethod]; // method called after above thread has completed running
});
});
}
Will this example work for what I'm trying to do? When running the application it appears that the callback method is called after the sleep(5) finishes. Is this the proper way of handling this situation or am I way off course?
You're spot on; that's the standard pattern for getting off and on the main thread. See my answer here: https://stackoverflow.com/a/13080519/341994
And for example code from my book, structured in this very way:
https://github.com/mattneub/Programming-iOS-Book-Examples/blob/master/bk2ch25p868mandelbrotGCD/ch38p1106mandelbrotNoThreading/MyMandelbrotView.swift
In that example, look at how drawThatPuppy gets off the main thread to do the time-consuming calculations and then back on the main thread to do the drawing into the interface.
I have an app where I want to have an image animation while I am reading some info from a database and building object. I have used UIImageView and set up and array of images, but if I start the animation and then do my DB processing, the animation does not play.
Is there another way to start the animation, or for me to do processing during the animation?
Thanks
It sounds like you're doing your processing on the main thread, which is preventing your animations from running.
Animations run on the main thread, so to avoid blocking this thread processing should be scheduled on a different thread.
You can achieve this using blocks like so:
dispatch_queue_t queue;
queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
// Your processing to be performed on this thread.
});
Or on earlier iOS versions, like so:
[self performSelectorInBackground:#selector(yourProcessing) withObject:nil];
- (void)yourProcessing {
// Your processing to be performed on this thread.
}
I highly recommend a read through of the Threading Programming Guide, followed by watching the WWDC sessions covering Blocks and Grand Central Dispatch (WWDC 2009).
You can run your DB processing on the background thread after you begin the animation. This will allow the two to happen simultaneously.
Sounds like you’re trying to do your database processing on the main thread, which, yes, will block your UI so it can’t animate (and so the user can’t interact with anything). Take a look at the Concurrency Programming Guide.