VoiceOver before heavy processing in main thread - objective-c

I want to accomplish following effect:
User presses the button;
VoiceOver speaks aloud a "processing" sentence;
Performing some heavy processing.
Everything is being ran in main thread and I don't want GUI to be able to update in that time. For that, I'd like the method not to return before the end of heavy processing. I have following code:
UIAccessibilityPostNotification(UIAccessibilityAnnouncementNotification,
#"Processing");
heavyProcessing();
The problem is, that VoiceOver speaks the information after heavy processing has been completed.
How to make VoiceOver speak out the information "asynchronously", before method finishes and returns control to the main loop? If necessary, the heavy processing may be ran in another thread.

That would be because, if the main thread is doing heavy processing, it can't do anything else and that would include initiating voice over requests.
In fact, there are many things that happen on the main thread that mean that you never want to do lengthy processing on it. Your app can't, for instance, respond to notifications from the OS like low memory warnings. If that's the case, iOS might kill your app thinking it has hung.
What you need to do is run your heavy processing on a background thread - I recommend using NSOperationQueue - and disable the controls you don't want to work while it is happening.

Related

Update UI with progress during UI-intensive loop

I've got a long-running loop which involves a fair amount of UI functions. This loop therefore must be run on the main thread. However, I also want to display progress of this task, so this must also run on the main thread as displaying the current progress would involve updating the UI. I am really struggling to find a way of allowing the UI to update with current progress on the main thread when the main loop is also running on the main thread. What happens is that the UI is frozen during the loop and then updates to show that the process is finished when it's done.
This is not for a production app, it's for a personal project that will never be release. So it is of no concern that the UI is frozen from a UX perspective. If the solution involves putting the processing in the background then this refactoring is fine, but I'm not sure how to do it when a lot of the heavy lifting during this loop involves UI stuff too.
Isn't it funny how you sometimes come up with a solution just after posting the question?! The key seemed to be rather than using a for loop for the processing, instead putting the processing function inside a separate method and repeatedly calling it, passing the array of objects to process to it. Doing this, you can call the function using [self performSelector:withObject:afterDelay:]. Even if you provide a value of zero for the delay, it causes the method to be called on the next run loop. This means you can update the UI, process the next item, and repeat this process until the array of items is empty. Here's my completed solution. If anybody knows a better way I'd still love to hear it, but for now this is at least working!
Edit - I packaged this solution up into a class of its own to make it easier to manage, and put it on my Github. Maybe it will help somebody else out :)
Edit 2 - made the processing class more flexible by making it run loops instead of iterating through arrays. You can of course use it to iterate through an array yourself, as per the example in the readme. But if you're not working with an array, you can just run the loop runCount times and do whatever you need to do in the processingBlock.
https://github.com/mashers/BackgroundLoopProcessor

Objective-C and applescript -> Timeout events & threads

I am on macOSX (Sierra), not iOS, Objective-C, Xcode9.
I have an application with implemented applescript classes, XCode compiles them for me. Whenever i call an applescript method from within an *.m file (and from a background thread!) i dispatch_sync it to the main thread (as applescript needs to be executed in the main thread) - sync cause i need the result to continue.
I'd like to show you with a simple example:
Applescript:
on openFile_filePath(filePath)
try
tell application "Adobe InDesign CC 2018"
set myDoc to open (filePath as string)
return id of myDoc
end tell
end
return 0
end
Objective-C
// Method is running in a background thread
// appleScriptHelper is properly instantinated
__block NSInteger docID = 0;
NSString* someFile = #"/Users/user/Desktop/";
dispatch_sync(dispatch_get_main_queue(), ^{
docID = [self.appleScriptHelper openFile:someFile];
});
This runs smooth - as long as InDesign responds! Sometimes, InDesign freezes and then my whole app freezes cause it basically waits forever on the main thread.
What i tried:
I cannot use a timer cause the main thread is blocked anyways and i cant pass a "cancel" message - cause Applescript is busy anyways waiting for something never happen.
In addition it is not possible to work with "with timeout of x seconds" in applescript when compiled from XCode (just doesnt work as mentioned in other posts).
I tried it with NSOperations but as i need to dispatch to the mainThread... still the same issue.
So my question is: Is there any way i can STOP the whole dispatch_sync block after a time of x seconds? Or is there any other possibility to keep the app running and not being locked up forever through InDesign freeze?
Note: The implementation works fine - please don't recommend 'use NSApplescript' or 'use Scripting Bridge'.
Reasons: ScriptingBridge - it's almost impossible to create a working HEADER file for InDesign (it almost weights 15 MB and throws tons of compiler errors - i did fix that once with lot of manual work just to see it not working anymore for the next Version of InDesign). NSApplescript is fine as long as you have simple scripts which is not the case.
Any help appreciated
Were NSAppleScript sufficient for your needs, I'd say use NSUserAppleScriptTask which runs scripts out of process with async completion callbacks. And yes, as you say, Scripting Bridge is utterly unfit for non-trivial automation, especially any involving large complex crusty Carbon apps like Adobe's, so don't waste a second on that.
There is AppleEventBridge/SwiftAE, but with Apple shuffling off the whole AS/AE infrastructure to quietly die off, I don't promote or support those any more, so maxima caveat emptor. (I still use Python appscript for my own Adobe app automation,btw, and it continues to blow everything else out the water, but I won't be surprised if the whole industry eventually goes Windows as the only professional-oriented platform left.)
..
The problem with using AppleScript-ObjC* is that AppleScript component (aka interpreter) instances are not thread-safe: you can instantiate them on any thread you like, but you can only use them on that thread, not from others. ASOC doesn't let you control any of this stuff for yourself; neither does NSAppleScript. (OSAKit does, but it's as painful to use as NSAppleScript is.) So ASOC code is de facto limited to running on the main thread only.
If you're stuck with using ASOC, I think your best bet is to push that code out into a subprocess that your main process talks to asynchronously via XPC Services or whatever. That'll avoid blocking your main process's main event loop (which then blocks its GUI) while allowing ASOC to do its own thing independently.
p.s. Another problem with ASOC is that changes in 10.13's bridgesupport files have changed/broken how C APIs are mapped to AS, which can break existing ASOC-based scripts. (I've stopped recommending ASOC unless/until that's fixed.)

VB.NET Synchronization confusion

VB.NET, .NET 4
Hello all,
I have an application that controls an industrial system. It has a GUI which, once a process is started, principally displays the states of various attached devices. It basically works like this:
A System.Timers.Timer object is always running. At each Elapsed event, it polls the devices for their current values and invokes controls on the GUI, updating them with the new values.
A start button is clicked, a process time Stopwatch object is created and started (Labels on the GUI are now invoked and updated on the System.Timers.Timer's Elapsed event, in addition to the other work that is taken care of on this event)
A new thread is created which runs a Process() subroutine
Some Stopwatch objects are created and started (these Stopwatches are periodically restarted during the process via their Restart() method.
Some logic is executed on the new Stopwatchs' Elapsedmilliseconds properties to determine when to do things like write new setpoints to the devices, update the data log, etc...
Here's my problem: The program occasionally freezes. My ignorant efforts at tracking down the problem have led me to suspect that read/writes to the subset of devices that are RS-232 controlled are the culprits most of the time. However, I occasionally see other strange things upon program freeze, e.g., one of the time Labels whose Text property is determined by a Stopwatch's Elapsedmilliseconds property sometimes will show an impossible value (e.g., -50 hours or something).
For the RS-232 problems, I suspect something like a read event is being executed at the same time as a write event and this causes a freeze(?). I tried to prevent this by making sure that all communication with an RS-232 device is funneled through a Transmit() subroutine which has the following attribute:
Which, as far as my ignorance permits me to understand, should force one Transmit() execution to finish completely before another one can start. Perhaps another risk is the code getting blocked here if one Transmit() never finishes?
Regarding the Stopwatch trouble, I speculate that the problem is that the Timer is trying to update a GUI Label at the same time that the Stopwatch's Restart() method is being executed. I'm unsure if this could cause a problem. All I know is that this problem has only occurred at a point in the process when a Restart() call would be made.
I am wondering if I could use a SyncLock or something to lock a Stopwatch while the Label is being updated (or, conversely, while its being restarted)? Or, perhaps I should stop the Timer, restart the Stopwatch, and then start the timer again, like so?:
Timer.Stop
Stopwatch.Restart
Timer.Start
My trepidation regarding how to proceed is due to my complete lack of understanding of how .NET synchronization objects actually work. I've tried slapping a few SyncLocks in various places, but I really have no idea if they're implemented correctly or not. I'm wondering if, having provided all this context, someone really smart might be able to tell me how I'm stupid and how to do this right. I would really appreciate any input. If it would be useful to provide some code snippets, I'd be happy to, I just worry that everything's so convoluted that it would just detract from what I'm hoping is a conceptual question.
Thanks in advance!
Brian
I would consider a shift to a task scheduling framework instead of relying on manual manipulation of timers if your working on anything SCADA related. A simple starting point would be something similar to the hardcodet.Scheduling classes and you can move to something like the beast that is Quartz. Most of these types of frameworks will provide you with a way to pause and resume scheduled actions.
If I'm working with Modbus, I normally keep a local cache of the register values and make changes to any value fire a change event. This has the benefit of allowing you to implement things like refreshing values manually without interfering with your process scheduling and checking for deadband when evaluating your polled response. This happened to be the side effect of implementing a polled protocol to a subset of the OPC DA interface.

.NET CF 2.0: possible single-threaded reentrancy

A simple application is written in CF 2.0. It's single-threaded as far as I'm concerned.
Two parts of the application are of interest: an event handler that handles "Barcode scanned" event raised by a class that represents PDA's barcode scanner (provided by manufacturer), and an event handler for Windows.Forms.Timer that runs every 30 seconds.
Recently the application suffered from a bug the only possible reason for which, as I can see, is processing Barcode Scanned event right in the middle of Timer_Tick event. I was absolutely sure that this was not possible and that one of the events would wait in the queue until first one is handled completely. Windows.Forms.Timer page in MSDN also assures that it's a regular single-threaded timer. Code triggered by Barcode Scanned changes some pieces of the interface, that causes no exceptions, so I'm assuming it's single-threaded as well. No, we're not using DoEvents or such.
Can anybody tell me for sure that such reentrancy is not possible and I should look harder for other possible reasons, or vice versa, that they have suffered from the same problem?
The Windows.Forms timer is going to happen on the UI thread via a call to PostMessage. That is a guarantee. How the "barcode scanned" even comes in is completely up to the developer of the library that's giving you the event. You should certainly not assume that it's going to run in the same context as your timer unless you specifically force it to (via a call to Control.Invoke). Even with that I don't believe you can guaranteee a call order.
If you think re-entrancy might be a cause, the solution is relatively simply - use a Monitor in both handlers (the timer proc and the event) and lock on the same object. That will rule out the possibility that it's a reentrancy issue. If the problem goes away, you know the cause and already have a fix. If the problem persists then you know for certain that it's not reentrancy and you can focus elsewhere.
Pretty much every barcode scanning component i've worked with runs off a background thread, so i'd look at that more closely.

wxWidgets : non blocking copy to FTP

I want to copy a file to a FTP server using wxFTP, but I would like to do this without blocking the UI, and much better, while displaying a progress bar. Can I do this without extra thread?
I'm using wxLua, but I can adapt a solution written in any language as long as it uses a wxWidgets binding.
Try using wx.lib.delayedresult. It's available in wxPython, but maybe also it is in your wxWidgets library too. It creates separate worker thread and is called with a consumer function that is called once worker thread finishes his job. Quite useful thing.
See wxPython docs for details.
What's wrong with starting your own Thread for this?
You could check the streams canRead() method periodically (through a timer or in the event loop, maybe) and only read when it returns true, but it'll probably be a lot more complex than just starting a separate thread.