Jiar / SegementSlide

Multi-tier UIScrollView nested scrolling solution. 😋😋😋
https://blog.jiar.me/2019/02/13/Multi-tier-UIScrollView-nested-scrolling-solution/
Apache License 2.0
1.31k stars 161 forks source link

App crashes: KERN_PROTECTION_FAILURE error in childScrollViewDidScroll(_:). #69

Open HyunjoonKo opened 4 years ago

HyunjoonKo commented 4 years ago

A lot of error reports came into my app's Crashlytics. Please check.

Stack trace:

Crashed: com.apple.main-thread 
EXC_BAD_ACCESS KERN_PROTECTION_FAILURE 0x000000016f9bff40
SegementSlideViewController.childScrollViewDidScroll(_:)

0  libswiftCore.dylib             0x1b411e9a4 swift_getWitnessTable + 8
1  libswiftCore.dylib             0x1b4135e10 swift::TargetProtocolConformanceDescriptor<swift::InProcess>::getWitnessTable(swift::TargetMetadata<swift::InProcess> const*) const + 424
2  libswiftCore.dylib             0x1b410a2b8 swift_dynamicCastImpl(swift::OpaqueValue*, swift::OpaqueValue*, swift::TargetMetadata<swift::InProcess> const*, swift::TargetMetadata<swift::InProcess> const*, swift::DynamicCastFlags) + 1028
3  libswiftCore.dylib             0x1b410a798 swift_dynamicCastImpl(swift::OpaqueValue*, swift::OpaqueValue*, swift::TargetMetadata<swift::InProcess> const*, swift::TargetMetadata<swift::InProcess> const*, swift::DynamicCastFlags) + 2276
4  libswiftFoundation.dylib       0x1dd50ec9c closure #1 in closure #1 in _KeyValueCodingAndObserving.observe<A>(_:options:changeHandler:) + 348
5  libswiftFoundation.dylib       0x1dd50ea38 closure #1 in _KeyValueCodingAndObserving.observe<A>(_:options:changeHandler:) + 272
6  libswiftFoundation.dylib       0x1dd591540 specialized NSKeyValueObservation.Helper._swizzle_me_observeValue(forKeyPath:of:change:context:) + 808
7  libswiftFoundation.dylib       0x1dd50e150 @objc NSKeyValueObservation.Helper._swizzle_me_observeValue(forKeyPath:of:change:context:) + 200
8  Foundation                     0x1a69f789c NSKeyValueNotifyObserver + 292
9  Foundation                     0x1a69f9924 NSKeyValueDidChange + 340
10 Foundation                     0x1a69f9398 -[NSObject(NSKeyValueObservingPrivate) _changeValueForKeys:count:maybeOldValuesDict:maybeNewValuesDict:usingBlock:] + 632
11 Foundation                     0x1a6942f60 -[NSObject(NSKeyValueObservingPrivate) _changeValueForKey:key:key:usingBlock:] + 72
12 Foundation                     0x1a69f5340 _NSSetPointValueAndNotify + 316
13 Mubeat                         0x100e1c498 SegementSlideViewController.childScrollViewDidScroll(_:) + 1369700 (<compiler-generated>:1369700)
14 Mubeat                         0x100e1ad5c closure #1 in SegementSlideViewController.segementSlideContentView(_:didSelectAtIndex:animated:) + 1363752 (<compiler-generated>:1363752)
15 Mubeat                         0x100e1c3a8 partial apply for thunk for @escaping @callee_guaranteed (@guaranteed UIScrollView, @in_guaranteed NSKeyValueObservedChange<CGPoint>) -> () + 1369460 (<compiler-generated>:1369460)
16 libswiftFoundation.dylib       0x1dd50eaf8 closure #1 in _KeyValueCodingAndObserving.observe<A>(_:options:changeHandler:) + 464
17 libswiftFoundation.dylib       0x1dd591540 specialized NSKeyValueObservation.Helper._swizzle_me_observeValue(forKeyPath:of:change:context:) + 808
18 libswiftFoundation.dylib       0x1dd50e150 @objc NSKeyValueObservation.Helper._swizzle_me_observeValue(forKeyPath:of:change:context:) + 200
19 Foundation                     0x1a69f789c NSKeyValueNotifyObserver + 292
20 Foundation                     0x1a69f9924 NSKeyValueDidChange + 340
21 Foundation                     0x1a69f9398 -[NSObject(NSKeyValueObservingPrivate) _changeValueForKeys:count:maybeOldValuesDict:maybeNewValuesDict:usingBlock:] + 632
22 Foundation                     0x1a6942f60 -[NSObject(NSKeyValueObservingPrivate) _changeValueForKey:key:key:usingBlock:] + 72
23 Foundation                     0x1a69f5340 _NSSetPointValueAndNotify + 316
24 Mubeat                         0x100e1c498 SegementSlideViewController.childScrollViewDidScroll(_:) + 1369700 (<compiler-generated>:1369700)
25 Mubeat                         0x100e1ad5c closure #1 in SegementSlideViewController.segementSlideContentView(_:didSelectAtIndex:animated:) + 1363752 (<compiler-generated>:1363752)
26 Mubeat                         0x100e1c3a8 partial apply for thunk for @escaping @callee_guaranteed (@guaranteed UIScrollView, @in_guaranteed NSKeyValueObservedChange<CGPoint>) -> () + 1369460 (<compiler-generated>:1369460)
27 libswiftFoundation.dylib       0x1dd50eaf8 closure #1 in _KeyValueCodingAndObserving.observe<A>(_:options:changeHandler:) + 464
28 libswiftFoundation.dylib       0x1dd591540 specialized NSKeyValueObservation.Helper._swizzle_me_observeValue(forKeyPath:of:change:context:) + 808
29 libswiftFoundation.dylib       0x1dd50e150 @objc NSKeyValueObservation.Helper._swizzle_me_observeValue(forKeyPath:of:change:context:) + 200
30 Foundation                     0x1a69f789c NSKeyValueNotifyObserver + 292
31 Foundation                     0x1a69f9924 NSKeyValueDidChange + 340
32 Foundation                     0x1a69f9398 -[NSObject(NSKeyValueObservingPrivate) _changeValueForKeys:count:maybeOldValuesDict:maybeNewValuesDict:usingBlock:] + 632
33 Foundation                     0x1a6942f60 -[NSObject(NSKeyValueObservingPrivate) _changeValueForKey:key:key:usingBlock:] + 72
34 Foundation                     0x1a69f5340 _NSSetPointValueAndNotify + 316
35 UIKitCore                      0x1aa938dd8 -[UITableView _restoreOrAdjustContentOffsetWithRowCount:initialContentInsetTop:] + 212
36 UIKitCore                      0x1aa928338 -[UITableView _updateVisibleCellsNow:] + 3404
37 UIKitCore                      0x1aa928364 -[UITableView _updateVisibleCellsNow:] + 3448
38 UIKitCore                      0x1aa928364 -[UITableView _updateVisibleCellsNow:] + 3448
39 UIKitCore                      0x1aa928364 -[UITableView _updateVisibleCellsNow:] + 3448
40 UIKitCore                      0x1aa928364 -[UITableView _updateVisibleCellsNow:] + 3448
41 UIKitCore                      0x1aa928364 -[UITableView _updateVisibleCellsNow:] + 3448
42 UIKitCore                      0x1aa928364 -[UITableView _updateVisibleCellsNow:] + 3448
43 UIKitCore                      0x1aa928364 -[UITableView _updateVisibleCellsNow:] + 3448
44 UIKitCore                      0x1aa928364 -[UITableView _updateVisibleCellsNow:] + 3448
45 UIKitCore                      0x1aa928364 -[UITableView _updateVisibleCellsNow:] + 3448
46 UIKitCore                      0x1aa928364 -[UITableView _updateVisibleCellsNow:] + 3448
47 UIKitCore                      0x1aa9452a8 -[UITableView layoutSubviews] + 164
48 UIKitCore                      0x1aac2b2bc -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 2160
49 QuartzCore                     0x1ad283978 -[CALayer layoutSublayers] + 292
50 QuartzCore                     0x1ad283db8 CA::Layer::layout_if_needed(CA::Transaction*) + 472
51 QuartzCore                     0x1ad29621c CA::Layer::layout_and_display_if_needed(CA::Transaction*) + 144
52 QuartzCore                     0x1ad1dae10 CA::Context::commit_transaction(CA::Transaction*, double) + 304
53 QuartzCore                     0x1ad2058c4 CA::Transaction::commit() + 684
54 QuartzCore                     0x1ad13dee4 CA::Display::DisplayLink::dispatch_items(unsigned long long, unsigned long long, unsigned long long) + 888
55 QuartzCore                     0x1ad20d5fc display_timer_callback(__CFMachPort*, void*, long, void*) + 268
56 CoreFoundation                 0x1a6582c68 __CFMachPortPerform + 176
57 CoreFoundation                 0x1a65ad3f0 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 60
58 CoreFoundation                 0x1a65aca9c __CFRunLoopDoSource1 + 448
59 CoreFoundation                 0x1a65a7630 __CFRunLoopRun + 1856
60 CoreFoundation                 0x1a65a6bc8 CFRunLoopRunSpecific + 480
61 GraphicsServices               0x1b098f5cc GSEventRunModal + 164
62 UIKitCore                      0x1aa759744 UIApplicationMain + 1936
63 Mubeat                         0x10035c7d4 main + 14 (AppDelegate.swift:14)
64 libdyld.dylib                  0x1a6423384 start + 4

in SegementSlideViewController+scroll.swift:

스크린샷 2020-09-22 오후 4 10 36
lumanmann commented 4 years ago

I have got this error too

Jiar commented 4 years ago

Thanks for your feedback!

May I ask what version of SegementSlide you used?

HyunjoonKo commented 4 years ago

@Jiar I am currently using version 3.0.1. The problem has occurred since Xcode 12 (Swift 5.3).

Jiar commented 4 years ago

@HyunjoonKo @lumanmann I run the Example under the same environment, but no problem is found. It is better to have a Demo that can reproduce the problem, otherwise it is difficult to troubleshoot the problem.

seangou commented 3 years ago

I have got the same error from Firebase Crashlytics report.

hansolnoh95 commented 3 years ago

So as I... Is there anyone who solved this problem?

HyunjoonKo commented 3 years ago

@hansolnoh95 Not yet. It does not appear in the development environment, but many reports are still reported in Crashlytics and Xcode crash reports.

HyunjoonKo commented 3 years ago

@Jiar Update information:

    internal func childScrollViewDidScroll(_ childScrollView: UIScrollView) {
        defer {
            scrollViewDidScroll(childScrollView, isParent: false)
        }
        let parentContentOffsetY = scrollView.contentOffset.y // 0.0
        let childContentOffsetY = childScrollView.contentOffset.y // 0.0
        switch innerBouncesType {
        case .parent:
            if !canChildViewScroll {
                childScrollView.contentOffset.y = 0 // Thread 1: EXC_BAD_ACCESS (code=2, address=0x16b8e3ff0)
            } else if childContentOffsetY <= 0 {
                canChildViewScroll = false
                canParentViewScroll = true
            }
        case .child:
            if !canChildViewScroll {
                childScrollView.contentOffset.y = 0
            } else if childContentOffsetY <= 0 {
                if parentContentOffsetY <= 0 {
                    canChildViewScroll = true
                }
                canParentViewScroll = true
            } else {
                if parentContentOffsetY > 0 && parentContentOffsetY < headerStickyHeight {
                    canChildViewScroll = false
                }
            }
        }
    }

The problem was solved when I tried to fix it as follows:

// ...
case .parent:
      if !canChildViewScroll, childScrollView.contentOffset.y != childContentOffsetY {
          childScrollView.contentOffset.y = 0
      } else if childContentOffsetY <= 0 {
          canChildViewScroll = false
          canParentViewScroll = true
      }
// ...
skeyboy commented 3 years ago

@Jiar Update information:

    internal func childScrollViewDidScroll(_ childScrollView: UIScrollView) {
        defer {
            scrollViewDidScroll(childScrollView, isParent: false)
        }
        let parentContentOffsetY = scrollView.contentOffset.y // 0.0
        let childContentOffsetY = childScrollView.contentOffset.y // 0.0
        switch innerBouncesType {
        case .parent:
            if !canChildViewScroll {
                childScrollView.contentOffset.y = 0 // Thread 1: EXC_BAD_ACCESS (code=2, address=0x16b8e3ff0)
            } else if childContentOffsetY <= 0 {
                canChildViewScroll = false
                canParentViewScroll = true
            }
        case .child:
            if !canChildViewScroll {
                childScrollView.contentOffset.y = 0
            } else if childContentOffsetY <= 0 {
                if parentContentOffsetY <= 0 {
                    canChildViewScroll = true
                }
                canParentViewScroll = true
            } else {
                if parentContentOffsetY > 0 && parentContentOffsetY < headerStickyHeight {
                    canChildViewScroll = false
                }
            }
        }
    }

The problem was solved when I tried to fix it as follows:

// ...
case .parent:
      if !canChildViewScroll, childScrollView.contentOffset.y != childContentOffsetY {
          childScrollView.contentOffset.y = 0
      } else if childContentOffsetY <= 0 {
          canChildViewScroll = false
          canParentViewScroll = true
      }
// ...

how can you fix it, can you share the why?

HyunjoonKo commented 3 years ago

Hi @skeyboy

You can see the fixed source code here: https://github.com/HyunjoonKo/SegementSlide/blob/customized/Source/General/SegementSlideViewController%2Bscroll.swift

Install with CocoaPods:

pod 'SegementSlide', :git => 'https://github.com/HyunjoonKo/SegementSlide.git', :branch => 'customized'

If childScrollView.contentOffset.y is 0, setting 0 again will cause a crash. I don't know why this happens. Because I don't know how to reproduce the phenomenon. I could only tell which code was the problem by looking at the crash report.