I have a view (a couple of them actually) with a standard search bar at the bottom. When the user touches the search bar, I need to move the search bar up so it's not hidden by the keyboard, then down again when the keyboard is dismissed.
I do this the same way as everybody else, by observing UIKeyboardWillShowNotification and UIKeyboardWillHideNotification. From these notifications, I get the height of the keyboard, and that tells me where to put the bottom edge of the search bar. It works perfectly, except for rare cases when the search bar doesn't animate, or doesn't animate far enough, and vanishes behind the keyboard. I have seen this a handful of times out of hundreds of tries with myself and my QA people testing on iPhones and iPods. Just once, I saw the search bar fly off the top of the screen as the keyboard came up. We've never seen any of this on the simulator, and we see it more often on the iPod than the iPhone. We are running iOS 4.x, mostly 4.3.3.
So I can think of two possibilities. One is that very occasionally UIKeyboardWillShowNotification is not sent and the other is that the data in the notification is wrong. The second one would explain the one case where the search bar flew off the top of the screen.
And then of course it is possible that my code is wrong in some very devious way; but the scenario is so simple -- enter the view and tap the search bar -- that I can't see how a bug in my code could cause these rare and intermittent failures.
If anyone can offer insight, I would be very grateful.
I finally discovered the answer to my question, and it's interesting. To cut to the chase, my search bar is animating into the wrong position; in some cases it's still behind the keyboard, and in others it's off the top of the screen. This is not caused by wrong data in the notification, but by a bug in accessing the height member of a CGSize or the y member of a CGPoint.
Specifically: in certain scenarios, when you write mySize.height, the generated code accesses mySize.width. If you are reading, you get the value of mySize.width; if you are writing, you clobber mySize.width. Similarly, myPoint.y actually accesses myPoint.x.
You may never see this problem. I only saw it on older iPod touch devices running iOS 4.2.1, and only in Release builds, and only when compiling with Apple LLVM Compiler 3.0, and then maybe only sometimes. But I reported it to Apple and they say it's a duplicate of a known bug (#10043857) that they are addressing. Connecting a few dots, I am guessing that it's somewhere in the compiler chain in Xcode 4.2.
The workaround is to take the address of the CGSize or CGPoint struct, then use pointer arithmetic to access the desired member. I wrote a set of little helper functions to do this, and I call them all over my app's code.
Related
This is so weird. I have been working on a series of iterations of the same application for almost 2 months, have not touched the code related to the view management in weeks, and this bug just appeared.
Basically I am at the root level view, i go to the last view in the stack by way of a "skip" type button. This page is used for settings. I then change some things (not related to the view hierarchy) and save, which takes me back to root. Then i try going to the first view in the stack.
Initially all of the textfields for the view are visible, but their uilabels are not. The view then slowly drifts to the right, revealing the same view with labels intact directly under it. I have never seen a bug like this before in over 2 years of iOS dev, so here I am.
The only code I have changed in the last week is related to web services and threading, nothing having to do with the view hierarchy.
If anyone has seen this bug before please help! Probably important as well, I have not seen this happen on the simulator, only on the actual device (iPad running 4.3.3)
Thanks!
Threading is the most likely culprit: making UI calls anywhere other than the main thread can cause any number of strange problems. Make sure anything you do to the UI, even a -popViewControllerAnimated:, is wrapped in a -performSelectorOnMainThread:withObject:waitUntilDone: or an appropriate dispatch_async(dispatch_get_main_queue(), ^{...}) call.
When my app resigns activation it covers the current view with a black view to prevent iOS from taking a screenshot of the potentially sensitive document being shown.
When pushing the app to background this works fine. The screenshot is taken AFTER didEnterBackground.
Using multitasking gestures to switch back shows the black view.
However with the new 4/5 finger gestures if you swipe left or right, first "resign activation" is triggered and then "did enter background" but the screenshot seems to be taken BEFORE these events.
How to prevent it in that case?
If I understand correctly, you're trying to avoid this problem:
http://software-security.sans.org/blog/2011/01/14/whats-in-your-ios-image-cache-backgrounding-snapshot/
And the issue is that the behavior doesn't match what Apple documents here:
http://developer.apple.com/library/ios/#documentation/iphone/conceptual/iphoneosprogrammingguide/CoreApplication/CoreApplication.html#//apple_ref/doc/uid/TP40007072-CH3-SW21
If that's true, then this definitely sounds like a bug -- but you do realize the gesture you mentioned is apparently a developer feature that's not available to the public (and under NDA)?
I'd do the following:
Sumbit a bug report - http://bugreport.apple.com/
Ask on the Apple Developer Forums (and include the bug number). People can speak freely there, and it's possible that an Apple developer will respond or at least notice your post (and hopefully prioritize the bug).
Finally, if you really want a response from Apple, then problems like this are a perfect use for your technical support incidents. You get 2 of these per year included with your ADC membership: http://developer.apple.com/support/resources/technical-support.html
Which "resign activation" ?
Have you tried UIApplication delegates method didResignActive or willResignActive ?
Or have you set a listener on a specific notification ?
I know this is kind of kludgy, but you could code your app to sense when more than 3 or 4 fingers are touching/moving and throw up the "shield screen", then remove the shield n second(s) after the fingers are removed in case the 3or4+ finger touch/move was indeed one of the app-switching gestures.
I'm trying to workaround a long-running bug in Apple's SDK here, but I can't see how to achieve it without huge amounts of code.
Here's the bug:
Create a view.
Put another view inside it, with an origin ANYTHING except (0,0).
Configure the subview to resize to fill
...then, at runtime:
4. Set the superview size to zero
5. Set the superview back to ANY non-zero size
BANG! Apple's SDK goes haywire, resets the origin of the subviews, loses all ability to tell up from down, etc. (seems like the programmer "Forgot" to include a variable to record what the spring/strut-size was before it went to 0).
I've heard this bug has existed in OS X for 5 years or so, and Apple still hasn't fixed it. What I would like is some way (any way!) of working around it, without re-writing Apple's entire springs/struts system and implementing it properly, without the bug. Unfortunately, I can't even find the original references to the OS X bug that someone showed me previously.
EDIT:
...I have a resizing "drawer" at the bottom of the screen that has to shrink to small height. The problem is subviews "collapsing" all down to origin 0 (amongst other things) at the drop of a hat (technically: they're reducing their origin.height, but not re-increasing it).
The best solution I have found is to limit your minimum window size so that none of your views can ever hit zero size.
EDIT: an hour later, the collapsing behaviour has returned, without me touching the source files. I'll use source-control to double-check, but I believe all that happened is I added other files to a different part of the view-hierarchy and re-built. Argh!
(what follows SEEMED to work, but is now failing again, in the same way)
Hmm. So, I had two UIVC's on one screen. Refactoring so that I only had one made the resizing bug vanish. It seems to be a bug in the UIVC layout code.
NB: I had the idea this might be a problem because I know Apple currently advises you to only have one UIVC on screen at once with iPhone, even though this means you have to ignore their MVC architecture for complex apps. So, technically, they warn you away from this. But, at the same time, I'm now unable to use the MVC stuff for this code.
The following worked (for my current example - may not be universal!).
HOW:
If you're adding any UITableViewController instances ... give up. You'll have to re-implement that class yourself
Find my subviews that were in UIVC instances, and change the extended class in the UIVC header from "UIViewController" to "NSObject"
Move all code from viewDidLoad to init (remembering that "init" has special rules about first few lines etc)
Replace the instantiation of that UIVC from "[[vc alloc] initWithNibName:nil bundle:nil]" with a plain "[[vc alloc] init]"
Another potential workaround (that works in my current situation):
The only View I have right now that MUST have a non-zero origin and MUST resize-to-fit is a UITableView.
Apple has a special feature of letting you put any view as a "table-header".
So ... I've taken all my other components, stuck them in a large view, and made that the table-header view.
The downside is that they now scroll off the top when you scroll the table, but it allows me to give the table a zero-origin, working around the SDK bug.
When I've learned that I have to write some code to make the iphone keyboard go away. I was quite surprised. I was surprised even more when it become apperent that it is just the top of the iceberg.
What are the expected UI behaviors that aren't provided by system OOTB?
Is the list below complete?
The expected UI behaviors:
Focusing next text field when [done] is hit
Hiding the keyboard when background is hit
Using Touch Up Inside to fire a button action. (To give user opportunity to change his/her mind)
Supporting the screen rotation.
Some of that is silly, but some of it has uses as well.
Focusing next text field when [done] is hit
Which field is "next"? If you have a large form with fields both next to and above/below each other, next might not be so obvious. Even if they are in some linear layout, the iPhone would have to work to figure out which one is next. Do you want to wrap around at the end of the form, or dismiss the keyboard, or submit the form?
Hiding the keyboard when background is hit
I mostly agree with you here, though there are a few cases where this is useless. For example, adding a new phone number in the contact app.
Using Touch Up Inside to fire a button action
This one I really don't get. I can only guess that it's designed to allow you to use buttons instead of the touchesBegan/Moved/Ended methods. I guess it could be useful, but I've never used anything but Touch Up Inside.
Supporting the screen rotation
Many apps just don't work in any other orientation, such as games. If you want to use rotation, you only have to add two lines of code assuming you've done your layout well.
I hope this helps explain some of the strangeness. Aside from the keyboard dismissal, I've never really found anything too annoying. The one thing I wish they supported was using the highlight state of UIButtons for the set state. It would be a quick and easy toggle button, but I've taken to screenshotting a highlighted button and using that for the background image of a selected button.
Want a rounded rectangular button that isn't white? Since that one uses a background image, you can't just click something somewhere that makes it the color of your choice. You have to create your own image or you could even use CSS (WTF!?) to do it.
Unfortunately, the iPhone SDK lacks a lot of helpful things one would think would just be there. However, many people have taken the time to write wrappers for many of these kinds of things to help facilitate development - a quick google search into the functionality you are expecting may turn up a lot of useful answers!
For example, you could make the keyboard go away when you tap outside of it by creating a new view when it appears, and placing that view behind any user-interactable views on the screen. When that new view is tapped, it will become first responder and cause the keyboard to slide away (because the UITextField is no longer first responder).
Such a thing could be easily implemented as a drop-in fix for pretty much anything you'd need it for with very little code.
Still should have been included in the SDK in the first place, though!
I have an app with a UITextField, amongst other things. When the user first taps on the text field, there is a noticeable delay before the virtual keyboard appears. On a 3GS it isn't too obvious, but on an older iPhone the delay can be around 1 second. After that the keyboard always pops up instantly. The delay is only the first time the keyboard pops up after app startup.
It looks like the initial UIKeyboard instantiation takes some time (quite a bit...) but is kept around after that.
I found very little information about this, which surprised me. However I did find this write up of the issue along with a hack-around solution.
http://blog.weareuproar.com/preloading-the-uikeyboard
My question is: is this hack around the only available solution? Is there a way to signal the framework (e.g. via info plist?) to instantiate the keyboard on startup?
No, there is no other (documented) way to do that. And even Apple's built-in apps (such as Maps) suffer from the same problem. You can either go with the hack you linked to or follow Apple's advice to not load stuff in advance before you really need it. By the way, this isn't much of an issue anymore with the iPhone 3Gs and the new iPod touch. The newer and faster devices load the keyboard almost instantly.