EDIT: Prefixed the question with "Method Swizzle Crash" to help others find the bug.
For each key pressed in the Vietnamese keyboard on the simulator or any device running iOS 4 or higher, the following message prints to the console and no character is sent to the first responder:
Can't find tr开发者_如何学JAVAansliterator file: vi_TelexTransliterator
utrans_transUChars error U_ILLEGAL_ARGUMENT_ERROR
There are no instances of these strings or substrings in my server or client code. This is coming from the API.
Simulators and devices running iOS 4 will crash consistently on the second key press. There is no crash on iOS 5. The error at the top of the call stack looks like this:
*** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[NSCFString substringToIndex:]: Range or index out of bounds'
The call stacks looks like this:
Foundation -[NSString substringToIndex:]
TextInput -[TIKeyboardInputManagerZephyr internalIndexToExternal:]
TextInput -[TIKeyboardInputManagerZephyr inputCount]
UIKit -[UIKeyboardImpl addInputString:fromVariantKey:]
UIKit -[UIKeyboardImpl handleStringInput:fromVariantKey:]
UIKit -[UIKeyboardImpl handleKeyEvent:]
UIKit -[UIApplication _handleKeyEvent:]
UIKit -[UIResponder(Internal) _handleKeyEvent:]
UIKit -[UIResponder(Internal) _handleKeyEvent:]
UIKit -[UIResponder(Internal) _handleKeyEvent:]
UIKit -[UIResponder(Internal) _handleKeyEvent:]
UIKit -[UIResponder(Internal) _handleKeyEvent:]
UIKit -[UIResponder(Internal) _handleKeyEvent:]
UIKit -[UIResponder(Internal) _handleKeyEvent:]
UIKit -[UIResponder(Internal) _handleKeyEvent:]
UIKit -[UIResponder(Internal) _handleKeyEvent:]
UIKit -[UIResponder(Internal) _handleKeyEvent:]
UIKit -[UIApplication handleKeyEvent:]
UIKit -[UIKeyboardLayoutStar sendStringAction:forKey:]
UIKit -[UIKeyboardLayoutStar touchUp:]
UIKit -[UIKeyboardLayout touchesEnded:withEvent:]
UIKit -[UIWindow _sendTouchesForEvent:]
UIKit -[UIWindow sendEvent:]
UIKit -[UIApplication sendEvent:]
UIKit _UIApplicationHandleEvent
GraphicsServices PurpleEventCallback
CoreFoundation __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__
CoreFoundation __CFRunLoopDoSource1
CoreFoundation __CFRunLoopRun
CoreFoundation CFRunLoopRunSpecific
CoreFoundation CFRunLoopRunInMode
GraphicsServices GSEventRunModal
GraphicsServices GSEventRun
UIKit -[UIApplication _run]
UIKit UIApplicationMain
APP main (main.m:XXX)
I've tried this keyboard in a variety of locations throughout the application, including on a security screen before the main view is loaded and with all of our input handling methods commented out in its delegate. The failure is consistent. When the delegate methods are implemented and I step through textField:shouldChangeCharactersInRange:replacementString:, the string received is valid.
Everything seems to indicate that this is an Apple problem, but I'm finding no other reports of the issue online. My gut says it's something in my code. Can anyone lend a hint?
The information in this answer will be most useful to those experiencing similar issues when using method swizzling. For an explanation of method swizzling, go here.
I swizzled pathForResource:ofType: in NSBundle for my own method that searches every bundle my application has loaded. It also searches the resource archives I've shipped with my app. Now for the problem: keyboards normally access data from bundles that are private to iOS internals. My swizzled method didn't have access to those, so keyboards would intermittently fail and give me no useful information as to why.
To resolve it, I changed the swizzled method so that it would call the original implementation of [NSBundle pathForResource:ofType:] if no resource could be found by my app's method.
Problem solved.
精彩评论