> On Apr 25, 2017, at 4:37 PM, Charles Srstka <[email protected]> wrote:
> 
>> On Apr 25, 2017, at 9:51 AM, Dave <[email protected]> wrote:
>> 
>> Mac Project.
>> 
>> Hi All, 
>> 
>> I’m using performSelector: withObject: afterDelay: in order to postpone 
>> further processing until after the current method/run loop as expired, this 
>> puts the request at the End of the Queue, my question is, is there anyway of 
>> putting it at the head of the Queue so it gets processing before other 
>> requests?
>> 
>> All the Best
>> Dave
> 
> Consider using NSOperationQueue (OperationQueue if you’re using Swift) 
> instead of performSelector:withObject:afterDelay:, and have a look at the 
> queuePriority property on Operation/NSOperation. The following code:
> 
>> import Foundation
>> 
>> let op1 = BlockOperation {
>>      print("op1")
>> }
>> 
>> let op2 = BlockOperation {
>>      print("op2")
>> }
>> 
>> let quitOp = BlockOperation {
>>      exit(0)
>> }
>> 
>> quitOp.addDependency(op1)
>> quitOp.addDependency(op2)
>> 
>> op1.queuePriority = .veryLow
>> op2.queuePriority = .veryHigh
>> 
>> OperationQueue.main.addOperations([op1, op2, quitOp], waitUntilFinished: 
>> false)
>> 
>> RunLoop.main.run()
> 
> outputs:
> 
>> op2
>> op1
> 
> This shouldn’t be taken as a guarantee, but it does make it more likely that 
> your operation will be executed before others.
> 
> Charles

Addendum:

After doing some further tests, it appears that the queuePriority property only 
affects the ordering relative to other (NS)Operations, and not other things 
done by CF/NSRunLoop. I guess I’d had some sort of idealistic vision of the 
main run loop submitting its operations to the main operation queue and having 
everything work in harmony. In fact, it’s quite the opposite; all operations on 
the main queue are performed *after* operations scheduled via CFRunLoop or the 
medieval performSelector:etc:etc: methods, so using (NS)OperationQueue will 
actually do the opposite of what you want.

From a quick look at the disassembly for __CFRunLoopRun, it appears that 
CFRunLoop executes things in the following order: observers, blocks, sources 
(performSelector:etc:etc: is implemented using a CFRunLoop source), and 
finally, operations on the main dispatch and operation queues. So, unless you 
want to kludge together a fake observer and then trigger it, which I would not 
recommend, your best bet is probably to use CFRunLoopPerformBlock. 
Unfortunately, there’s no way that I can see to prioritize things submitted 
this way, so you’ll still run in series with any other operations submitted via 
CFRunLoopPerformBlock, but you should run ahead of most everything else. The 
test below bears this out:

> import Foundation
> 
> let group = DispatchGroup()
> 
> class Foo: NSObject {
>     @objc func bar() {
>         print("something called via performSelector")
>         group.leave()
>     }
> }
> 
> // Do this stuff in an operation after the run loop starts, because it seems 
> if the operations are
> // added before the run loop is running, the first one enqueued will run 
> first no matter what.
> OperationQueue.main.addOperation {
>     let op = BlockOperation {
>         print("something called via the main operation queue")
>         group.leave()
>     }
>     
>     op.queuePriority = .veryHigh
>     
>     group.enter()
>     OperationQueue.main.addOperation(op)
>     
>     group.enter()
>     DispatchQueue.main.async {
>         print("something called via the main dispatch queue")
>         group.leave()
>     }
>     
>     group.enter()
>     Foo().performSelector(onMainThread: #selector(Foo.bar), with: nil, 
> waitUntilDone: false)
>     
>     let cfRunLoop = RunLoop.main.getCFRunLoop()
>     
>     group.enter()
>     CFRunLoopPerformBlock(cfRunLoop, CFRunLoopMode.commonModes.rawValue) {
>         print("Our thingy got called!")
>         group.leave()
>     }
>     
>     CFRunLoopWakeUp(cfRunLoop)
>     
>     group.notify(queue: DispatchQueue.main) {
>         exit(0)
>     }
> }
> 
> RunLoop.main.run()

outputs:

> Our thingy got called!
> something called via performSelector
> something called via the main dispatch queue
> something called via the main operation queue

Unfortunately, I don’t think this is documented anywhere, so there’s no 
guarantee it won’t change in future versions of macOS, but for now, it works.

Charles

_______________________________________________

Cocoa-dev mailing list ([email protected])

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to [email protected]

Reply via email to