tombenner / nui

Style iOS apps with a stylesheet, similar to CSS
MIT License
3.76k stars 459 forks source link

Product > Test fails due to double method swizzling #154

Open benjie opened 11 years ago

benjie commented 11 years ago

v0.3.2 installed via CocoaPods.

If I add a breakpoint to NUISettings L175 I can see when I run tests that it's ran twice. This causes an infinite loop as a swizzled method calls itself until EXC_BAD_ACCESS occurs.

Poking it in lldb I seem to be seeing two instances of the same class in memory (?!)

First time breakpoint triggers:

(lldb) po self
$0 = 0x0043a944 NUISettings
(lldb) po &instance
$1 = 0x00451ab4 [no Objective-C description available]

Second time breakpoint triggers:

(lldb) po self
$2 = 0x0abb4e64 NUISettings
(lldb) po &instance
$3 = 0x0abc8da8 [no Objective-C description available]
(lldb) po (Class)NSClassFromString(@"NUISettings")
$4 = 0x0043a944 NUISettings

This strikes me as very odd; I'm perplexed. I guess it could be an issue with cocoapods' link_with? I'm not very experienced with it.

cristianbica commented 11 years ago

It seems that during testing in [NUISettings getInstance] the NUISettings is called two times so the swizzling happens two times

intonarumori commented 9 years ago

I found that checking in NUISwizzler if the methods were already swizzled gives a safeguard against double swizzling.

Something like this:


- (void)swizzleAll
{
    if([self wasSwizzledMoveToWindow:[UIView class]])
    {
        return;
    }

...

}

- (BOOL)wasSwizzledMoveToWindow:(Class)class
{
    return [self wasSwizzled:class methodName:@"didMoveToWindow"];
}

- (BOOL)wasSwizzled:(Class)class methodName:(NSString *)methodName
{
    return [class instancesRespondToSelector:NSSelectorFromString([NSString stringWithFormat:@"%@%@", @"override_", methodName])];
}

This does not solve the singleton problems but at least the tests can be run.

phatmann commented 9 years ago

Which singleton problems are not solved? Do you want to submit a pull request with this fix? Seems very important as well as safe.

intonarumori commented 9 years ago

I was referring to https://github.com/tombenner/nui/issues/154#issuecomment-24496745

To reproduce create a project and add and initialise NUI the run some tests. Swizzling will run twice because NUISettings singleton will be instantiated twice.

I'm not completely sure whats happening but at least the double swizzling can be prevented.

Similar, related information here: http://stackoverflow.com/questions/21014843/ios-testing-dispatch-once-get-called-twice-first-in-app-second-in-test-probl

timbodeit commented 8 years ago

Can someone provide an example project to reproduce this issue?

TIEmerald commented 8 years ago

TestPorjectForNUI.zip

If you test any test Case in TestPorjectForNUITests.m it will cause a crash like this: screen shot 2016-06-23 at 3 25 56 pm

The same issues as intonarumori said, because NUISwizzler swizzle the "override_didMoveToWindow" function of a same Class twice. Which caused the deadlock.

In this project, I am using cocoapods 0.39. And in another project I am using the newest version(1.0.1) of cocoapods which seems could avoid this problem... Still checking it.....

Wenzhi commented 8 years ago

I also see this issue comes up suddenly when trying to run a UI test on a new machine. I'm using Cocoapods version 1.0.1.

Here is when the instance got created again(When I trying to set my navigation controller to be the root controller of the window): image

Here is the loop: image