zhuowei / MarzipanTool

Tools for running iOSMac apps on macOS 10.14 Beta
https://worthdoingbadly.com/iosmac/
MIT License
286 stars 12 forks source link

App crashing on +[_UIScrollerImp scrollerImpWithStyle:horizontal:replacingScrollerImp:] #1

Open colincameron opened 6 years ago

colincameron commented 6 years ago

Using an existing app that makes heavy use of table views, I was getting a crash on launch after viewDidLoad is called but before anything appears on screen. Here's the output:

2018-06-07 12:54:00.232 MyApp[16814:511918] *** Assertion failure in +[_UIScrollerImp scrollerImpWithStyle:horizontal:replacingScrollerImp:], /BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKitCore/UIKit-3698.72.5.7/_UIScrollerImp.m:114
2018-06-07 12:54:00.234 MyApp[16814:511918] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid parameter not satisfying: newScrollerStyle == _UIScrollerStyleLegacy || newScrollerStyle == _UIScrollerStyleOverlay'
*** First throw call stack:
(
    0   CoreFoundation                      0x00007fff4f7df16a __exceptionPreprocess + 197
    1   libobjc.A.dylib                     0x00007fff7b713b10 objc_exception_throw + 48
    2   CoreFoundation                      0x00007fff4f7e3050 +[NSObject(NSObject) _copyDescription] + 0
    3   Foundation                          0x00007fff51c14918 -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 194
    4   UIKitCore                           0x0000000102080520 +[_UIScrollerImp scrollerImpWithStyle:horizontal:replacingScrollerImp:] + 661
    5   UIKitCore                           0x0000000101ad5627 -[UIScrollView _updateScrollerImpsForcingReplacement:] + 778
    6   UIKitCore                           0x0000000102085aaf +[_UIScrollerImpPair _updateAllScrollerImpPairsForNewRecommendedScrollerStyle:] + 355
    7   UIKitCore                           0x0000000102085bd7 +[_UIScrollerImpPair _scrollerStyleRecommendationChanged:] + 151
    8   CoreFoundation                      0x00007fff4f782f80 __CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ + 12
    9   CoreFoundation                      0x00007fff4f782f04 ___CFXRegistrationPost_block_invoke + 63
    10  CoreFoundation                      0x00007fff4f782e7a _CFXRegistrationPost + 397
    11  CoreFoundation                      0x00007fff4f782bf6 ___CFXNotificationPost_block_invoke + 87
    12  CoreFoundation                      0x00007fff4f74be48 -[_CFXNotificationRegistrar find:object:observer:enumerator:] + 1633
    13  CoreFoundation                      0x00007fff4f74b0c9 _CFXNotificationPost + 465
    14  Foundation                          0x00007fff51b43e1f -[NSNotificationCenter postNotificationName:object:userInfo:] + 66
    15  UIKitCore                           0x0000000102085013 _UIUpdateScrollerStyleFromSystemAppearance + 220
    16  UIKitCore                           0x0000000101ada378 +[UIScrollView _updateFromSystemAppearance:] + 56
    17  UIKitCore                           0x000000010172b366 __58-[UIApplication(iOSMacSupport) _initiateIOSMacConnections]_block_invoke_2.166 + 65
    18  libdispatch.dylib                   0x00007fff7c65f0cf _dispatch_call_block_and_release + 12
    19  libdispatch.dylib                   0x00007fff7c6584d2 _dispatch_client_callout + 8
    20  libdispatch.dylib                   0x00007fff7c662f56 _dispatch_main_queue_callback_4CF + 1120
    21  CoreFoundation                      0x00007fff4f7a5dfb __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 9
    22  CoreFoundation                      0x00007fff4f770b13 __CFRunLoopRun + 2341
    23  CoreFoundation                      0x00007fff4f76ffc7 CFRunLoopRunSpecific + 463
    24  GraphicsServices                    0x00007fff6c39aa67 GSEventRunModal + 295
    25  GraphicsServices                    0x00007fff6c39a78a GSEventRun + 106
    26  UIKitCore                           0x0000000101738a8f UIApplicationMain + 159
    27  MyApp                       0x0000000100002200 main + 112
    28  libdyld.dylib                       0x00007fff7c692ee1 start + 1
    29  ???                                 0x0000000000000001 0x0 + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
2018-06-07 12:54:00.236 UIKitHostApp[16815:512223] UIKitHostAppService error: Error Domain=NSPOSIXErrorDomain Code=53 "Software caused connection abort" UserInfo={remote impersonator={
    class = ROCKForwardingProxy;
}{
    "instance information" =     {
        bundle = "NSBundle </System/Library/PrivateFrameworks/UIKitHostAppServices.framework/Versions/A/XPCServices/UIKitHostApp.xpc> (loaded)";
        class = "UIKitHostApp.UHAService";
        protocols = "{(\n    <Protocol: 0x7fffb1c6ce10>,\n    <Protocol: 0x7fffb1c6a0b0>\n)}";
    };
}}
Abort trap: 6

I removed all table views and scroll views from the main storyboard and was still seeing this error, even when there wasn't a single instance of UIScrollView in the view hierarchy.

I've managed to work around the issue by swizzling the method -[UIScrollView _updateScrollerImpsForcingReplacement:], which doesn't appear to break anything, and the app launches correctly. This also seems to allow displaying scroll indicators.

@implementation UIScrollView (Swizzling)

+ (void)load {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        Class class = [self class];

        SEL originalSelector = @selector(_updateScrollerImpsForcingReplacement:);
        SEL swizzledSelector = @selector(my_updateScrollerImpsForcingReplacement:);

        Method originalMethod = class_getInstanceMethod(class, originalSelector);
        Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);

        BOOL didAddMethod =
        class_addMethod(class,
                        originalSelector,
                        method_getImplementation(swizzledMethod),
                        method_getTypeEncoding(swizzledMethod));

        if (didAddMethod) {
            class_replaceMethod(class,
                                swizzledSelector,
                                method_getImplementation(originalMethod),
                                method_getTypeEncoding(originalMethod));
        } else {
            method_exchangeImplementations(originalMethod, swizzledMethod);
        }
    });
}

- (id) my_updateScrollerImpsForcingReplacement:(id)arg {
    return nil;
}

@end

Unfortunately without any public documentation on UIScrollerImp or -[UIScrollView _updateScrollerImpsForcingReplacement:] I can't go any further on finding a solution.

zhuowei commented 6 years ago

@colincameron When I ran into this I had to disable both scroll indicators in Storyboard, so it's good that you found a solution for keeping the indicators. Would you like to add your solution to the repo in a pull request?