Animations bound to array values causing EXC_BAD_ACCESS - swiftui

I have a swiftUI view that has a number of animations which are bound to an array of structs. When I test the app on my phone I keep getting EXC_BAD_ACCESS. This is what the top of the backtrace looks like:
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=2, address=0x16f7cfff0)
frame #0: 0x00000001892665c8 SwiftUI`SwiftUI.DefaultCombiningAnimator.value(in: τ_0_0.Value, for: Swift.Double) -> Swift.Optional<τ_0_0.Value> + 48
frame #1: 0x00000001892fac40 SwiftUI`SwiftUI.AnimatorBox.value(in: τ_0_0.Value, for: Swift.Double) -> Swift.Optional<τ_0_0.Value> + 168
frame #2: 0x0000000189264a28 SwiftUI`SwiftUI.AnyAnimator.value(in: τ_0_0, for: Swift.Double) -> Swift.Optional<τ_0_0> + 156
frame #3: 0x0000000189266898 SwiftUI`SwiftUI.DefaultCombiningAnimator.value(in: τ_0_0.Value, for: Swift.Double) -> Swift.Optional<τ_0_0.Value> + 768
frame #4: 0x00000001892fac40 SwiftUI`SwiftUI.AnimatorBox.value(in: τ_0_0.Value, for: Swift.Double) -> Swift.Optional<τ_0_0.Value> + 168
frame #5: 0x0000000189264a28 SwiftUI`SwiftUI.AnyAnimator.value(in: τ_0_0, for: Swift.Double) -> Swift.Optional<τ_0_0> + 156
frame #6: 0x0000000189266898 SwiftUI`SwiftUI.DefaultCombiningAnimator.value(in: τ_0_0.Value, for: Swift.Double) -> Swift.Optional<τ_0_0.Value> + 768
frame #7: 0x00000001892fac40 SwiftUI`SwiftUI.AnimatorBox.value(in: τ_0_0.Value, for: Swift.Double) -> Swift.Optional<τ_0_0.Value> + 168
frame #8: 0x0000000189264a28 SwiftUI`SwiftUI.AnyAnimator.value(in: τ_0_0, for: Swift.Double) -> Swift.Optional<τ_0_0> + 156
The previous 4000 frames all repeat the same sequence of AnyAnimator / AnimatorBox / DefaultCombiningAnimator. The only difference I can see is that in frame #0 the DefaultCombiningAnimator ends in '-> Swift.Optional<τ_0_0.Value> + 48' instead of '+ 768'.
Can anyone give me a clue as to what (if anything) this is telling me. The underlying array is constantly updated but remains a fixed size with no appends or deletions.
This is the animated view element:
ZStack {
//MARK: - Fret Cents Label
NoteLabel()
.fill(activeFret == thisFret ? .white : intonationModel.gString[thisFret].hasBeenSet ? .black : .gray)
.opacity(0.8)
.shadow(color: .black, radius: 4, x: 0, y: 3)
VStack(spacing: 0) {
Text(String(format: "%.1f", cents))
.font(Font.custom("Karantina-Regular", size: scaleHeight * 0.06))
.foregroundColor(activeFret == thisFret ? .black : .white)
}
}
.frame(width: width * 0.9 , height: scaleHeight * 0.1)
.position(x: width * 0.6, y: scaleHeight * 0.5)
.offset(y: yScaleCents * abs(cents) <= 10 ?
scaleHeight * (yScaleCents * 0.05 * -cents) :
scaleHeight * 0.5 * -(abs(cents) / cents))
.animation(.easeInOut(duration: 0.2), value: cents)
This is where it is called in the parent view:
ForEach($intonationModel.gString.indices, id: \.self) { index in
let columnWidth = fretWidth + (120 / (CGFloat(index + 1) * 4))
if index > 0 {
VStack(spacing: 0) {
IntonatorChartColumn(
thisFret: index,
scaleHeight: scaleHeight,
scaleMargin: scaleMargin,
fretboardHeight: fretboardHeight,
fretLabelHeight: fretLabelHeight,
yScaleCents: self.yScaleCents,
stringGap: stringGap,
showFretboard: $showFretboard,
cents: $intonationModel.gString[index].cents,
note: $intonationModel.gString[index].closestNote,
octave: $intonationModel.gString[index].octave,
activeFret: $intonationModel.currentFret
)
.frame(width: columnWidth)
.id(index)
}
.padding(.top, topMargin)
}
}
The app is refusing to crash when I'm looking for zombies, even though it will reliably crash when not being monitored. I'll have a go at re-working my code to avoid the use of indices (as advised by jnpdx).

I believe there were two things going on here.
It seems like the view with the animations was updating even when it was in the background. Ensuring the published variables only updated when the view was in the foreground stopped the crashing.
The incorrect use of ForEach which I've changed to the following:
ForEach(Array(zip(intonationEngine.gString.indices, intonationEngine.gString)) , id: \.0) {index, note in
Since doing this the crashes have stopped.

Related

SwiftUI Charts - Plotting Hours and Minutes on the y axis

I'm plotting sunrise - date against time, and it works but not perfectly.
How do I plot Hours and Minutes on the y axis, as a compound time.
If I just plots hours I get a step chart:
Chart{
ForEach(sunriseSunset) {item in
LineMark(
x: .value("Date", item.sunrise),
y: .value("Time", (Calendar.current.dateComponents(components, from: item.sunrise).hour!))
)
}
}
Alternatively if I multiple the hours * 60 and add the minutes I get the correct curve but the intervals on the RHS are in minutes. Is there a way to express the time as hours/minutes?
Chart{
ForEach(sunriseSunset) {item in
LineMark(
x: .value("Date", item.sunrise),
y: .value("Time", ((Calendar.current.dateComponents(components, from: item.sunrise).hour!) * 60) + (Calendar.current.dateComponents(components, from: item.sunrise).minute!))
)
}
}

SwiftUI Drag & Drop - NSInternalInconsistencyException: Could not get the cell at indexPath

I have implemented drag & drop between two lists in SwiftUI. Regular drag and drops work fine when dropping it in between list items, but when I do some more advanced drag like dragging it onto the cell itself, my app crashes.
This crash happens even before I drop it (so while I am still dragging it, without releasing drop)
Has anyone occurred this crash ? Is this a SwiftUI bug or am I doing something wrong ?
I have tried removing my code blocks inside dropDestinations and yet crash still exists, so what could I be doing wrong ?
Here is the gif of the crash (crash occurs right after I drag it onto the second cell, without dropping/releasing it):
Code inside dropDestination does not even get called.
SwiftUI Code
var body2: some View {
HStack {
VStack {
Text("title-pending")
List {
ForEach(viewModel.pendingOrders) { order in
RestaurantOrderCardView(order: order) {
.background(cardBackground)
.draggable(order)
}
.listRowSeparator(.hidden)
.listRowBackground(Color.clear)
.padding(.top)
}
.listStyle(.plain)
.background(listBackground)
}
VStack {
Text("title-in-preparation")
List {
ForEach(viewModel.inPreparationOrders) { item in
RestaurantOrderCardView(order: item)
.background(cardBackground)
}
.dropDestination(for: RestaurantOrder.self) { items, offset in
guard let firstItem = items.first else { return }
withAnimation {
viewModel.dropItem(firstItem, offset: offset)
}
}
.listRowSeparator(.hidden)
.listRowBackground(Color.clear)
.padding(.top)
}
.listStyle(.plain)
.background {
if !viewModel.inPreparationOrders.isEmpty {
listBackground
}
}
.overlay {
if viewModel.inPreparationOrders.isEmpty {
RoundedRectangle(cornerRadius: 8)
.foregroundColor(!inDropArea ? .grayBackgroundColor : .grayBackgroundColor.opacity(0.25))
.ignoresSafeArea()
.dropDestination(for: RestaurantOrder.self) { items, location in
guard let firstItem = items.first else { return false }
withAnimation {
viewModel.dropItem(firstItem, offset: 0)
}
return true
} isTargeted: { inDropArea in
withAnimation {
self.inDropArea = inDropArea
}
}
}
}
}
}
}
Crash Log
2023-01-06 11:25:05.995303+0100 SimplifyStayAdmin[78761:2158775] *** Assertion failure in -[_UICollectionViewDragAndDropController _beginDragAndDropInsertingItemAtIndexPath:], _UICollectionViewDragAndDropController.m:620
2023-01-06 11:25:06.074407+0100 SimplifyStayAdmin[78761:2158775] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Could not get the cell at indexPath <NSIndexPath: 0x8846e25efd6dfbf1> {length = 2, path = 0 - 0} to start the reording portion of the Drag-and-drop'
*** First throw call stack:
(
0 CoreFoundation 0x000000018040e7c8 __exceptionPreprocess + 172
1 libobjc.A.dylib 0x0000000180051144 objc_exception_throw + 56
2 Foundation 0x0000000180b13b98 _userInfoForFileAndLine + 0
3 UIKitCore 0x0000000109a546ec -[_UICollectionViewDragAndDropController _beginDragAndDropInsertingItemAtIndexPath:] + 540
4 UIKitCore 0x0000000109a53064 -[_UICollectionViewDragAndDropController beginReorderingForItemAtIndexPath:cell:] + 204
5 UIKitCore 0x0000000109a1bad0 -[UICollectionView _beginInteractiveMovementForItemAtIndexPath:] + 196
6 UIKit 0x000000011803040c -[UICollectionViewAccessibility beginInteractiveMovementForItemAtIndexPath:] + 80
7 UIKitCore 0x0000000109a5c55c -[_UICollectionViewDragDestinationController _reorderingDisplayLinkDidTick] + 912
8 QuartzCore 0x0000000187dd04f8 _ZN2CA7Display11DisplayLink14dispatch_itemsEyyy + 808
9 QuartzCore 0x0000000187ec89a8 _ZL22display_timer_callbackP12__CFMachPortPvlS1_ + 336
10 CoreFoundation 0x000000018033ee94 __CFMachPortPerform + 172
11 CoreFoundation 0x000000018037387c __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 56
12 CoreFoundation 0x0000000180372e9c __CFRunLoopDoSource1 + 496
13 CoreFoundation 0x000000018036d43c __CFRunLoopRun + 2176
14 CoreFoundation 0x000000018036c7a4 CFRunLoopRunSpecific + 584
15 GraphicsServices 0x0000000188ff7c98 GSEventRunModal + 160
16 UIKitCore 0x000000010a1f237c -[UIApplication _run] + 868
17 UIKitCore 0x000000010a1f6374 UIApplicationMain + 124
18 SwiftUI 0x000000010e6150d4 OUTLINED_FUNCTION_51 + 496
19 SwiftUI 0x000000010e614f7c OUTLINED_FUNCTION_51 + 152
20 SwiftUI 0x000000010dd7ab60 OUTLINED_FUNCTION_10 + 88
21 SimplifyStayAdmin 0x000000010044d0c4 $s17SimplifyStayAdmin0abC3AppV5$mainyyFZ + 40
22 SimplifyStayAdmin 0x000000010044d378 main + 12
23 dyld 0x00000001080c1fa0 start_sim + 20
24 ??? 0x00000001081c9e50 0x0 + 4431060560
25 ??? 0x0869800000000000 0x0 + 606156362346397696
)
libc++abi: terminating with uncaught exception of type NSException
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Could not get the cell at indexPath <NSIndexPath: 0x8846e25efd6dfbf1> {length = 2, path = 0 - 0} to start the reording portion of the Drag-and-drop'
terminating with uncaught exception of type NSException
CoreSimulator 857.14 - Device: iPad (10th generation) (D79A0AD8-4970-4F84-A5F9-078DAFB697A3) - Runtime: iOS 16.2 (20C52) - DeviceType: iPad (10th generation)

Getting crash while going back in Navigation Stack, Not getting much out of back trace

I am getting crash while getting back from navigation stack. Basically, I was trying to migrate from NavigationView to NavigationStack.
below is the stack trace, some how not getting any hint why it's happening.
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BREAKPOINT (code=1, subcode=0x1b96d6ef8)
frame #0: 0x00000001b96d6ef8 SwiftUI`___lldb_unnamed_symbol194523 + 476
frame #1: 0x00000001b92a4c80 SwiftUI`___lldb_unnamed_symbol163702 + 176
frame #2: 0x00000001b905cd00 SwiftUI`___lldb_unnamed_symbol143411 + 7680
frame #3: 0x00000001b9058a00 SwiftUI`___lldb_unnamed_symbol143387 + 3840
frame #4: 0x00000001b9057794 SwiftUI`___lldb_unnamed_symbol143385 + 428
frame #5: 0x00000001b906bc04 SwiftUI`___lldb_unnamed_symbol143652 + 24
frame #6: 0x00000001b857f288 SwiftUI`___lldb_unnamed_symbol63520 + 28
frame #7: 0x00000001b8e2be18 SwiftUI`___lldb_unnamed_symbol128084 + 572
frame #8: 0x00000001b84aa6e0 SwiftUI`___lldb_unnamed_symbol59254 + 116
frame #9: 0x00000001b9057544 SwiftUI`___lldb_unnamed_symbol143383 + 572
frame #10: 0x00000001b93b5b30 SwiftUI`___lldb_unnamed_symbol169980 + 1644
frame #11: 0x00000001b93b5bf4 SwiftUI`___lldb_unnamed_symbol169981 + 72
frame #12: 0x00000001b6e1b274 UIKitCore`-[UINavigationController navigationTransitionView:didEndTransition:fromView:toView:] + 1564
frame #13: 0x00000001b6ecd22c UIKitCore`__49-[UINavigationController _startCustomTransition:]_block_invoke + 208
frame #14: 0x00000001b6f8185c UIKitCore`-[_UIViewControllerTransitionContext completeTransition:] + 116
frame #15: 0x00000001b74cce98 UIKitCore`__53-[_UINavigationParallaxTransition animateTransition:]_block_invoke_5 + 608
frame #16: 0x00000001b7cef1b0 UIKitCore`__UIVIEW_IS_EXECUTING_ANIMATION_COMPLETION_BLOCK__ + 36
frame #17: 0x00000001b6d9c114 UIKitCore`-[UIViewAnimationBlockDelegate _didEndBlockAnimation:finished:context:] + 636
frame #18: 0x00000001b6d9b070 UIKitCore`-[UIViewAnimationState sendDelegateAnimationDidStop:finished:] + 436
frame #19: 0x00000001b6d9a790 UIKitCore`-[UIViewAnimationState animationDidStop:finished:] + 196
frame #20: 0x00000001b6d9a8a4 UIKitCore`-[UIViewAnimationState animationDidStop:finished:] + 472
frame #21: 0x00000001b61b4ae8 QuartzCore`CA::Layer::run_animation_callbacks(void*) + 232
frame #22: 0x0000000105bb604c libdispatch.dylib`_dispatch_client_callout + 20
frame #23: 0x0000000105bc6800 libdispatch.dylib`_dispatch_main_queue_drain + 1196
frame #24: 0x0000000105bc6344 libdispatch.dylib`_dispatch_main_queue_callback_4CF + 44
frame #25: 0x00000001b4bd6a08 CoreFoundation`__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 16
frame #26: 0x00000001b4bb8368 CoreFoundation`__CFRunLoopRun + 2036
frame #27: 0x00000001b4bbd1e4 CoreFoundation`CFRunLoopRunSpecific + 612
frame #28: 0x00000001ed9dd368 GraphicsServices`GSEventRunModal + 164
frame #29: 0x00000001b706cd88 UIKitCore`-[UIApplication _run] + 888
frame #30: 0x00000001b706c9ec UIKitCore`UIApplicationMain + 340
frame #31: 0x0000000104b1fd30 MrDoc`main at AppDelegate.swift:15:7
frame #32: 0x00000001d2ee1948 dyld`start + 2504
After wasting my 2 hours, I finally got the solution so basically this crash is related to state of navigation stack. I was not providing path argument in navigation stack. It's kind of strange that it is pushing the view without it but when we pop it, the state of navigation gets corrupted and get the crash. I wish Apple team works more towards better error diagnostics for SwiftUI. Might be helpful for someone who stumble upon this error.
NavigationStack(path: $navigationCoordinator.path) { // <= missing argument
HStack(spacing: 30.0) {
ForEach(categories) { item in
Button(action: {
navigationCoordinator.path.append(item)
}) {
GeometryReader { geometry in
CategoryView(title: item.title,
image: item.image,
color: item.color,
shadowColor: item.shadowColor)
.rotation3DEffect(Angle(degrees: Double(geometry.frame(in: .global).minX - 30) / -40),
axis: (x: 0, y: 10.0, z: 0))
}
.frame(width: 240, height: 320)
}
}
}
.navigationDestination(for: Category.self, destination: { item in
IndexView()
.toolbar(.hidden, for: .tabBar)
})

CGPath not working in Swift 3 [duplicate]

This question already has an answer here:
1. CGPathMoveToPoint' is unavailable: Use move(to:transform:) 2. 'CGPathAddLineToPoint' is unavailable: Use addLine(to:transform:)
(1 answer)
Closed 6 years ago.
I am updating code for swift 3. I have created a custom path for my spritekit object that works in swift 2. However, now I get a compiler error:
Nil is not compatible with expected argument type 'Unsafe Pointer CGAffineTransform'
let offsetX = player.size.width * player.anchorPoint.x
let offsetY = player.size.height * player.anchorPoint.y
let path = CGMutablePath()
CGPathMoveToPoint(path, nil, 10 - offsetX, 16 - offsetY)
CGPathAddLineToPoint(path, nil, 10 - offsetX, 0 - offsetY)
CGPathAddLineToPoint(path, nil, 24 - offsetX, 0 - offsetY)
CGPathAddLineToPoint(path, nil, 24 - offsetX, 16 - offsetY)
CGPathAddLineToPoint(path, nil, 24 - offsetX, 16 - offsetY)
CGPathAddLineToPoint(path, nil, 28 - offsetX, 40 - offsetY)
CGPathAddLineToPoint(path, nil, 18 - offsetX, 46 - offsetY)
CGPathAddLineToPoint(path, nil, 6 - offsetX, 36 - offsetY)
CGPathAddLineToPoint(path, nil, 6 - offsetX, 18 - offsetY)
path.closeSubpath()
The error is for passing nil in the second argument when adding to the path. I attempted to pass in an unsafe pointer as so:
var tr = CGAffineTransform.identity
CGPathMoveToPoint(path, &tr, 10 - offsetX, 16 - offsetY)
....
but then got another strange error.
CGPathMoveToPoint is unavailable. Use move(to: transform:)
However, there was no move function with argument name to. There was a move(toParent: ) however.
Most of the syntaxes are changed in Swift 3, But they didn't removed any API methods(like CGPathMoveToPoint) and It's just renamed like below.
let path = CGMutablePath()
path.move(to: CGPoint(x: 10.0, y: 10.0))
path.addLine(to: CGPoint(x: 10.0, y: 10.0))

Calculate enclosing rectangle of a given aspect ratio

Given the height and the width of a rectangle of any size and an aspect ratio, how can I calculate the height and width of a minimum enclosing rectangle of the given aspect ratio?
In code, the function signature would look like this
public Size getMinimumEnclosingRectangle(Size originalRectangle, float aspectNumerator, float aspectDenomiator);
Calls to this function would look like
originalRectangle AspectRatio Result
-------------------------------------------
100x100 1:2 100x200
64x32 1:1 64x64
125x100 3:2 150x100
100x345 1:3 115x345
This may not be the best way, but the way I do this calculation is to calculate the change in aspect ratio and then base the resulting width/height calculation of of that. Here is some code to illustrate this algorithm in practice:
var sourceImages = [
{width: 100, height: 100, toAspectRatio:1/2 },
{width: 64, height: 32, toAspectRatio:1/1 },
{width: 125, height: 100, toAspectRatio:3/2 },
{width: 100, height: 345, toAspectRatio:1/3 },
{width: 345, height: 100, toAspectRatio:1/3 }
];
function calculateNewSize( sourceWidth, sourceHeight, toAspectRatio )
{
var aspectRatioChange = (sourceWidth / sourceHeight) / toAspectRatio;
var fitWidth = aspectRatioChange < 1 ? sourceHeight * toAspectRatio : sourceWidth;
var fitHeight = aspectRatioChange >= 1 ? sourceWidth / toAspectRatio : sourceHeight;
console.log('(' + aspectRatioChange + ') ' + sourceWidth + " x " + sourceHeight + " -> "
+ toAspectRatio + ' -> ' + fitWidth + ' x ' + fitHeight);
}
sourceImages.forEach(function(source) {
calculateNewSize(source.width, source.height, source.toAspectRatio);
});