Heads up: Apple store rejection for apps using three20

1,046 views
Skip to first unread message

Pradeepta Dash

unread,
Oct 26, 2009, 6:20:53 PM10/26/09
to thr...@googlegroups.com
Apologies if this has been reported earlier. 

An app of mine got rejected because three20 uses private API/ivars.

- UITouch._locationInWindow
- UITouch._phase
- UITouch._previousLocationInWindow
- UITouch._tapCount
- UITouch._timestamp
- UITouch._touchFlags
- UITouch._view
- UITouch._window

--pradeepta

Mads Rasmussen

unread,
Oct 26, 2009, 6:27:25 PM10/26/09
to thr...@googlegroups.com
That's bad !!

Any workarounds? are the use of these private APIs isolated or used in all classes?

Mads
--
Mads Rasmussen
Creative-Apps
Chief Technology Officer
------------------------------------------
mads.ra...@creative-apps.com
www.creative-apps.com
Mobile: 55 11 7533-6292
Mobile: 55 11 9407-4493
Skype: rasmussen.brazil2
@mazebr

Pradeepta Dash

unread,
Oct 26, 2009, 6:38:15 PM10/26/09
to thr...@googlegroups.com
To be fair the source code in three20 calls it out

"/**

 * WARNING: This depends on undocumented APIs and may be fragile.  For testing only.

 */

"


From UIViewAdditions, I am going to remove 

a) - (void)simulateTapAtPoint:(CGPoint)location
b) UITouch (TTCategory)

That *should* be enough.

I will let everyone know how that works out.

--pradeepta

uprise78

unread,
Oct 26, 2009, 6:38:35 PM10/26/09
to Three20
Ummmm....those arent private. They are listed right in the UITouch
docs:

http://developer.apple.com/iphone/library/documentation/UIKit/Reference/UITouch_Class/Reference/Reference.html

What you may be referring to is the simulateTapAtPoint: method and the
UITouch/UIEvent categories. Just remove the simulateTapAtPoint:
method and everything it references which is just the UITouch
(TTCategory) and UIEvent (TTCategory). You can get extra efficient and
remove the UIEventFake class.

Pradeepta Dash

unread,
Oct 26, 2009, 6:47:14 PM10/26/09
to thr...@googlegroups.com
Here is the code : http://github.com/joehewitt/three20/blob/master/src/UIViewAdditions.m

@implementation UITouch (TTCategory)
 
- (id)initInView:(UIView *)view location:(CGPoint)location {
  if (self = [super init]) {
    _tapCount = 1; <= BAD
    _locationInWindow = location; <= BAD
    _previousLocationInWindow = location; <= BAD
 
    UIView *target = [view.window hitTest:_locationInWindow withEvent:nil];
    _view = [target retain]; <= BAD
    _window = [view.window retain]; <= BAD
    _phase = UITouchPhaseBegan; <= BAD
    _touchFlags._firstTouchForView = 1; <= BAD
    _touchFlags._isTap = 1; <= BAD
    _timestamp = [NSDate timeIntervalSinceReferenceDate]; <= BAD
  }
  return self;
}
 
- (void)changeToPhase:(UITouchPhase)phase {
  _phase = phase; <= BAD
  _timestamp = [NSDate timeIntervalSinceReferenceDate]; <= BAD
}
 
@end

Matt Vague

unread,
Oct 26, 2009, 8:32:06 PM10/26/09
to Three20
So were supposed to remove this from three20??

On Oct 26, 3:47 pm, Pradeepta Dash <pradee...@gmail.com> wrote:
> Here is the code :http://github.com/joehewitt/three20/blob/master/src/UIViewAdditions.m
>
> @implementation UITouch (TTCategory)
>
> - (id)initInView:(UIView *)view location:(CGPoint)location {
>   if (self = [super init]) {
>     _tapCount = 1; <= BAD
>     _locationInWindow = location; <= BAD
>     _previousLocationInWindow = location; <= BAD
>
>     UIView *target = [view.window hitTest:_locationInWindow withEvent:nil];
>     _view = [target retain]; <= BAD
>     _window = [view.window retain]; <= BAD
>     _phase = UITouchPhaseBegan; <= BAD
>     _touchFlags._firstTouchForView = 1; <= BAD
>     _touchFlags._isTap = 1; <= BAD
>     _timestamp = [NSDate timeIntervalSinceReferenceDate]; <= BAD
>   }
>   return self;
>
> }
>
> - (void)changeToPhase:(UITouchPhase)phase {
>   _phase = phase; <= BAD
>   _timestamp = [NSDate timeIntervalSinceReferenceDate]; <= BAD
>
> }
>
> @end
>
>
>
> On Mon, Oct 26, 2009 at 3:38 PM, uprise78 <des...@gmail.com> wrote:
>
> > Ummmm....those arent private.  They are listed right in the UITouch
> > docs:
>
> >http://developer.apple.com/iphone/library/documentation/UIKit/Referen...

uprise78

unread,
Oct 26, 2009, 10:51:50 PM10/26/09
to Three20
To be safe, you probably should. That being said, I have a few apps
in the app store that have that code in them. It just depends on your
luck with the Apple employee who does your review.

neptune2000

unread,
Oct 27, 2009, 11:58:36 AM10/27/09
to Three20
Can anyone else confirm rejection?

neptune2000

unread,
Oct 27, 2009, 12:01:02 PM10/27/09
to Three20
Can anyone give a list of "safe" changes that are going to satisfy the
requirement and not break everything?

Notice that three20 is included in the Facebook app.

Jonathan Saggau

unread,
Oct 27, 2009, 12:10:10 PM10/27/09
to thr...@googlegroups.com
Is it perhaps time for a #define APP_STORE_SAFE ? :)

Mike D

unread,
Oct 27, 2009, 12:16:07 PM10/27/09
to thr...@googlegroups.com
Safe changes are listed below in one of my previous replies.

Nazar

unread,
Oct 27, 2009, 12:55:26 PM10/27/09
to Three20
Thanks for the heads up, Pradeepta

neptune2000

unread,
Oct 27, 2009, 1:43:18 PM10/27/09
to Three20
What about the call to simulateTapAtPoint in UIWebViewAdditions.m ?

On Oct 26, 3:38 pm, uprise78 <des...@gmail.com> wrote:
> Ummmm....those arent private.  They are listed right in the UITouch
> docs:
>
> http://developer.apple.com/iphone/library/documentation/UIKit/Referen...

Mike D

unread,
Oct 27, 2009, 1:46:10 PM10/27/09
to thr...@googlegroups.com
you will need to remove that as well or your project wont compile.

neptune2000

unread,
Oct 27, 2009, 3:56:35 PM10/27/09
to Three20
I get that, but removing the call is going to pretty much break the
function that uses it.

Mike D

unread,
Oct 27, 2009, 4:48:18 PM10/27/09
to thr...@googlegroups.com
Nothing in three20 uses it. As long as you arent using it then it
won't hurt anything.

neptune2000

unread,
Oct 27, 2009, 6:08:06 PM10/27/09
to Three20
That's good. So if I remove

- (void) simulateTapAtPoint:(CGPoint_ location

- (id)initInView:(UIView *)view location:(CGPoint)location {

- (void)changeToPhase:(UITouchPhase)phase {

- (void)simulateTopElement:(NSString*) query {

I should not be getting any compilation errors, right?

I guess it is time to try.

neptune2000

unread,
Oct 27, 2009, 6:21:30 PM10/27/09
to Three20
That seems to do it. No compilation errors.

Nick Partridge

unread,
Oct 28, 2009, 9:02:23 PM10/28/09
to thr...@googlegroups.com
Related to this rejection, I just had an app rejected with the following feedback:

> The non-public APIs that are included in your applications are the
> following:
> - firstResponder
> - undocumented, Private UITouch instance variables

I'm going to assume that the UITouch instance variables is the same issue as Pradeepta's, however the firstResponder problem is troubling.

That selector is used whenever Three20 (or otherwise) needs to know if the keyboard is visible, or to scroll the first responder into the view. I'll have to strip all that functionality out of three20 to use it.

A greater concern though, is that Three20 is using private APIs without flagging it to the consumer of the library. As much as I find three20 to be a great productivity to boost to working with cocoa, we're going to be phasing it out of our applications.

-Nick


taco

unread,
Oct 28, 2009, 9:49:39 PM10/28/09
to Three20
Ouch.

I've just started adopting Three20. Abandon ship?

Mike D

unread,
Oct 28, 2009, 9:51:15 PM10/28/09
to thr...@googlegroups.com
I sure wouldn't abandon ship. TTStyle alone is more than enough
reason to keep using it let alone all the other built in goodies.

Pradeepta Dash

unread,
Oct 28, 2009, 9:53:26 PM10/28/09
to thr...@googlegroups.com
I got rejected for the 2nd reason, exact same verbage.

However, I took out the all calls to firstResponder as well and re-submitted the app just now (just to safe)

Thanks for the heads up.
--pradeepta

Lyndsay Hackett

unread,
Oct 28, 2009, 10:13:28 PM10/28/09
to Three20
Pradeepta & Nick, were the calls ones that you'd made inside your own
code or were they calls that are made in the Three20 libraries? In
other words, will just having the library in your app trigger a
possible rejection or do you need to make those calls yourself to
trigger the rejection?

Thanks

Lyndsay

siong1987

unread,
Oct 28, 2009, 10:24:06 PM10/28/09
to Three20
Hi Pradeepta,

Is it possible for you to fork a branch on github to share your SAFE
three20 library with us?

Thank you.

On Oct 28, 6:53 pm, Pradeepta Dash <pradee...@gmail.com> wrote:

Nick Partridge

unread,
Oct 28, 2009, 11:25:45 PM10/28/09
to thr...@googlegroups.com
For firstResponder, any TTViewController that has a keyboard displayed within it will call the private selector. Given this is the base for every view controller in three20... :-s . We are definitely calling this code.

However, I'm confident we're not using the code that accesses the UITouch private variables and yet they have included that in the rejection notice. I suspect they're using static analysis to find the usages and that just having the code within your project will be enough for a rejection.

-Nick

David Morford

unread,
Oct 29, 2009, 12:28:36 AM10/29/09
to thr...@googlegroups.com
The changes are straight forward. To get rid of firstResponder calls,
do the following:

1. Delete the TTIsKeyboardVisible function in TTGlobal.h/m. Nothing
calls it.

2. Delete TTMessageController. It accounts for the majority of the
calls and MFMailComposeViewController in MessageUI basically makes it
obsolete.

3. Replace scrollFirstResponderIntoView in UITableViewAdditions with
this (or something similar):

-(void) scrollFirstResponderIntoView {
NSIndexPath *selectedRowIndexPath = [self indexPathForSelectedRow];
if (![[self indexPathsForVisibleRows]
containsObject:selectedRowIndexPath]) {
[self
scrollToNearestSelectedRowAtScrollPosition:UITableViewScrollPositionMiddle
animated:YES];
}
}

This breaks the TTTableControlItem... but they are kind broken in the
present form anyway so just add UITextFields directly to a
TTTableViewItem or don't use TTableItem/TTTableViewController for
views that need interaction. I would guesstimate that anything that
wants to scroll to TTStyledNode might be affected as well but can not
fathom where they might be used realistically other than a
TTStyledTextTableItemCell that might want to scroll to a particular
TTStyledNode subclass instance in its TTStyledTextLabel.

4. In frameWithKeyboardSubtracted in UIViewAdditions.m, Comment out
the line below (302 in e8ecb80) and the matching bracket:

if ([self.window performSelector:@selector(firstResponder)]) {

I removed these and the UITouch code from my own branch as soon as I
saw them, ages ago it seems now. I maintain my own branch manually,
incorporating changes by hand so that I am always aware of what is
going on inside the code. I did test them with the latest master,
e8ecb80, using TTCatalog. I found nothing that seemed broken aside
from scrolling for TTTableControlItem instances. There are prolly some
other issues... make the changes and report them back here. This is
what open source libraries are all about...

Apple needs to add an open source libraries and frameworks category to
the design awards at WWDC next year and Joe should win on iPhone OS
for Three20. That having been said, Three20 encompasses a number of
advanced concepts and anyone contemplating using it for production
applications, your own or for your clients or company, should take the
time to fully understand it.


Cheers,
David

Joe Hewitt

unread,
Oct 29, 2009, 12:55:44 AM10/29/09
to Three20
I got a phone call from Apple today about this issue. They asked me
to remove simulateTapAtPoint and related code due to their static
analyzer automatically flagging it and rejecting apps. I just checked
in some changes which wrap this code in an #ifdef DEBUG so they can
still be used for their intended debugging purposes.

Nick Partridge

unread,
Oct 29, 2009, 12:58:57 AM10/29/09
to thr...@googlegroups.com
That having been said, Three20 encompasses a number of
advanced concepts and anyone contemplating using it for production
applications, your own or for your clients or company, should take the
time to fully understand it.
 
Indeed, the need to audit all your dependencies is a valuable lesson I've just learned! Hopefully other's can benefit from my experience.

The snapshot I've been using is a50859aa3, dated July 8. I assumed that this would have been through the App Store a number of times already, and was really relying on a crowd-sourced audit. I guess apple have a new tool for checking for this.
 
Message has been deleted

Jonathan Saggau

unread,
Oct 29, 2009, 2:44:08 AM10/29/09
to thr...@googlegroups.com
In case anybody ever wants to get first responder by searching the view
hierarchy:

//
// UIWindow+ttFirstResponder.h
// Three20
//
// Created by jonathan on 10/29/09.
// Copyright 2009 __MyCompanyName__. All rights reserved.
//

#import <UIKit/UIKit.h>


@interface UIWindow (ttFirstResponder)

-(UIView *)ttFirstResponder;

@end


// UIWindow+ttFirstResponder.m

#import "UIWindow+ttFirstResponder.h"

UIView * recursiveFirstResponderSearchInView(UIView *viewToSearch)
{
UIView *fResponder = nil;
if([viewToSearch isFirstResponder])
{
return viewToSearch;
}
for (UIView *view in [viewToSearch subviews]) {
if([view isFirstResponder])
{
fResponder = view;
break;
}
UIView *someOtherView = recursiveFirstResponderSearchInView(view);
if([someOtherView isFirstResponder])
{
fResponder = someOtherView;
break;
}
}
return fResponder;
}

@implementation UIWindow (ttFirstResponder)

-(UIView *)ttFirstResponder;
{
UIView *responder = recursiveFirstResponderSearchInView(self);
return responder;
}

@end

Eelco Lempsink

unread,
Oct 29, 2009, 3:37:29 AM10/29/09
to thr...@googlegroups.com

I got two apps accepted this week, both using the September 8 version
(969d6f6, extended with some bugfixes).

--
Regards,

Eelco Lempsink

David Morford

unread,
Oct 29, 2009, 4:16:34 AM10/29/09
to thr...@googlegroups.com
Good fix Jonathan. Much thanks for sharing.

David Morford

unread,
Oct 29, 2009, 4:25:52 AM10/29/09
to thr...@googlegroups.com

I should add that TTMessageController does not use firstResponder WRT
UIWindow. It just has text strings to store which text field was the
firstResponder during persist/restoreView calls. Should have looked
closer in Project Find but I never use the class and don't include in
my local project variant.

Cheers,
David

neptune2000

unread,
Oct 29, 2009, 11:41:42 AM10/29/09
to Three20
What changes did you do to eliminate the reliance on calls to
firstResponder? Would you mind being more specific?

On Oct 28, 6:53 pm, Pradeepta Dash <pradee...@gmail.com> wrote:

Adam Jack

unread,
Oct 29, 2009, 11:57:55 AM10/29/09
to thr...@googlegroups.com
First, David (Morford) thank you for your steps to removing the offending calls.

Second, Jonathan, this is very useful thanks. I'll be using it to update David's step #4. 

4. In frameWithKeyboardSubtracted in UIViewAdditions.m, Comment out  
the line below (302 in e8ecb80) and the matching bracket:

     if ([self.window performSelector:@selector(firstResponder)]) {

I found that ignoring detecting if a keyboard was raised meant things overlays (loading, error, etc.) fit into the space above a keyboard, and failed to cover the whole visible view. At first I opted to comment out the whole section this "if block" contained (since I don't have such cases w/ a keyboard) but I like the idea of fixing it properly with this.

regards,

Adam
--
Share Wildlife: http://wildobs.com
iPhone Application: http://wildobs.com/about/iphone



wuf810

unread,
Oct 29, 2009, 2:43:14 PM10/29/09
to Three20
I'm confused! Sorry but I am.

So a question: will Joe's latest commit take care of the issue of a
potential rejection or should I consider changing the firstResponder
code?

If the latter, can someone be a bit more specific....I can see
Jonathan's UIWindow Category fix but where am I suppose to implement
it.

Sorry still early days for me and I need a bit of hand holding :-)

TIA, Michael.
Message has been deleted

Mike D

unread,
Oct 30, 2009, 10:15:49 PM10/30/09
to thr...@googlegroups.com
Hi ifdefed only part of the code. The whole GSEvent and UITouch
category needs to get ifdefed as well.




On Fri, Oct 30, 2009 at 7:14 PM, Cory <cory.i...@gmail.com> wrote:
>
> I just had a few Apps that were using Three20 get rejected too. I
> think we need to get Joe to fix it up in the main development line for
> all future apps...
>
> On Oct 28, 8:25 pm, Nick Partridge <nkp...@gmail.com> wrote:
>> For firstResponder, any TTViewController that has a keyboard displayed
>> within it will call the private selector. Given this is the base for every
>> view controller in three20... :-s . We are definitely calling this code.
>>
>> However, I'm confident we're not using the code that accesses the UITouch
>> private variables and yet they have included that in the rejection notice. I
>> suspect they're using static analysis to find the usages and that just
>> having the code within your project will be enough for a rejection.
>>
>> -Nick
>> On Thu, Oct 29, 2009 at 12:13 PM, Lyndsay Hackett <lyndsay.hack...@gmail.com

wuf810

unread,
Oct 30, 2009, 11:16:17 PM10/30/09
to Three20
Is this something we can do ourselves? if yes anybody willing to share
advice/instructions?

TIA, Michael.