Cleanly Accessing the UITextView field in TWTweetComposeViewController

I have been working with my son Nathan over the last several months, helping him get started doing contract iOS development (check out his first solo app, Cincy Lineup.) While working on an enhancement, he needed to pre-populate the text of a tweet, then position the cursor at the beginning of the field with nothing selected to make it easy for users to customize the tweet.

Apple’s TWTweetComposeViewController is a great component and takes care of most of the details to construct and send tweets for you, but it does not expose any of the fields. We could have looped through the views and subviews directly to find the field we want — but we wanted a safer method that didn’t depend on the current configuration of views, since that can change when iOS is updated.

But, there is a simple, clean approach that does not try to find a particular view inside Apple’s view controller, nor does it depend on any private api’s or structure.

  1. We add a notification observer for UIKeyboardWillShowNotification,
  2. We call ‘presentModalViewController’ with our instance of TWTweetComposeViewController,
  3. When our notification handler method is called, we find the first responder,
  4. We check to see if it is a UITextView,
  5. We set the selection range to the beginning of the field so the cursor is prepositioned where we want it.
…
// at an appropriate place in your code, 
//      add and remove the observer for UIKeyboardWillShowNotification

    [[NSNotificationCenter defaultCenter] addObserver:self 
                                             selector:@selector(handleKeyboardWillShow:) 
                                                 name:UIKeyboardWillShowNotification 
                                               object:nil];
…


- (UIView *) findFirstResponderInView:(UIView*) view
{
    if (view.isFirstResponder) {
        return view;
    }
    for (UIView *subview in view.subviews) {
        UIView *result = [self findFirstResponderInView:subview];
        if (result) {
            return result;
        }
    }
    return nil;
}

- (void) handleKeyboardWillShow:(NSNotification *) notification;
{
    UIView *fr = [self findFirstResponder:self.tweetSheetViewController.view];
    if ([fr isKindOfClass:[UITextView class]]) {
        UITextView *tv = (UITextView *) fr;
        [tv setSelectedRange:NSMakeRange(0,0)];
    }
}


I hope you find this short tip useful. It has been several months since I posted to iDevBlogADay, hopefully I can get back on the regular writing track.

[Update: the app was approved as expected without any problem]


Here is a little more information about me, Doug Sjoquist, and how I came to my current place in life.. Hope you have a great day!