bad_Access exception when typing in UITextView - ios

I don't know what is wrong with this code; when i start typing in the UITextView, the program terminates with exc_Bad_Access exception.
UIView *toolbar = [[UIView alloc] initWithFrame:CGRectMake(0, 430, 320, 44)];
toolbar.backgroundColor = [UIColor lightGrayColor];
UITextView *sendTextView = [[UITextView alloc] initWithFrame:CGRectMake(10, 9, 240, 26)];
sendTextView.backgroundColor = [UIColor whiteColor];
sendTextView.inputAccessoryView = toolbar;
sendTextView.layer.cornerRadius = 12.0;
[toolbar addSubview:sendTextView];
[self.view addSubview:toolbar];
The above code is inside the viewDidLoad method of a UIViewController which has a UIScrollView as its view.

Putting an editable text view in a toolbar seems strange. (What do you do when the user wants to edit it? Move it up above the keybaord? I wouldn't expect a toolbar to move OR to contain an editable field.) Nevertheless, I'd be surprised if doing that caused EXC_BAD_ACCESS.
Your problem is more likely in code that actually runs when you're typing, such as one of the text view delegate methods. If you can't find anything there, please post the stack trace at the time of the crash and code for the method that was actually running at the time.
Update: After you pointed it out in your comment, I see that you're setting the toolbar as the input accessory view for sendTextView and adding it to the view controller's view. I'd guess that what's happening here is that when you start editing the text view, the text view adds the toolbar to the keyboard's view without first removing it from the view controller's view. A given view can only be part of one view hierarchy at a time; adding it to your view and using it as the input accessory view won't work. If you look at Apple's sample code for using an accessory view you'll find that the view used as the accessory isn't part of the normal view hierarchy.

Related

Why is this UISearchBar getting resized?

As shown below, my UISearchBar is getting resized when I tap on the search field. It animates nicely to cover the navigation bar, and then pop... it shrinks.
The setup
The UISearchBar is inside a vanilla UIView set as the tableHeaderView. I'm using a UIView (as opposed to setting the UISearchBar as the header) because I would like to put additional views in the header.
The view is defined in a XIB file and the UISearchBar is anchored to all of its borders. The constraints don't seem to matter; if I remove them, the same problem happens.
Experiments
Examining the view hierarchy in Reveal tells me that the UIView has the right size and the UISearchBar has width 1 (?!) when this happens.
As an experiment, I subclassed the UISearchBar and made intrinsicContentSize return {320,44}. With this the UISearchBar shows properly, but when I press Cancel I get the following exception:
*** Assertion failure in -[UITableView layoutSublayersOfLayer:], /SourceCache/UIKit_Sim/UIKit-2903.23/UIView.m:8540
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Auto Layout still required after executing -layoutSubviews. UITableView's implementation of -layoutSubviews needs to call super.'
The workaround
If I create everything by code, it just works.
_headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, 44)];
UISearchBar *searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, 44)];
searchBar.delegate = self;
[_headerView addSubview:searchBar];
_searchDisplayController = [[UISearchDisplayController alloc] initWithSearchBar:searchBar contentsController:self];
_searchDisplayController.searchResultsDelegate = self;
_searchDisplayController.searchResultsDataSource = self;
_searchDisplayController.delegate = self;
_tableView.tableViewHeader = _headerView;
What is going on here? I clearly won't use nibs to work with UISearchBar anymore, but I would like to understand what the heck happened anyway.
The difference is in the search bar's value of translatesAutoresizingMaskIntoConstraints. It defaults to NO for the XIB-based view and YES for the code-based view. Apparently, the search controller assumes a value of YES and doesn't set up any explicit constraints when it transplants the search bar.
Setting the value to YES in code should fix it (verified locally).
UPDATE
As noted in the comments, even with translatesAutoresizingMaskIntoConstraints = YES, the controller does not restore the header view to it's original state on cancel. But there does seem to be a workaround. You can create an outlet to your header view and restore it yourself in searchDisplayControllerDidEndSearch. I did a crude proof-of-concept (and updated my sample project):
- (void)searchDisplayControllerDidEndSearch:(UISearchDisplayController *)controller
{
self.tableView.tableHeaderView = self.headerView;
[self.searchBar removeFromSuperview];
self.searchBar.frame = CGRectMake(0, 20, 320, 44);
[self.headerView addSubview:self.searchBar];
}
Following on from what both #TimothyMoose and #hpique have said about setting translatesAutoresizingMaskIntoConstraints = YES (yuck)
In my code I have found that if I do the following to show the searchDisplayController
self.searchDisplayController.searchBar.translatesAutoresizingMaskIntoConstraints = YES
[self.searchDisplayController setActive:YES animated:YES]
and do the opposite when closing the searchDisplayController,
self.searchDisplayController.searchBar.translatesAutoresizingMaskIntoConstraints = NO
[self.searchDisplayController setActive:NO animated:YES]
Then my view remains unchanged (everything goes back to what I'm expecting)
if i do not call the following line when closing
self.searchDisplayController.searchBar.translatesAutoresizingMaskIntoConstraints = NO
Then the view screws up.
The reason for this I believe is that the NSAutoresizingMaskLayoutConstraint are asserting them self and as they are the last in the constraint list, the Layout engine brakes the real constraint to satisfy the unwanted NSAutoresizingMaskLayoutConstraint constraints.

ios adding custom inputView

I'm stuck on a concept in iOS that I can't seem to understand, no matter how much I read about it. I'm trying to override the standard iOS number pad with a custom design. When the user touches the UITextField, I want the custom inputView to reveal instead of the standard number pad.
I created an separate .h/.m/.xib ViewController class for my custom inputView called "customInputViewController" Right now, it's just a dark background and one button that obscures about half of the screen when the UITextField is touched (similar to the number pad, but it just looks different). My implementation fails when I click the one button in my custom inputView -- iOS throws an EXC_BAD_ACCESS error.
This is how I load the .xib file at runtime and attach the custom inputView to the UITextField object:
UIViewController *v = [[customInputViewController alloc] initWithNibName:#"customInputDesign" bundle:nil];
myTextInput.inputView = v.view;
In the .xib file of the custom inputView, I set the File's Owner to be "customInputViewController" and I created an (IBAction) method and attached it to a UIButton. When that button is clicked, the (IBAction) is set up to send an NSLog(#"Button Clicked") message. Nothing special. It's just a simple boilerplate implementation that continues to throw an error.
Maybe I'm doing this entirely wrong. Can anyone provide a simple example?
The view v.view is retained as the inputView property is defined as (readwrite, retain). However, if you release your customInputViewController v somewhere before the input button is clicked, you will get a crash (EXC_BAD_ACCESS)
You can try this in your main controller:
- (IBAction) keyboardButtonClicked
{
NSLog(#"keyboard Button Clicked");
}
- (void) viewDidLoad
{
// do your stuff here ...
UIView *v = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 100)]; // add autorelease if you don't use ARC
v.backgroundColor = [UIColor darkGrayColor];
UIButton *b = [UIButton buttonWithType:UIButtonTypeCustom];
[b setTitle:#"Test button" forState:UIControlStateNormal];
[b addTarget:self action:#selector(keyboardButtonClicked) forControlEvents:UIControlEventTouchUpInside];
b.frame = CGRectMake(80, 25, 160, 50);
[v addSubview:b];
myTextInput.inputView = v;
}
Should work fine ...
First of all, Take a look at this
The UIKit framework includes support for custom input views and input
accessory views. Your application can substitute its own input view
for the system keyboard when users edit text or other forms of data in
a view. For example, an application could use a custom input view to
enter characters from a runic alphabet. You may also attach an input
accessory view to the system keyboard or to a custom input view; this
accessory view runs along the top of the main input view and can
contain, for example, controls that affect the text in some way or
labels that display some information about the text.
To get this feature if your application is using UITextView and
UITextField objects for text editing, simply assign custom views to
the inputView and inputAccessoryView properties. Those custom views
are shown when the text object becomes first responder...
Actually i don't need to mention all this mess to you, but there is an interesting reason for mentioning this, from the first sentence i am mentioning view-view-view, but you are making the input view in a separate view controller and you are trying to assign it as an input view of your textfield and init shouldn't be creating the view, loadView does that. Calling the view getter (v.view) when view is nil will cause loadView to be invoked.Thats why it is crashing with EXC_BAD_ACCESS.
Source : Text, Web, and Editing Programming Guide for iOS

UIView appearing before navigation transition is over

I'm writing an iPhone app with a table inside a navigation controller. When the user clicks one of the cells in the main screen a UIView on top of the incoming view controller is created (it's like a toolbar).
self.toolbar = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 45)];
toolbar.backgroundColor = [UIColor colorWithRed:0.8823 green:0.8823 blue:0.8823 alpha:1.0];
[self.navigationController.view addSubview:toolbar];
The problem is that the view appears before the transition to the new view controller is complete and the effect is pretty weird. I suppose this is due to the fact I add the view to the navigationController,but I need to do this otherwise the bar would scroll together with the table and instead I want it to be fixed.
Any suggestion?
I've found a possible solution: add the toolbar as TableHeaderView and follow iOS: Add UIView to UITableView
Any other better solution is more than welcome

Text in UITextView not display correctly, invisible, but occupied spaces

There is a UITextView in the view, the view controller is showing with Modal style. In my viewDidLoad method, I set the text of this UITextView, but, the text is not showing. Image below showing the error. Text color is black.
The weird thing is , when I long tap in the text view or tap [return] in keyboard, the text become visible. One thing I noticed is this error only occurred when the text I set is longer than the UITextView frame width, and the last word is not broken such as a long url.
I think the problem is maybe the word wrap not work correctly.
Thanks in advance.
Code like below:
UITextView *myTextView = [[UITextView alloc]initWithFrame:CGRectMake(10, 10, 520, 220)];
myTextView.textColor = [UIColor blackColor];
myTextView.font = [UIFont systemFontOfSize:20];
myTextView.layer.cornerRadius = 5;
myTextView.delegate = self;
myTextView.text = #"long text should some like http://stackoverflow.com/posts/11200726/edit";
[self.view addSubview:myTextView];
[myTextView release];
RESOVLED. In viewDidLoad method, add code below:
CGRect tempFrame = myTextView.frame;
[myTextView setFrame:CGRectZero];
[myTextView setFrame:tempFrame];
Subclass UITextView, to a class of your own, let's say MyUITextView:UITextView.
Initialize it offscreen with
[[MyUITextView alloc] initWithFrame:CGRectZero]
In MyUITextView override the method
-(void)willMoveToWindow:(UIWindow *)newWindow
and in it, set self.frame to the proper value.
this worked for me!
Are you sure the text color is black? Also make sure that the image is behind the textView in the view hierarchy. TextView handles Word wrap automatically.
I think in this case, the viewDidLoad is getting called before modelViewController is presented.
Set the text after modalViewController is presented.
If that also not working, then after presenting model, call a method to set the text explicitly.
Check your view hierarchy. You might have added another textView above that view.
Try changing the background color of textView. It must appear is UITextView is added there. And make sure you are not adding another view as a subview above your UITextView. If the textColor is black it must be visible, wordwrap is done by default automatically unless you change the property.Also try to check the attributes settings in XIB if added and plz show the code if adding programmatically.
I think problem in:
self.view
Try add this code line at top
self.view = [[[UIView alloc] initWithFrame:[UIScreen mainScreen].bounds] autorelease];
And if not will help, try remove this code line
myTextView.layer.cornerRadius = 5;

Two controllers inside of a UIPopoverController: having issues with frames

I have a UIPopoverController with two view controllers inside of it. I'm building it like so:
CommentsPopoverController *commentsPopoverController = [[CommentsPopoverController alloc] init];
self.delegate = commentsPopoverController;
commentsPopoverController.navigationItem.title = #"Comments";
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:commentsPopoverController];
popover = [[UIPopoverController alloc] initWithContentViewController:navController];
Inside my commentsPopoverController I have this:
commentsViewController = [[CommentsViewController alloc] init];
commentsViewController.view.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height);
addCommentsViewController = [[AddCommentViewController alloc] init];
addCommentsViewController.view.frame = CGRectMake(0, commentsViewController.view.bounds.size.height - 200, 320, 346);
addCommentsViewController.view.backgroundColor = [UIColor darkGrayColor];
[self.view addSubview:addCommentsViewController.view];
[self.view addSubview:commentsViewController.view];
So when I first load the popover, the addCommentsViewController is hidden by the commentsViewController. When I reveal it, it looks like this:
So far so good. The problem I'm having is that from here, when the user rotates the device or shows the keyboard or shows the keyboard THEN rotates the device things start to get out of whack. The top view controller (commentsViewController) which is a UITableView always does the right thing no matter what the orientation is or whether or not the keyboard is showing. But the bottom view controller (addCommentsViewController) doesn't automatically change it's origin.y to stay directly under the top view controller.
So I've basically had to hack the crap out of my code to keep the addCommentsViewController directly under the commentsViewController by constantly calculating the height of the top view controller so that I could adjust the bottom view controller's origin.y. This involved dropping in NSNotifications for the keyboard's show/hide state and for the device's orientation and constantly recalculating. Very hackish and ugly.
So my question (finally) is: Is there an easier way of controlling these views or am I stuck hacking it the way I did?
To handle rotation, there are two appropriate techniques. One is that you make CommentsPopoverController's view a subclass of UIView that overrides layoutSubviews to lay out your two views properly. The other is that you define viewDidLayoutSubviews on CommentsPopoverController to lay out your views. If you lay out your views in either of these methods, you shouldn't have to subscribe to rotation notifications.
As for moving your view out from under the keyboard, that is discussed in the Text, Web, and Editing Programming Guide for iOS. Part of the technique involves subscribing to keyboard will show/did hide notifications.
I assume your CommentsViewController is a subclass of UITableViewController, because UITableViewController takes care of adjusting the table view when the keyboard is hidden or shown.

Resources