UITextView freezes iPad app from textViewShouldBeginEditing. (Invalid Glyph Index) - ios

So I've been working on this bug for about a week now, and for the life of me I can't figure out what's happening.
Due to confidentiality issues I can't post too much code, but I'll do my best to explain everything.
What's happening is that we're populating a UITextField via code, and initially have the text greyed out. The user then can do one of two things:
1) Tap a button which says "commit" and a method is called which does the following method we'll call "commitData". It does the following:
Registers the commit with an undo Manager
Changes the text from grey to black
Register with our application that the text field has been updated and needs to be saved upon application close
2) Tap on the text field with the greyed out text, which then calls the following default apple method textViewShouldBeginEditing. From here we call our "commitData" method listed from option 1 like so:
-(BOOL)textViewShouldBeginEditing:(UITextView *)textView
{
if ([[self box] hasGreyedOutText])
[[self box] commitData];
[self setActiveTextView:textView];
return YES;
}
The issue we're having is that tapping the button to commit the greyed out text works perfectly fine, and we run into no issues.
HOWEVER
When we tap into the text field and trigger the textViewShouldBeginEditing method, our iPads can freeze up and make the user wait for a couple of minutes before finishing. When I mean freeze, I mean the entire iPad freezes. The iPad clock won't even update while this is happening.
When this happens, we get an error code in the console which says:
!!! _NSLayoutTreeLineFragmentRectForGlyphAtIndex invalid glyph index 2147483647
We can get the error code above to display from all of our hardware when following the steps above, but can only reproduce the freezing on an iPad 2(with 100% accuracy however).
A note on this, my co-worker has found through diagnostics that we only have about 8MB of free RAM when this error occurs. We only ever hit this little of RAM on the iPad 2 however, so this could just be a coincidence.
I have a feeling that this could be related to threading and that we might need to somehow call our method after returning YES from the textViewShouldBeginEditing method, but I'm not quite sure how I should be going about that.
If anybody has any ideas on how to fix this, or even ideas that could point me in the right direction, I would be incredibly grateful. I've looked everywhere I can possibly think of, and none of the solutions I've found relating to the error code have ended up working.

I can't debug, so in my guess it may caused by non-main thread UI operation. So, my suggestion is to make sure your UI code is in mainThread. Try this:
-(BOOL)textViewShouldBeginEditing:(UITextView *)textView
{
dispatch_async(dispatch_get_main_queue(), ^{
if ([[self box] hasGreyedOutText])
[[self box] commitData];
[self setActiveTextView:textView];
}
return YES;
}

Related

Xcode errors appearing and disappearing with every build (clean doesn't help)

Hey idk if I am doing something wrong or if I should file a bug report for this.
I initiate UI elements to my main viewcontroller like the following:
knob[7] =[[UIImageView alloc] initWithFrame:CGRectMake(a, b, c, d)];
knobS[7] =[[knobBand alloc] initWithFrame:CGRectMake(a, b, c, d)];
knob[8] =[[UIImageView alloc] initWithFrame:CGRectMake(a, b, c, d)];
Then I do
[self.view addSubview:knobS[7]];
[knob[7] setImage:[UIImage imageNamed:#"knob"]];
[knob[8] setImage:[UIImage imageNamed:#"knob"]];
[self.view addSubview:knob[7]];
[self.view addSubview:knob[8]];
If I put the [self.view addSubview:knobS[7]]; below the other 4 lines, the knob[7] and knob[8] will not show up at all, although they are the same size and only knob[7] is covered by knobS[7]. I thought this is some programming mistake so I didn't investigate this any further because putting said line above the 4 lines worked - until I built the project the third time and this is where it's getting weird:
Now, whenever I build, build&clean, clean&build, ... the project, one of these 3 things happen:
Only knobS[7] is showing
All 3 UI elements are showing
the project builds but when launching it throws EXC_BAD_ACCESS at the setImage: line
And the amount of occurrences is pretty accurately summed up by the order; 1. is happening 60% of the times, 2. 30% and case 3 is happening in 1 out of 10 cases.
I tried rebooting and there isn't a single line of code grabbing the current time or a random value which might affect the outcome of the code. Even after hitting CMD+R twice within 10 sec without changing ANY code I get 2 different results.
Is there any other form of cleaning/building a project which might help here?
EDIT: This behavior is somehow not reproducible in Xcode 7, it's only 6 that causes the problems.
If I put the [self.view addSubview:knobS[7]]; below the other 4 lines, the knob[7] and knob[8] will not show up at all
You're creating three controls that are all the same size. Whichever one is added last will be on top. You may or may not be able to see the others, depending on how the one on top draws itself, whether the background is opaque, etc.
Now, whenever I build, build&clean, clean&build, ... the project, one of these 3 things happen:
Sounds like you've got a bad pointer and perhaps some other errors. If you use an invalid pointer, your app might throw an exception or it might not, depending on whether the pointer happens to point to a valid object. These kinds of problems have a very non-deterministic feel to them because they're very sensitive to tiny changes: where in memory the object was allocated in the first place, when it gets deallocated, whether anything else gets allocated using the same memory, etc.
I tried rebooting and there isn't a single line of code grabbing the current time or a random value which might affect the outcome of the code.
Doesn't matter -- you really can't expect the system to be in exactly the same state between one run of your app and the next.
Is there any other form of cleaning/building a project which might help here?
There's nothing wrong with how you're building the project, and it probably doesn't need to be cleaned either. To help find the problem, enable NSZombies, which will make your pointers to deallocated objects point instead to a small object that will trigger an exception when you try to use the pointer. That should make the problem more obvious and more reproducible.

Swift performSegueWithIdentifier delay

I have the following situation: I do a check when user touches screen, to check if it matches some bounds if menuButton.frame.contains(coordinates) {
Then, I try to push a segue like this performSegueWithIdentifier(menuButton.whichButton(menuButton.tag), sender: self) My problem is that the first time the segue performs, it has a huge delay (about 3-4 sec). Afterwards, everything runs as it should. I did check for main thread and I am in the main thread. Can you please help me?
I found the answer, as strange as it may appear, it was related with the fonts. I added some fonts, selected them in interface builder, but of course I didn't check the target membership. So the system was looking for them, I think, before reverting to default font, thus creating the lag. I hope it helps someone at some point.
Have you tried to run on a device or only in the simulator? Just to make sure...
You can try this too:
dispatch_async(dispatch_get_main_queue(),{
self.performSegueWithIdentifier(mysegueIdentifier, self)
})

iOS8 Button setEnabled doesn't work

I just downloaded the iOS8 GM Seed, and found that my UIButtons, which are setEnabled when in app purchases are bought, are not working.
In
- (void)viewDidLoad
I have
[mainToneBtn setEnabled:YES];
Pre-iOS8 this updates the button to be clickable, but not now. I haven't done any changes pertaining to this, and in debug, the code above is hit. No code sets it back to setEnabled:NO.
Any ideas?
Thanks.
I am unable to reproduce your problem. It seems, for whatever reason, that ViewDidLoad is now too early in the ViewController lifecycle for you to enable your buttons. I would suggest trying to enable them later in ViewDidLayoutSubviews.
For some reason this works,
[self performSelector:#selector(updateAllInAppPurchases) withObject:nil afterDelay:0.001];
the button code is within updateAllInAppPurchases
but I have no idea why I have to do this in ios8. I will accept the answer of anyone who can give me a good explanation, thanks!

UITextField can send its action twice. Is this an iOS bug, or did I make an error?

In iOS, I have a UITextField in a UITableViewController scene that is governed by a Navigation Controller. All static cells. The text field has the "Clear on editing" flag switched on. I want to get and save the value entered in the field, so I have the -editingDidEnd: action call my saveData: method in the custom UITableViewController subclass. If I click out of the text field, all is well. However, if I back out of the scene using the Back navigation button, then saveData: gets called twice. Once with the entered value, and a second time with an empty value. This appears to be incorrect behavior.
I've made a demo project and posted it to GitHub here: https://github.com/davehirsch/BugDemo
Am I doing something wrong? Is this an iOS bug? It seems unlikely that it's a bug nobody else has found (and I've looked around for others reporting similar things). I'm running the latest non-beta versions of Xcode and OS X, and the bug is happening in the iOS Simulator (but I'm not sure if it would happen on a real device, I guess).
Yes you are right. It looks like a bug in UINavigationController.
Before and after animation the method [UITextField resignFirstResponder] is called before and after animation. The first call is done by [UINavigationController popViewControllerAnimated:], and the second one in [UINavigationConteoller navigationTransitionView:didEndTransition:fromView:toView:] that call [UIView(Hierarchy) _removeFirstResponderFromSubtree].
Looks like your text field hasn't resigned yet as a first responder before animation ends.
[EDIT]
I recommend to look at rdelmar comment.

Possible UISwitch bug in iOS7?

I am using a UISwitch to call a subview to screen in my app. However, the switch only works about 60% of the time. To test my code I hooked the switch to another IBAction to write the state of the switch to the console. Both functions are not responding to the state of the switch at certain times, i.e., both functions are ignoring the state of the switch simultaneously some of the time. Has anybody else experienced this behaviour with UISwitches in iOS7?
- (IBAction)showHideSomeSubView:(UISwitch *)sender {
if (_mySwitch.on) {
[self.view addSubview:someSubView];
}
else {
[someSubVew removeFromSuperview];
}}
Edit:
The same switch is connected to the following action:
- (IBAction)switchToggled:(UISwitch *)sender {
sender = _mySwitch;
if ([sender isOn]) {
NSLog(#"On");
} else {
NSLog(#"Off");
}}
Both actions respond in the same way to the switch.
I confirm that weird behaviour with you!!!!
Just drag the little circle of the switch around and around, you will see the action called multiple times (in my case up to 403 :D )
I am really not sure that is what Apple engineers intended to do, because I have not found any documentation about this new behaviour, BTW, if you find one, please let me know too.
Thank you very much
I'm using several UISwitches in an iOS 7 app, I have had no problem at all responding to the Value Changed action. The switch consistently reports its value correctly. You should unhook the switch from its action in IB and then reconnect, making sure you are connecting the Value Changed action.
Yes, with a UISwitch in the iOS 7 iPad simulator, I am seeing 1-12 callbacks to my equivalent of your switchToggled: method. On the last callback, the value has in fact changed. On the previous callbacks, it hasn't. What I am doing is caching whether or not the switch is on. Then in the switchToggled: method, I check whether or not the value has in fact changed. If it hasn't, I ignore the callback. This seems to make things behave correctly for the user.
The problem does also happen on the device, though apparently less often. The same work-around seems to work there.

Resources