hyouuu
hyouuu

Reputation: 2491

SwiftUI: Crash when calling scrollTo method with anchor: .center

Not 100% sure if it's caused by the anchor as I just removed it and haven't experienced crash so far (will report back if more crashes happens) - could someone check and help see if that could actually be where the bug is? Going to file an Apple bug as well.

My view looks like this:

var body: some View {
    ScrollViewReader { scrollProxy in
        ScrollView {
            if isShowingContent {
                LazyVStack {
                    ForEach(mo.msgMos.indices, id: \.self) { i in
                        ...
                    }
                }
            }
        }
        .onChange(of: mo.scrollToIdx) { idx in
            withAnimation {
                scrollProxy.scrollTo(targetIdx, anchor: .center)
            }
        }
    }
}

And the crash stack looks like this:

Crashed: com.apple.main-thread
0  AttributeGraph                 0x1cedce974 AGGraphGetValue + 284
1  SwiftUI                        0x1addcbe5c _ViewCache.layout.getter + 52
2  SwiftUI                        0x1addcc2f4 _ViewCache.withPlacementData<A>(_:) + 160
3  SwiftUI                        0x1addd02d0 closure #1 in IncrementalScrollable.makeTarget(at:anchor:) + 336
4  SwiftUI                        0x1addd6a9c partial apply for closure #1 in IncrementalScrollable.makeTarget(at:anchor:) + 56
5  SwiftUI                        0x1ae2241fc HostingScrollView.updateAnimationTarget(_:) + 216
6  SwiftUI                        0x1ae2245c4 HostingScrollView.bounds.didset + 188
7  SwiftUI                        0x1ae2244e8 HostingScrollView.bounds.setter + 128
8  SwiftUI                        0x1ae22444c @objc HostingScrollView.bounds.setter + 44
9  UIKitCore                      0x1aa494e4c -[UIScrollView setContentOffset:] + 804
10 UIKitCore                      0x1aa48f1e0 -[UIScrollViewScrollAnimation setProgress:] + 320
11 UIKitCore                      0x1a95094b8 -[UIAnimator _advanceAnimationsOfType:withTimestamp:] + 276
12 QuartzCore                     0x1aa8e46a4 CA::Display::DisplayLink::dispatch_items(unsigned long long, unsigned long long, unsigned long long) + 664
13 QuartzCore                     0x1aa9bb1a0 display_timer_callback(__CFMachPort*, void*, long, void*) + 280
14 CoreFoundation                 0x1a7633ce4 __CFMachPortPerform + 176
15 CoreFoundation                 0x1a7658098 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 60
16 CoreFoundation                 0x1a7657440 __CFRunLoopDoSource1 + 596
17 CoreFoundation                 0x1a7651320 __CFRunLoopRun + 2360
18 CoreFoundation                 0x1a76504bc CFRunLoopRunSpecific + 600
19 GraphicsServices               0x1be0d5820 GSEventRunModal + 164
20 UIKitCore                      0x1a9ff4734 -[UIApplication _run] + 1072
21 UIKitCore                      0x1a9ff9e10 UIApplicationMain + 168
22 Fablur                         0x102453f8c main + 12 (AppDelegate.swift:12)
23 libdyld.dylib                  0x1a7317e60 start + 4

Upvotes: 9

Views: 1772

Answers (5)

DarkDust
DarkDust

Reputation: 92384

Yet another crash reason I found was the attempt to scroll an empty scroll view. So before attempting to scroll, check your view model whether the scroll view would be empty.

Upvotes: 1

Morgz
Morgz

Reputation: 574

I've found that if you use scrollTo with anchor and it positions the contents of the scrollview to a position it wouldn't normally be able to reach through normal scrolling, then it will crash when the view is removed.

For example. Scrolling to the last view in a scrollview and using a .leading or .center position.

I've fixed this by adding a blank view to the end of my scrollview. Not ideal but works.

Upvotes: 5

Alex Giatrakis
Alex Giatrakis

Reputation: 375

Remove the withAnimation block and you'll be fine

.onChange(of: mo.scrollToIdx) { idx in
    scrollProxy.scrollTo(targetIdx, anchor: .center)
}

Upvotes: 2

nicksarno
nicksarno

Reputation: 4245

I've had very similar problems and came to the (potential) conclusion that the ScrollViewReader doesn't calculate properly because your content is in a LazyVStack and since the Lazy items don't preload... the reader doesn't know how long the scrollview actually is. This is my guess at least...

Upvotes: 1

Asperi
Asperi

Reputation: 258305

I assume it should be attached in different place

var body: some View {
    ScrollViewReader { scrollProxy in
        ScrollView {
            if isShowingContent {
                LazyVStack {
                    ForEach(mo.msgMos.indices, id: \.self) { i in
                        ...
                    }
                }
                .onChange(of: mo.scrollToIdx) { idx in
                   withAnimation {
                      scrollProxy.scrollTo(targetIdx, anchor: .center)
                   }
                }
            }
        }
    }
}

Upvotes: 1

Related Questions