Method swizzling cause for 4.0 rejection

859 views
Skip to first unread message

Jeff

unread,
May 11, 2010, 5:57:43 PM5/11/10
to Three20
Just received this from Apple. Looks like the use of method swizzling
in TT is grounds for rejection and/or removal from the store. Anyone
else get a similar notice? Any plans for revving the library to
remove these issues?

-----------------
Your application, xxx, currently posted to the App Store is using
method_exchangeImplementations to exchange the implementation of Apple
provided APIs with your own implementations. Because of upcoming
changes, this behavior in your application may cause a crash or cause
user data loss on iPhone OS 4.0.

xxx uses method_exchangeImplementations to exchange the implementation
of dealloc with your method ttdealloc. It also exchanges the
implementation of the method popViewControllerAnimated: with your
method popViewControllerAnimated2:.

Please resolve this issue immediately and upload your new binary to
iTunes Connect. We may remove your application if we believe that
doing so is prudent or necessary.

--
You received this message because you are subscribed to the Google Groups "Three20" group.
To post to this group, send email to thr...@googlegroups.com.
To unsubscribe from this group, send email to three20+u...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/three20?hl=en.

Joseph

unread,
May 12, 2010, 10:06:13 AM5/12/10
to Three20
Any update on this? This swizzling has been in the framework for quite
some time now...it's weird that they're complaining now.

Dirk Holtwick

unread,
May 12, 2010, 10:44:49 AM5/12/10
to Three20
That's really bad news... Would be great if Apple could communicate
this policy changes 'before' they reject the first apps.

I think if you comment out the TTSwapMethods body in TTGlobalCore.m
and avoid using TTNavigator it should be fine:

void TTSwapMethods(Class cls, SEL originalSel, SEL newSel) {
/*
Method originalMethod = class_getInstanceMethod(cls, originalSel);
Method newMethod = class_getInstanceMethod(cls, newSel);
method_exchangeImplementations(originalMethod, newMethod);
*/
}

Dirk

---

holtwick.it

Joe D'Andrea

unread,
May 12, 2010, 10:50:07 AM5/12/10
to Three20


On May 12, 10:44 am, Dirk Holtwick <dirk.holtw...@gmail.com> wrote:

> I think if you comment out the TTSwapMethods body in TTGlobalCore.m
> and avoid using TTNavigator it should be fine:

Yep, avoiding TTNavigator should do the trick. That looks to be the
only component that uses TTSwapMethods.

After that, Dead-Code Stripping should do the rest.

http://developer.apple.com/iphone/library/documentation/DeveloperTools/Conceptual/XcodeBuildSystem/500-Linking/bs_linking.html

- Joe

Ian Chia

unread,
May 13, 2010, 2:06:57 AM5/13/10
to Three20
What if your app relies heavily on TTNavigator (as mine that I'm about
to submit does)? Eeek ... any recommendations as a workaround? Surely
avoiding TTNavigator would impact a big number of apps in development
and in the App Store?

Many thanks,

- Ian

On May 13, 12:50 am, "Joe D'Andrea" <jdand...@gmail.com> wrote:
> On May 12, 10:44 am, Dirk Holtwick <dirk.holtw...@gmail.com> wrote:
>
> > I think if you comment out the TTSwapMethods body in TTGlobalCore.m
> > and avoid using TTNavigator it should be fine:
>
> Yep, avoiding TTNavigator should do the trick. That looks to be the
> only component that uses TTSwapMethods.
>
> After that, Dead-Code Stripping should do the rest.
>
> http://developer.apple.com/iphone/library/documentation/DeveloperTool...

Blake Watters

unread,
May 13, 2010, 9:42:41 AM5/13/10
to thr...@googlegroups.com
Avoiding TTNavigator and URL dispatch is not a viable solution for any real app leveraging Three20. We're going to need a fix that eliminates the method swizzling and makes the Apple gatekeepers happy. It's not immediately obvious to me how to avoid the swizzle without introducing heavy violations of DRYness.
Blake Watters
Two Toasters | CTO

Joe D'Andrea

unread,
May 13, 2010, 10:16:08 AM5/13/10
to Three20


On May 13, 9:42 am, Blake Watters <bl...@twotoasters.com> wrote:
> Avoiding TTNavigator and URL dispatch is not a viable solution for any real
> app leveraging Three20.

With all respect, I'm sure there are "real apps" that leverage Three20
without using TTNavigator and URL dispatch.

For example, if they simply have no need for navigation and URL
dispatch! Or they just use a subset of functionality.

Still, I recognize that there may be more Three20 apps using
TTNavigator than not.

> We're going to need a fix that eliminates the method
> swizzling and makes the Apple gatekeepers happy. It's not immediately
> obvious to me how to avoid the swizzle without introducing heavy violations
> of DRYness.

Agreed. :\

Robert Rasmussen

unread,
May 13, 2010, 10:19:47 AM5/13/10
to thr...@googlegroups.com
I have a decent solution for replacing the ttdealloc swizzle: I'm using an NSProxy subclass to wrap controllers cached by TTURLMap, and I've moved the ttdealloc code to the proxy's dealloc. 

Working around popViewController is a bigger pain. I don't use any custom transitions, so the quick fix was to just remove the TTSwapMethods call.

Stephan Diederich

unread,
May 12, 2010, 11:34:54 AM5/12/10
to thr...@googlegroups.com
On Wed, May 12, 2010 at 4:44 PM, Dirk Holtwick <dirk.h...@gmail.com> wrote:
> That's really bad news... Would be great if Apple could communicate
> this policy changes 'before' they reject the first apps.
>
> I think if you comment out the TTSwapMethods body in TTGlobalCore.m
> and avoid using TTNavigator it should be fine:

[snip]

from skimming through the code, this seems twofold:

1) swizzling for popViewController in UINavigationController is there
to be able to undo custom transitions.
-> don't use custom transitions and remove the swizzling
Another options might be to subclass UINavigationController, but I'm
not really sure about that, as Apple explicitly states
UINavigationController should not be subclassed
(http://developer.apple.com/iphone/library/documentation/UIKit/Reference/UINavigationController_Class/Reference/Reference.html)

2) swizzling of dealloc to ttdealloc in UIViewController
This seems to be necessary for caching of viewcontrollers. Maybe
TTNavigator navigation should only be allowed with TTViewControllers
and then those can do the unregister thingy.

other options?

cheers,
stephan

Stephan Diederich

unread,
May 13, 2010, 11:23:26 AM5/13/10
to thr...@googlegroups.com
On Thu, May 13, 2010 at 4:19 PM, Robert Rasmussen <rob.ra...@gmail.com> wrote:
I have a decent solution for replacing the ttdealloc swizzle: I'm using an NSProxy subclass to wrap controllers cached by TTURLMap, and I've moved the ttdealloc code to the proxy's dealloc. 

Thanks for sharing this idea on IRC!
Here's what I came up with codewise:

That's what you had in mind?
 
Working around popViewController is a bigger pain. I don't use any custom transitions, so the quick fix was to just remove the TTSwapMethods call.

same here, I've just commented the TTSwapMethod calls. Additionally, just to make this feel somehow better, I've added an assertion that triggers if custom animations are used:

cheers,
stephan

Robert Rasmussen

unread,
May 13, 2010, 7:21:38 PM5/13/10
to thr...@googlegroups.com
On May 13, 2010, at 10:23 AM, Stephan Diederich wrote:



On Thu, May 13, 2010 at 4:19 PM, Robert Rasmussen <rob.ra...@gmail.com> wrote:
I have a decent solution for replacing the ttdealloc swizzle: I'm using an NSProxy subclass to wrap controllers cached by TTURLMap, and I've moved the ttdealloc code to the proxy's dealloc. 

Thanks for sharing this idea on IRC!
Here's what I came up with codewise:

That's what you had in mind?

Yeah, pretty close but unfortunately it doesn't work. After looking at it some more, you'd have to wrap every controller that comes through TTNavigator (or that ever sets its superController or popupViewController) because of the caches set up in UIViewControllerAdditions.m.

I'm just going to change TTViewController to do the right thing for now and change the -dealloc method in the few controllers I have that don't inherit from it.


Drew McAuliffe

unread,
May 13, 2010, 7:23:15 PM5/13/10
to thr...@googlegroups.com
I hate to ask a stupid question, but is this an issue for current 3.x development, or strictly for things being submitted for 4.0 approval? I've got a couple of apps submitting this week that have me worried.

Thanks,
Drew

Robert Rasmussen

unread,
May 13, 2010, 7:28:47 PM5/13/10
to thr...@googlegroups.com
On May 13, 2010, at 6:23 PM, Drew McAuliffe wrote:

I hate to ask a stupid question, but is this an issue for current 3.x development, or strictly for things being submitted for 4.0 approval? I've got a couple of apps submitting this week that have me worried.

I'm in the same boat. The wording (emphasis added) was

"Your application, xxx, *currently posted to the App Store* is using method_exchangeImplementations to exchange the implementation of Apple provided APIs with your own implementations."

so this doesn't sound like just a 4.0 thing.

uprise78

unread,
May 13, 2010, 10:08:08 PM5/13/10
to Three20
You can't submit an app with a beta OS man...


On May 13, 4:23 pm, Drew McAuliffe <drew...@gmail.com> wrote:
> I hate to ask a stupid question, but is this an issue for current 3.x development, or strictly for things being submitted for 4.0 approval? I've got a couple of apps submitting this week that have me worried.
>
> Thanks,
> Drew
> On May 13, 2010, at 4:21 PM, Robert Rasmussen wrote:
>
>
>
>
>
> > On May 13, 2010, at 10:23 AM, Stephan Diederich wrote:
>
> >> On Thu, May 13, 2010 at 4:19 PM, Robert Rasmussen <rob.rasmus...@gmail.com> wrote:
> >> I have a decent solution for replacing the ttdealloc swizzle: I'm using an NSProxy subclass to wrap controllers cached by TTURLMap, and I've moved the ttdealloc code to the proxy's dealloc.
>
> >> Thanks for sharing this idea on IRC!
> >> Here's what I came up with codewise:
> >>http://github.com/diederich/three20/commit/1eb2f8fcc7f7ac749b278701ee...
>
> >> That's what you had in mind?
>
> > Yeah, pretty close but unfortunately it doesn't work. After looking at it some more, you'd have to wrap every controller that comes through TTNavigator (or that ever sets its superController or popupViewController) because of the caches set up in UIViewControllerAdditions.m.
>
> > I'm just going to change TTViewController to do the right thing for now and change the -dealloc method in the few controllers I have that don't inherit from it.
>
> > --
> > You received this message because you are subscribed to the Google Groups "Three20" group.
> > To post to this group, send email to thr...@googlegroups.com.
> > To unsubscribe from this group, send email to three20+u...@googlegroups.com.
> > For more options, visit this group athttp://groups.google.com/group/three20?hl=en.
>
> --
> You received this message because you are subscribed to the Google Groups "Three20" group.
> To post to this group, send email to thr...@googlegroups.com.
> To unsubscribe from this group, send email to three20+u...@googlegroups.com.
> For more options, visit this group athttp://groups.google.com/group/three20?hl=en.

Drew McAuliffe

unread,
May 13, 2010, 10:38:36 PM5/13/10
to thr...@googlegroups.com
Um, that's exactly what happened a couple of months ago with 3.2....

I was hoping this was a similar situation with 4.0.

Stephan Diederich

unread,
May 14, 2010, 7:42:20 AM5/14/10
to thr...@googlegroups.com
On Fri, May 14, 2010 at 1:21 AM, Robert Rasmussen
<rob.ra...@gmail.com> wrote:
> On May 13, 2010, at 10:23 AM, Stephan Diederich wrote:
>
>
> On Thu, May 13, 2010 at 4:19 PM, Robert Rasmussen <rob.ra...@gmail.com>
> wrote:
>>
>> I have a decent solution for replacing the ttdealloc swizzle: I'm using an
>> NSProxy subclass to wrap controllers cached by TTURLMap, and I've moved the
>> ttdealloc code to the proxy's dealloc.
>
> Thanks for sharing this idea on IRC!
> Here's what I came up with codewise:
> http://github.com/diederich/three20/commit/1eb2f8fcc7f7ac749b278701ee37bcd51bfb8536
> That's what you had in mind?
>
> Yeah, pretty close but unfortunately it doesn't work. After looking at it
> some more, you'd have to wrap every controller that comes through
> TTNavigator (or that ever sets its superController or popupViewController)
> because of the caches set up in UIViewControllerAdditions.m.

Not sure I can follow.
Let me try to explain how far I got:
The VC cache (_objectMappings in TTURLMap) can be filled from
'outside' through setObject:forURL but then the user is responsible
for removing it from the cache later.
VCs created by TTURLMap itself can be wrapped in a NSProxy, which
handles the removal in its dealloc.
Mind elaborating how VCs can be added to the cache besides that, or
where the problem actually is?

Btw, there was (at least) one bug in the last version, where the
NSProxy was created even for objects already in the cache.
revised version:
http://github.com/diederich/three20/commit/ceee37fe128936537154cfd760d8a06f51913d80

> I'm just going to change TTViewController to do the right thing for now and
> change the -dealloc method in the few controllers I have that don't inherit
> from it.

Here's what I came up for this idea:
http://github.com/diederich/three20/commit/037f68c0197a081ea3f19015450a50b6d031abd6

cheers,
stephan

p.s.: robert, do you have a public repo where you commit this stuff to?

Robert Rasmussen

unread,
May 14, 2010, 12:21:21 PM5/14/10
to thr...@googlegroups.com
There are two more non-retaining dictionaries (gSuperControllers and gPopupViewControllers) in UIViewAdditions.m that hold references to controllers, so they both need to be cleaned up, too. That's the purpose of the last few lines of ttdealloc, and it applies to all controllers and not just the shared controllers that get cached internally inside objectForURL:query:pattern.

So, while we could wrap pretty much everything that gets created in TTURLMap and TTNavigator, anyone who calls setSuperController with an unwrapped controller is going to eventually end up with a pointer to a freed object in gSuperControllers and TTNavigator will blow up trying to walk up the superController chain.

robert

Stephan Diederich

unread,
May 14, 2010, 12:59:21 PM5/14/10
to thr...@googlegroups.com
On Fri, May 14, 2010 at 6:21 PM, Robert Rasmussen
<rob.ra...@gmail.com> wrote:
> There are two more non-retaining dictionaries (gSuperControllers and gPopupViewControllers) in UIViewAdditions.m that hold references to controllers, so they both need to be cleaned up, too. That's the purpose of the last few lines of ttdealloc, and it applies to all controllers and not just the shared controllers that get cached internally inside objectForURL:query:pattern.
>
> So, while we could wrap pretty much everything that gets created in TTURLMap and TTNavigator, anyone who calls setSuperController with an unwrapped controller is going to eventually end up with a pointer to a freed object in gSuperControllers and TTNavigator will blow up trying to walk up the superController chain.

Thanks Robert for the detailed explanation!

Any ideas how this can be solved? (besides the workarounds we've already seen)

Actually I must say I don't get Apple's reasons behind forbidding
swizzling of dealloc. It's not like that method will go away and
things will break.
Maybe opening a thread on the devforums to clarify things would help...

cheers,
stephan

Romain

unread,
May 15, 2010, 10:58:33 AM5/15/10
to Three20
Can you please be strictly clear about what is impacted by this
issue ?
1) is TTNavigator present in the whole framework ?
2) Sorry for this question, but what is URL dispatch and why is it
concerned with this issue ?
Cheers,
Romain
On May 14, 6:59 pm, Stephan Diederich
<stephan.dieder...@googlemail.com> wrote:
> On Fri, May 14, 2010 at 6:21 PM, Robert Rasmussen
>
Reply all
Reply to author
Forward
0 new messages