Accessibility Notification gets overridden - ios

i am working on a iOS application with accessibility support. At some point in my application flow, i present an alert view. After presenting the view, i want to focus on the view using UIAccessibilityPostNotification, however the notification seems to get overridden.
[alertView show];
UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification,alertView.somesubView);
However i do not see the effect of this notification. The accessibility focus goes to some other view object in the background.
However, when i use dispatch_after with 0 delay, it works
[alertView show];
dispatch_time_t delay = dispatch_time(DISPATCH_TIME_NOW,0 * NSEC_PER_SEC);
dispatch_after(delay,dispatch_get_main_queue(), ^void(){
UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification,alertView.somesubView);
});
Can someone explain what is the reason ?

You've stumbled upon the standard solution. It's likely that the user interface or accessibility hierarchies may not have updated, yet, to reflect the presence of the alert view. An async dispatch to the main queue ensures that all other enqueued tasks, including any updates to user interface or accessibility state, execute before the notification is posted.
That said, VoiceOver should focus alert views automatically. You might want to investigate what interfered with this behavior in the first place.

Related

Remove previously posted notification

Posting notifications from the NSNotificationCenter on the certain button click event Hence When I have rapid button events The notification is being called that many times leads to the many problems. I want to cancel the previous posted notification when rapid events happening. How to do with below code.
func buttonClick() {
// I want to cancel the previous Event here
NSNotificationCenter.defaultCenter().postNotificationName("Event", object: self)
}
UPDATE:
Let me explain clearly what I want actually I have one observer method when a button click is happened from that I want to post the some notifications to control some UI elements like changing the button image. The problem is When I hit the button rapidly observer getting called many times as well my notifications being posted on the same count hence UI is blinking I can't have control on the Observer on the button click event I have only control over the posted event from my side.
Any help much appreciated.
NSNotificationCenter.post() is synchronous. It does not return until all the observers have performed their actions. So there is no way to cancel it; there is no queue.
If you are generating a lot of notifications very close to each other (especially within the same run-loop cycle), you can coalesce them using NSNotificationQueue with enqueueNotification. Generally something like:
NSNotificationQueue.defaultQueue().enqueNotification(note, postingStyle: .whenIdle)
That said, if this is tied to a button click (a human interaction), then the notifications are likely very far apart in computer terms. Half a second is an eternity in computer terms. If that's the case, you're likely better-off controlling this first at the UI, by disabling the button until you're willing to accept another click (for example with button.enabled = false).
It is possible to write a wrapper that coalesces operations over any arbitrary period, but this is likely to be confusing in your case, because the user will be able to click something that the system will ignore. If that's still what you want, I'll see if I can find an example of a coalescing trampoline (I've written them in ObjC, but I don't have a Swift example on hand).

iOS Swift Briefly Display Info

I want to have some information drop down from the top of a view, stay on the screen for a second or two, and then go back up out of the view. I have search for displaying notifications and/or banners. All I get is either push notifications (which I don't need to use) or iAds banners.
I'm working on a barcode scanning app and I want to briefly show the value of the barcode shown without requiring the user to tap on anything. How can I accomplish this?
Don't use notifications and banners, because that might not work: the user can turn them off. In any case this is not a notification of anything, so it's a misuse of notifications.
Just do what you described, yourself: animate a view onto the screen, and then (in the animation's completion handler) use delayed performance to animate the view right back off the screen after a short delay.
You should use a view which manages its own state (INCOMING, STAY PUT, OUTGOING). This way you can reduce the memory footprint and many other bugs in the process. I coded something for a similar process. Check it out

When does [UIAlert show] actually happen?

I'm stepping through some code in lldb, and I come across [alert show]. I step across it, nothing happens, then I continue and the alert pops up, presumably triggered sometime later. Just for curiosity's sake, when does that show message actually get sent to the operating system? What's really going on when I step over [alert show]? The documentation doesn't address it.
UIKit and core animation changes are processed and applied as part of the main run loop. When you call [alert show] the appropriate view hierarchy changes, frame changes, animations etc. are queued up in the system. When you return from your code the runloop will process these as part of the core animation transaction internals and you will see the changes on screen.

UIAlertView animation freeze

I have in the past seen a UIAlertView freeze momentarily during its animation, but not have anything else onscreen freeze (such as when deleting apps from a device...the other apps keep on wiggling). In my app right now I've got a UIAlertView freezing for a moment partway through its animation, but the Time Profiler in Instruments doesn't show the kind of CPU usage that would freeze the UI, and I can see other things happening in the UI behind the alert. What could cause this?
Often this type of thing is caused by showing the alertView in the action method of some control. If this is your case, use a dispatch block that shows the UIAlert (which you can prepare in the action routine), and dispatch it async to the main queue.

iOS: Hiding sensitive information on the screen when app is backgrounded

When a foreground app gets backgrounded (e.g. Home button gets pressed), how can I change elements on the topmost view controller prior to when iOS takes a snapshot of it and starts the animation to show the next screen?
I ask because I'm writing an app requiring HIPAA compliance, and I am concerned that the snapshot that the OS takes in order to do this animation sometimes contains sensitive data which should not be visible even for a split second when the app gets foregrounded later.
I'm aware that view controllers have lifecycle methods such as viewWillDisappear which might be usable, but I have a lot of controllers and I'd rather just have something in my App Delegate to handle this (e.g. by adding an opaque full-screen UIImageView overlay) rather than having to write custom code for this in every last controller.
I tried putting overlay-generating code in applicationWillResignActive, and I've been digging with Apple's docs and Google, but it's not working. I suspect the screenshot gets taken before the app has a chance to update the screen.
Thanks!
Not sure about HIPAA's requirements about backgrounding and possibly leaving the user logged in for someone else to resume, but the safest sounds like it would be to add a key UIApplicationExitsOnSuspend with a boolean value of YES to info.plist.
That will prevent the app from backgrounding entirely, and restarts it (possibly triggering a login procedure) every time you go back to it.
Most (if not all) mobile banking applications I've tested do this for safety reasons.
I believe the answer is to not concern oneself with changing what's on the screen before the backgrounding animation begins, but to simply modify what's displayed on the screen once the app enters the background (i.e. inside of applicationDidEnterBackground: in your App Delegate.) This solved my problem.
My UIImageView overlay idea worked here, although I decided just to pop to the root view controller instead. Simpler that way. My root view doesn't have any sensitive info.
Here's what it looks like:
-(void)applicationDidEnterBackground:(UIApplication *)application {
UINavigationController *navigationController =
(UINavigationController *)self.window.rootViewController;
[navigationController popToRootViewControllerAnimated:NO];
...
}

Resources