TextureGroup / Texture

Smooth asynchronous user interfaces for iOS apps.
https://texturegroup.org/
Other
8.02k stars 1.29k forks source link

XCTests using Texture/AsyncDisplayKit deadlock during initialisation when targeting iOS 15 #2029

Open benniebotha opened 3 years ago

benniebotha commented 3 years ago

While running the test, AsyncDisplayKit hangs before any tests run when iOS 15 is used as the test target. It appears to hang inside -[UIView init] which indicates there may be an issue with UIKit itself. This issue has been raised with Apple, but implementing a fix in Texture is needed in the meantime.

In AsyncDisplayKit we can see that the hang occurs in the following functions:

__attribute__((constructor)) static void ASLoadFrameworkInitializer(void)
{
  ASInitializeFrameworkMainThread();
}
void ASInitializeFrameworkMainThread(void)
{
  static dispatch_once_t onceToken;
  dispatch_once(&onceToken, ^{
    ASDisplayNodeCAssertMainThread();
    // Ensure these values are cached on the main thread before needed in the background.
    if (ASActivateExperimentalFeature(ASExperimentalLayerDefaults)) {
      // Nop. We will gather default values on-demand in ASDefaultAllowsGroupOpacity and ASDefaultAllowsEdgeAntialiasing
    } else {
      CALayer *layer = [[[UIView alloc] init] layer];
      allowsGroupOpacityFromUIKitOrNil = @(layer.allowsGroupOpacity);
      allowsEdgeAntialiasingFromUIKitOrNil = @(layer.allowsEdgeAntialiasing);
    }
    ASNotifyInitialized();
#if AS_SIGNPOST_ENABLE
    _ASInitializeSignpostObservers();
#endif
  });

It appears the hang is during the call to [[UIView alloc] init] inside the dispatch_once.

foxware00 commented 3 years ago

@benniebotha I can confirm i'm seeing the same thing. Would you be able to link to the Apple issue for tracking? Oddly I'm also seeing the same result very occasionaly running the app itself. It will freeze on a splash screen before didFinishLaunchingWithOptions is called and will prevent the app launching at all.

@nguyenhuy I don't suppose one of the team could look into this?

foxware00 commented 3 years ago

@benniebotha changing the ASInitializeFrameworkMainThread function to the following allows the tests to pass. I believe it's also the defaults fetched from the layer. I don't override this stuff in the .plist so it's an acceptable workaround for the meantime.

void ASInitializeFrameworkMainThread(void)
{
  static dispatch_once_t onceToken;
  dispatch_once(&onceToken, ^{
    ASDisplayNodeCAssertMainThread();
    // Ensure these values are cached on the main thread before needed in the background.
    if (ASActivateExperimentalFeature(ASExperimentalLayerDefaults)) {
      // Nop. We will gather default values on-demand in ASDefaultAllowsGroupOpacity and ASDefaultAllowsEdgeAntialiasing
    } else {
      allowsGroupOpacityFromUIKitOrNil = @(YES); // Use default values here instead of loading the layer
      allowsEdgeAntialiasingFromUIKitOrNil = @(NO);
    }
    ASNotifyInitialized();
#if AS_SIGNPOST_ENABLE
    _ASInitializeSignpostObservers();
#endif
  });
}
benniebotha commented 3 years ago

Thanks @foxware00 for looking into it further. The fact that it is occasionally happening outside of tests is even more concerning! I raised the issue under the dev tools feedback that is unfortunately not public. 😞 Your solution would does seem to work yes. Another work around seems to be activating the ASExperimentalLayerDefaults experiment. I haven't worked on Texture a lot, could you point me to the documentation on how these experiments work?

foxware00 commented 3 years ago

Thanks @foxware00 for looking into it further. The fact that it is occasionally happening outside of tests is even more concerning! I raised the issue under the dev tools feedback that is unfortunately not public. 😞 Your solution would does seem to work yes. Another work around seems to be activating the ASExperimentalLayerDefaults experiment. I haven't worked on Texture a lot, could you point me to the documentation on how these experiments work?

Yes it's very concerning, I can't say 100% that it's Texture during normal boot as i'm currently unable to get a spindump when it happens. However the result (freezing before the app boots without any logs) is identical to that shown when running UITests

In terms of the Experimental flags, I'm not 100% sure having not used them in the past. Which package manager are you using, you can point Cocoapods at a github fork with the changes mentioned above if it would satisfy you in the meantime?

foxware00 commented 3 years ago

@nguyenhuy I've had a response from eskimo at Apple and has indicated that the framework intialisation is at fault. He has suggested a couple of work arounds such as lazily initalizing the framework. Are you able to take a look at this and see if there is anything we can do?

https://developer.apple.com/forums//thread/689592?answerId=688696022&replyId=688696022

MikePendo commented 3 years ago

Any progress on this issue as we also experience it and we r heavy dependent on Texture. (or possible work around would )

MaximShnirman commented 3 years ago

same issue here

benniebotha commented 3 years ago

Thanks @foxware00 for raising it on the Apple forum. I got the experiment working as well as making those temporary changes in our fork. That should do for now thanks.

Hopefully it will get solved quickly on the main repo.

foxware00 commented 3 years ago

@benniebotha the solution we've aludded too seems to fix unit tests but still happens in the main app for a subset of users.

It would be good to have some weigh in from some of the authors as my knowledge of Objective-C and framework initalisers is limited.

@garrettmoon @nguyenhuy @appleguy @Adlai-Holler

foxware00 commented 3 years ago

Thanks @foxware00 for raising it on the Apple forum. I got the experiment working as well as making those temporary changes in our fork. That should do for now thanks.

Hopefully it will get solved quickly on the main repo.

@benniebotha It might be worth also rasing a compatability bug with Apple, the more people shouting the more likely they are to fix it.

GeekTree0101 commented 3 years ago

https://github.com/TextureGroup/Texture/pull/2032 I just open Pull-Request. It replace attribute from constructor to destructor for run after main on running unit test

galgord commented 3 years ago

same issue here

noambartouv commented 3 years ago

experiencing similar issue

jeffersonsetiawan commented 3 years ago

Really curious why this only/always happen in unit test but not in application itself

brandtdaniels commented 3 years ago

Really curious why this only/always happen in unit test but not in application itself

Any why only starting with iOS 15 / Xcode 13

dimanitm commented 3 years ago

Same here

MikePendo commented 2 years ago

I still don't understand how that related to the tests? Why the test got stuck even though the Texture related code wasn't invoke, (I see some dynamic invocation when loading the library I am not sure why its needed as fo example in our test cases we don't even use Texture so its kinda redundant and now causing some strange issues). Apparently I see some strange issue with cornerradius with and without that patch Ok I have looked a little bit in the code and apparently u r initializing some UI components on load time for instance here: ASInitializeFrameworkMainThread That what cause some issues on our side in general according to Apple docs u should not init any heavy object during load time (not sure why it was done that way, removing the initialization to more proper place seems to resolve the issue).

lucasromanomr commented 2 years ago

Same here

denkeni commented 2 years ago

https://github.com/TextureGroup/Texture/pull/2032 has been merged, so this issue has got fixed and could be closed. Check out the current master branch.

musakokcen commented 2 years ago

Hey! It looks like this pr https://github.com/TextureGroup/Texture/pull/2032 does not solve the issue. @foxware00 's this solution works.

christiankm commented 2 years ago

We're experiencing the same issue. Is there any way we can assist here, to resolve this?

richieshilton commented 2 years ago

Is there any update on this getting fixed in a release?