Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes a Paywall Template 7 crash when none of the tiers have any available products. #4243

Merged
merged 3 commits into from
Sep 9, 2024

Conversation

JayShortway
Copy link
Member

@JayShortway JayShortway commented Sep 5, 2024

Note

There's an equivalent Android fix here: RevenueCat/purchases-android#1834.

Bug

If a Template 7 Paywall is configured to use packages for which the products are not available, it crashes in Template7View.swift, line 74:
image

The SDK prints these logs:

ERROR: Tier 'Standard' has no available products and will be removed from the paywall.
ERROR: Tier 'Premium' has no available products and will be removed from the paywall.

After that, no tiers are left anymore, but this case isn't considered.

Stack trace
* thread #1, stop reason = Fatal error: Unexpectedly found nil while unwrapping an Optional value
  frame #0: 0x00000001891baebc libswiftCore.dylib`_swift_runtime_on_report
  frame #1: 0x0000000189241a70 libswiftCore.dylib`_swift_stdlib_reportFatalErrorInFile + 204
  frame #2: 0x0000000188f00cb4 libswiftCore.dylib`closure #1 (Swift.UnsafeBufferPointer<Swift.UInt8>) -> () in closure #1 (Swift.UnsafeBufferPointer<Swift.UInt8>) -> () in closure #1 (Swift.UnsafeBufferPointer<Swift.UInt8>) -> () in Swift._assertionFailure(_: Swift.StaticString, _: Swift.StaticString, file: Swift.StaticString, line: Swift.UInt, flags: Swift.UInt32) -> Swift.Never + 356
  frame #3: 0x0000000188f00a1c libswiftCore.dylib`closure #1 (Swift.UnsafeBufferPointer<Swift.UInt8>) -> () in closure #1 (Swift.UnsafeBufferPointer<Swift.UInt8>) -> () in Swift._assertionFailure(_: Swift.StaticString, _: Swift.StaticString, file: Swift.StaticString, line: Swift.UInt, flags: Swift.UInt32) -> Swift.Never + 192
  frame #4: 0x0000000188f003bc libswiftCore.dylib`Swift._assertionFailure(_: Swift.StaticString, _: Swift.StaticString, file: Swift.StaticString, line: Swift.UInt, flags: Swift.UInt32) -> Swift.Never + 228
* frame #5: 0x00000001016ad408 purchases-kmp Sample`Template7View.init(configuration=RevenueCatUI.TemplateViewConfiguration @ 0x000000016eef8820) at Template7View.swift:74:72
  frame #6: 0x000000010174b838 purchases-kmp Sample`static PaywallData.createView(template=<unavailable>, configuration=<unavailable>, self=RevenueCat.PaywallData) at TemplateViewType.swift:136:13
  frame #7: 0x000000010174a274 purchases-kmp Sample`PaywallData.createView(offering=<unavailable>, template=<unavailable>, configuration=<unavailable>, introEligibility=<unavailable>, self=<unavailable>) at TemplateViewType.swift:74:18
  frame #8: 0x00000001013f2a1c purchases-kmp Sample`LoadedOfferingPaywallView.content.getter(self=<unavailable>) at PaywallView.swift:445:14
  frame #9: 0x00000001013f1ccc purchases-kmp Sample`LoadedOfferingPaywallView.body.getter(self=<unavailable>) at PaywallView.swift:417:14
  frame #10: 0x00000001013f84e8 purchases-kmp Sample`protocol witness for View.body.getter in conformance LoadedOfferingPaywallView at <compiler-generated>:0
  frame #11: 0x000000018bde6780 SwiftUI`partial apply forwarder for closure #1 () -> τ_0_0.Body in SwiftUI.ViewBodyAccessor.updateBody(of: τ_0_0, changed: Swift.Bool) -> () + 28
  frame #12: 0x000000018bdd1614 SwiftUI`closure #1 () -> τ_0_0.Body in SwiftUI.BodyAccessor.setBody(() -> τ_0_0.Body) -> () + 44
  frame #13: 0x000000018bdbcd00 SwiftUI`SwiftUI.ViewBodyAccessor.updateBody(of: τ_0_0, changed: Swift.Bool) -> () + 1464
  frame #14: 0x000000018bddde38 SwiftUI`SwiftUI.DynamicBody.updateValue() -> () + 560
  frame #15: 0x000000018be1b87c SwiftUI`partial apply forwarder for implicit closure #2 (Swift.UnsafeMutableRawPointer, __C.AGAttribute) -> () in implicit closure #1 (τ_1_0.Type) -> (Swift.UnsafeMutableRawPointer, __C.AGAttribute) -> () in closure #1 () -> (Swift.UnsafeMutableRawPointer, __C.AGAttribute) -> () in closure #1 (Swift.UnsafePointer<τ_1_0>) -> AttributeGraph.Attribute<τ_0_0> in AttributeGraph.Attribute.init<τ_0_0 where τ_0_0 == τ_1_0.Value, τ_1_0: AttributeGraph.StatefulRule>(τ_1_0) -> AttributeGraph.Attribute<τ_0_0> + 28
  frame #16: 0x00000001b90dc114 AttributeGraph`AG::Graph::UpdateStack::update() + 516
  frame #17: 0x00000001b90db880 AttributeGraph`AG::Graph::update_attribute(AG::data::ptr<AG::Node>, unsigned int) + 392
  frame #18: 0x00000001b90dc8d8 AttributeGraph`AG::Graph::input_value_ref_slow(AG::data::ptr<AG::Node>, AG::AttributeID, unsigned int, AGSwiftMetadata const*, unsigned char&, long) + 544
  frame #19: 0x00000001b90da2e4 AttributeGraph`AGGraphGetValue + 236
  frame #20: 0x000000018bdd13d4 SwiftUI`SwiftUI._ConditionalContent< where τ_0_0: SwiftUI.View, τ_0_1: SwiftUI.View>.ChildView.content.getter : SwiftUI._ConditionalContent<τ_0_0, τ_0_1> + 76
  frame #21: 0x000000018bde935c SwiftUI`SwiftUI._ConditionalContent< where τ_0_0: SwiftUI.View, τ_0_1: SwiftUI.View>.ChildView.value.getter : SwiftUI.AnyView + 380
  frame #22: 0x000000018be6621c SwiftUI`protocol witness for AttributeGraph.Rule.value.getter : τ_0_0.Value in conformance SwiftUI._ConditionalContent<τ_0_0, τ_0_1>< where τ_0_0: SwiftUI.View, τ_0_1: SwiftUI.View>.ChildView : AttributeGraph.Rule in SwiftUI + 40
  frame #23: 0x000000018bdeb384 SwiftUI`implicit closure #2 (Swift.UnsafeMutableRawPointer, __C.AGAttribute) -> () in implicit closure #1 (τ_1_0.Type) -> (Swift.UnsafeMutableRawPointer, __C.AGAttribute) -> () in closure #1 () -> (Swift.UnsafeMutableRawPointer, __C.AGAttribute) -> () in closure #1 (Swift.UnsafePointer<τ_1_0>) -> AttributeGraph.Attribute<τ_0_0> in AttributeGraph.Attribute.init<τ_0_0 where τ_0_0 == τ_1_0.Value, τ_1_0: AttributeGraph.Rule>(τ_1_0) -> AttributeGraph.Attribute<τ_0_0> + 160
  frame #24: 0x00000001b90dc114 AttributeGraph`AG::Graph::UpdateStack::update() + 516
  frame #25: 0x00000001b90db880 AttributeGraph`AG::Graph::update_attribute(AG::data::ptr<AG::Node>, unsigned int) + 392
  frame #26: 0x00000001b90dc8d8 AttributeGraph`AG::Graph::input_value_ref_slow(AG::data::ptr<AG::Node>, AG::AttributeID, unsigned int, AGSwiftMetadata const*, unsigned char&, long) + 544
  frame #27: 0x00000001b90da2e4 AttributeGraph`AGGraphGetValue + 236
  frame #28: 0x000000018be30f9c SwiftUI`SwiftUI.AnyViewList.updateValue() -> () + 76
  frame #29: 0x000000018bef630c SwiftUI`partial apply forwarder for generic specialization <SwiftUI.ViewList, SwiftUI.AnyViewList> of implicit closure #2 (Swift.UnsafeMutableRawPointer, __C.AGAttribute) -> () in implicit closure #1 (τ_1_0.Type) -> (Swift.UnsafeMutableRawPointer, __C.AGAttribute) -> () in closure #1 () -> (Swift.UnsafeMutableRawPointer, __C.AGAttribute) -> () in closure #1 (Swift.UnsafePointer<τ_1_0>) -> AttributeGraph.Attribute<τ_0_0> in AttributeGraph.Attribute.init<τ_0_0 where τ_0_0 == τ_1_0.Value, τ_1_0: AttributeGraph.StatefulRule>(τ_1_0) -> AttributeGraph.Attribute<τ_0_0> + 20
  frame #30: 0x00000001b90dc114 AttributeGraph`AG::Graph::UpdateStack::update() + 516
  frame #31: 0x00000001b90db880 AttributeGraph`AG::Graph::update_attribute(AG::data::ptr<AG::Node>, unsigned int) + 392
  frame #32: 0x00000001b90dc8d8 AttributeGraph`AG::Graph::input_value_ref_slow(AG::data::ptr<AG::Node>, AG::AttributeID, unsigned int, AGSwiftMetadata const*, unsigned char&, long) + 544
  frame #33: 0x00000001b90da2e4 AttributeGraph`AGGraphGetValue + 236
  frame #34: 0x000000018be65f14 SwiftUI`generic specialization <SwiftUI.ViewList, SwiftUI._ViewListOutputs.ApplyModifiers> of implicit closure #2 (Swift.UnsafeMutableRawPointer, __C.AGAttribute) -> () in implicit closure #1 (τ_1_0.Type) -> (Swift.UnsafeMutableRawPointer, __C.AGAttribute) -> () in closure #1 () -> (Swift.UnsafeMutableRawPointer, __C.AGAttribute) -> () in closure #1 (Swift.UnsafePointer<τ_1_0>) -> AttributeGraph.Attribute<τ_0_0> in AttributeGraph.Attribute.init<τ_0_0 where τ_0_0 == τ_1_0.Value, τ_1_0: AttributeGraph.Rule>(τ_1_0) -> AttributeGraph.Attribute<τ_0_0> + 124
  frame #35: 0x00000001b90dc114 AttributeGraph`AG::Graph::UpdateStack::update() + 516
  frame #36: 0x00000001b90db880 AttributeGraph`AG::Graph::update_attribute(AG::data::ptr<AG::Node>, unsigned int) + 392
  frame #37: 0x00000001b90dc8d8 AttributeGraph`AG::Graph::input_value_ref_slow(AG::data::ptr<AG::Node>, AG::AttributeID, unsigned int, AGSwiftMetadata const*, unsigned char&, long) + 544
  frame #38: 0x00000001b90da2e4 AttributeGraph`AGGraphGetValue + 236
  frame #39: 0x000000018bddffdc SwiftUI`SwiftUI.AnyViewList.Item.list.getter : SwiftUI.ViewList + 120
  frame #40: 0x000000018be31104 SwiftUI`SwiftUI.AnyViewList.updateValue() -> () + 436
  frame #41: 0x000000018bef630c SwiftUI`partial apply forwarder for generic specialization <SwiftUI.ViewList, SwiftUI.AnyViewList> of implicit closure #2 (Swift.UnsafeMutableRawPointer, __C.AGAttribute) -> () in implicit closure #1 (τ_1_0.Type) -> (Swift.UnsafeMutableRawPointer, __C.AGAttribute) -> () in closure #1 () -> (Swift.UnsafeMutableRawPointer, __C.AGAttribute) -> () in closure #1 (Swift.UnsafePointer<τ_1_0>) -> AttributeGraph.Attribute<τ_0_0> in AttributeGraph.Attribute.init<τ_0_0 where τ_0_0 == τ_1_0.Value, τ_1_0: AttributeGraph.StatefulRule>(τ_1_0) -> AttributeGraph.Attribute<τ_0_0> + 20
  frame #42: 0x00000001b90dc114 AttributeGraph`AG::Graph::UpdateStack::update() + 516
  frame #43: 0x00000001b90db880 AttributeGraph`AG::Graph::update_attribute(AG::data::ptr<AG::Node>, unsigned int) + 392
  frame #44: 0x00000001b90dc8d8 AttributeGraph`AG::Graph::input_value_ref_slow(AG::data::ptr<AG::Node>, AG::AttributeID, unsigned int, AGSwiftMetadata const*, unsigned char&, long) + 544
  frame #45: 0x00000001b90da2e4 AttributeGraph`AGGraphGetValue + 236
  frame #46: 0x000000018bddffdc SwiftUI`SwiftUI.AnyViewList.Item.list.getter : SwiftUI.ViewList + 120
  frame #47: 0x000000018be31104 SwiftUI`SwiftUI.AnyViewList.updateValue() -> () + 436
  frame #48: 0x000000018bef630c SwiftUI`partial apply forwarder for generic specialization <SwiftUI.ViewList, SwiftUI.AnyViewList> of implicit closure #2 (Swift.UnsafeMutableRawPointer, __C.AGAttribute) -> () in implicit closure #1 (τ_1_0.Type) -> (Swift.UnsafeMutableRawPointer, __C.AGAttribute) -> () in closure #1 () -> (Swift.UnsafeMutableRawPointer, __C.AGAttribute) -> () in closure #1 (Swift.UnsafePointer<τ_1_0>) -> AttributeGraph.Attribute<τ_0_0> in AttributeGraph.Attribute.init<τ_0_0 where τ_0_0 == τ_1_0.Value, τ_1_0: AttributeGraph.StatefulRule>(τ_1_0) -> AttributeGraph.Attribute<τ_0_0> + 20
  frame #49: 0x00000001b90dc114 AttributeGraph`AG::Graph::UpdateStack::update() + 516
  frame #50: 0x00000001b90db880 AttributeGraph`AG::Graph::update_attribute(AG::data::ptr<AG::Node>, unsigned int) + 392
  frame #51: 0x00000001b90dc8d8 AttributeGraph`AG::Graph::input_value_ref_slow(AG::data::ptr<AG::Node>, AG::AttributeID, unsigned int, AGSwiftMetadata const*, unsigned char&, long) + 544
  frame #52: 0x00000001b90da2e4 AttributeGraph`AGGraphGetValue + 236
  frame #53: 0x000000018bddffdc SwiftUI`SwiftUI.AnyViewList.Item.list.getter : SwiftUI.ViewList + 120
  frame #54: 0x000000018be31104 SwiftUI`SwiftUI.AnyViewList.updateValue() -> () + 436
  frame #55: 0x000000018bef630c SwiftUI`partial apply forwarder for generic specialization <SwiftUI.ViewList, SwiftUI.AnyViewList> of implicit closure #2 (Swift.UnsafeMutableRawPointer, __C.AGAttribute) -> () in implicit closure #1 (τ_1_0.Type) -> (Swift.UnsafeMutableRawPointer, __C.AGAttribute) -> () in closure #1 () -> (Swift.UnsafeMutableRawPointer, __C.AGAttribute) -> () in closure #1 (Swift.UnsafePointer<τ_1_0>) -> AttributeGraph.Attribute<τ_0_0> in AttributeGraph.Attribute.init<τ_0_0 where τ_0_0 == τ_1_0.Value, τ_1_0: AttributeGraph.StatefulRule>(τ_1_0) -> AttributeGraph.Attribute<τ_0_0> + 20
  frame #56: 0x00000001b90dc114 AttributeGraph`AG::Graph::UpdateStack::update() + 516
  frame #57: 0x00000001b90db880 AttributeGraph`AG::Graph::update_attribute(AG::data::ptr<AG::Node>, unsigned int) + 392
  frame #58: 0x00000001b90dc8d8 AttributeGraph`AG::Graph::input_value_ref_slow(AG::data::ptr<AG::Node>, AG::AttributeID, unsigned int, AGSwiftMetadata const*, unsigned char&, long) + 544
  frame #59: 0x00000001b90da2e4 AttributeGraph`AGGraphGetValue + 236
  frame #60: 0x000000018bddffdc SwiftUI`SwiftUI.AnyViewList.Item.list.getter : SwiftUI.ViewList + 120
  frame #61: 0x000000018be31104 SwiftUI`SwiftUI.AnyViewList.updateValue() -> () + 436
  frame #62: 0x000000018bef630c SwiftUI`partial apply forwarder for generic specialization <SwiftUI.ViewList, SwiftUI.AnyViewList> of implicit closure #2 (Swift.UnsafeMutableRawPointer, __C.AGAttribute) -> () in implicit closure #1 (τ_1_0.Type) -> (Swift.UnsafeMutableRawPointer, __C.AGAttribute) -> () in closure #1 () -> (Swift.UnsafeMutableRawPointer, __C.AGAttribute) -> () in closure #1 (Swift.UnsafePointer<τ_1_0>) -> AttributeGraph.Attribute<τ_0_0> in AttributeGraph.Attribute.init<τ_0_0 where τ_0_0 == τ_1_0.Value, τ_1_0: AttributeGraph.StatefulRule>(τ_1_0) -> AttributeGraph.Attribute<τ_0_0> + 20
  frame #63: 0x00000001b90dc114 AttributeGraph`AG::Graph::UpdateStack::update() + 516
  frame #64: 0x00000001b90db880 AttributeGraph`AG::Graph::update_attribute(AG::data::ptr<AG::Node>, unsigned int) + 392
  frame #65: 0x00000001b90dc8d8 AttributeGraph`AG::Graph::input_value_ref_slow(AG::data::ptr<AG::Node>, AG::AttributeID, unsigned int, AGSwiftMetadata const*, unsigned char&, long) + 544
  frame #66: 0x00000001b90da2e4 AttributeGraph`AGGraphGetValue + 236
  frame #67: 0x000000018be985c8 SwiftUI`SwiftUI.DynamicLayoutViewAdaptor.updatedItems() -> Swift.Optional<SwiftUI.ViewList> + 68
  frame #68: 0x000000018be56370 SwiftUI`generic specialization <SwiftUI.DynamicLayoutViewAdaptor> of SwiftUI.DynamicContainerInfo.updateItems(disableTransitions: Swift.Bool) -> (changed: Swift.Bool, hasDepth: Swift.Bool) + 64
  frame #69: 0x000000018be4026c SwiftUI`generic specialization <SwiftUI.DynamicLayoutViewAdaptor> of SwiftUI.DynamicContainerInfo.updateValue() -> () + 488
  frame #70: 0x000000018be475c0 SwiftUI`partial apply forwarder for generic specialization <SwiftUI.DynamicContainer.Info, SwiftUI.DynamicContainerInfo<SwiftUI.DynamicLayoutViewAdaptor>> of implicit closure #2 (Swift.UnsafeMutableRawPointer, __C.AGAttribute) -> () in implicit closure #1 (τ_1_0.Type) -> (Swift.UnsafeMutableRawPointer, __C.AGAttribute) -> () in closure #1 () -> (Swift.UnsafeMutableRawPointer, __C.AGAttribute) -> () in closure #1 (Swift.UnsafePointer<τ_1_0>) -> AttributeGraph.Attribute<τ_0_0> in AttributeGraph.Attribute.init<τ_0_0 where τ_0_0 == τ_1_0.Value, τ_1_0: AttributeGraph.StatefulRule>(τ_1_0) -> AttributeGraph.Attribute<τ_0_0> + 20
  frame #71: 0x00000001b90dc114 AttributeGraph`AG::Graph::UpdateStack::update() + 516
  frame #72: 0x00000001b90db880 AttributeGraph`AG::Graph::update_attribute(AG::data::ptr<AG::Node>, unsigned int) + 392
  frame #73: 0x00000001b90dc8d8 AttributeGraph`AG::Graph::input_value_ref_slow(AG::data::ptr<AG::Node>, AG::AttributeID, unsigned int, AGSwiftMetadata const*, unsigned char&, long) + 544
  frame #74: 0x00000001b90da2e4 AttributeGraph`AGGraphGetValue + 236
  frame #75: 0x000000018beb17a8 SwiftUI`generic specialization <SwiftUI._FormVStackLayout> of SwiftUI.DynamicLayoutComputer.containerInfo.getter : Swift.Optional<SwiftUI.DynamicContainer.Info> + 140
  frame #76: 0x000000018be63a50 SwiftUI`merged generic specialization <SwiftUI.LayoutComputer, SwiftUI.DynamicLayoutComputer<SwiftUI._HStackLayout>> of implicit closure #2 (Swift.UnsafeMutableRawPointer, __C.AGAttribute) -> () in implicit closure #1 (τ_1_0.Type) -> (Swift.UnsafeMutableRawPointer, __C.AGAttribute) -> () in closure #1 () -> (Swift.UnsafeMutableRawPointer, __C.AGAttribute) -> () in closure #1 (Swift.UnsafePointer<τ_1_0>) -> AttributeGraph.Attribute<τ_0_0> in AttributeGraph.Attribute.init<τ_0_0 where τ_0_0 == τ_1_0.Value, τ_1_0: AttributeGraph.StatefulRule>(τ_1_0) -> AttributeGraph.Attribute<τ_0_0> + 72
  frame #77: 0x000000018be323f4 SwiftUI`partial apply forwarder for generic specialization <SwiftUI.LayoutComputer, SwiftUI.DynamicLayoutComputer<SwiftUI._VStackLayout>> of implicit closure #2 (Swift.UnsafeMutableRawPointer, __C.AGAttribute) -> () in implicit closure #1 (τ_1_0.Type) -> (Swift.UnsafeMutableRawPointer, __C.AGAttribute) -> () in closure #1 () -> (Swift.UnsafeMutableRawPointer, __C.AGAttribute) -> () in closure #1 (Swift.UnsafePointer<τ_1_0>) -> AttributeGraph.Attribute<τ_0_0> in AttributeGraph.Attribute.init<τ_0_0 where τ_0_0 == τ_1_0.Value, τ_1_0: AttributeGraph.StatefulRule>(τ_1_0) -> AttributeGraph.Attribute<τ_0_0> + 40
  frame #78: 0x00000001b90dc114 AttributeGraph`AG::Graph::UpdateStack::update() + 516
  frame #79: 0x00000001b90db880 AttributeGraph`AG::Graph::update_attribute(AG::data::ptr<AG::Node>, unsigned int) + 392
  frame #80: 0x00000001b90dc8d8 AttributeGraph`AG::Graph::input_value_ref_slow(AG::data::ptr<AG::Node>, AG::AttributeID, unsigned int, AGSwiftMetadata const*, unsigned char&, long) + 544
  frame #81: 0x00000001b90de7dc AttributeGraph`AGGraphGetInputValue + 268
  frame #82: 0x000000018bdd777c SwiftUI`SwiftUI.StackLayout.Header.init(layoutContext: SwiftUI.SizeAndSpacingContext, proxies: SwiftUI.LayoutProxyCollection, majorAxis: SwiftUI.Axis, minorAxisAlignment: SwiftUI.AlignmentKey, uniformSpacing: Swift.Optional<CoreGraphics.CGFloat>, childStorage: Swift.UnsafeMutablePointer<SwiftUI.StackLayout.Child>, capacity: Swift.Int, resizeChildrenWithTrailingOverflow: Swift.Bool) -> SwiftUI.StackLayout.Header + 680
  frame #83: 0x000000018be83580 SwiftUI`function signature specialization <Arg[2] = [Closure Propagated : closure #1 (Swift.AnyObject, (Swift.AnyObject) -> Swift.Int) -> SwiftUI.StackLayout.(Header in _68D684484B5AEF917B6B8353D57CF590) in SwiftUI.StackLayout.init(layoutContext: SwiftUI.SizeAndSpacingContext, children: SwiftUI.LayoutProxyCollection, majorAxis: SwiftUI.Axis, minorAxisAlignment: SwiftUI.AlignmentKey, uniformSpacing: Swift.Optional<CoreGraphics.CGFloat>, resizeChildrenWithTrailingOverflow: Swift.Bool) -> SwiftUI.StackLayout, Argument Types : [SwiftUI.SizeAndSpacingContextSwiftUI.LayoutProxyCollectionSwiftUI.AxisSwiftUI.AlignmentKeySwift.Optional<CoreGraphics.CGFloat>Swift.Bool]> of generic specialization <SwiftUI.StackLayout.Header, SwiftUI.StackLayout.Child> of Swift.ManagedBufferPointer.init(bufferClass: Swift.AnyObject.Type, minimumCapacity: Swift.Int, makingHeaderWith: (Swift.AnyObject, (Swift.AnyObject) -> Swift.Int) throws -> τ_0_0) throws -> Swift.ManagedBufferPointer<τ_0_0, τ_0_1> + 256
  frame #84: 0x000000018c0dc434 SwiftUI`merged generic specialization <SwiftUI._FormVStackLayout, SwiftUI.StaticLayoutComputer<SwiftUI._FormVStackLayout>> of closure #2 () -> SwiftUI.StackLayout.Storage in SwiftUI.HVStack.updateLayoutComputer<τ_0_0 where τ_1_0: AttributeGraph.StatefulRule, τ_1_0.Value == SwiftUI.LayoutComputer>(rule: inout τ_1_0, layoutContext: SwiftUI.SizeAndSpacingContext, children: SwiftUI.LayoutProxyCollection) -> () + 168
  frame #85: 0x000000018c11cb20 SwiftUI`merged generic not re-abstracted specialization <SwiftUI._FormVStackLayout, SwiftUI.StaticLayoutComputer<SwiftUI._FormVStackLayout>> of closure #2 () -> SwiftUI.StackLayout.Storage in SwiftUI.HVStack.updateLayoutComputer<τ_0_0 where τ_1_0: AttributeGraph.StatefulRule, τ_1_0.Value == SwiftUI.LayoutComputer>(rule: inout τ_1_0, layoutContext: SwiftUI.SizeAndSpacingContext, children: SwiftUI.LayoutProxyCollection) -> () + 56
  frame #86: 0x000000018c15670c SwiftUI`merged partial apply forwarder for generic not re-abstracted specialization <SwiftUI._VStackLayout, SwiftUI.StaticLayoutComputer<SwiftUI.AdaptiveStackLayout>> of closure #2 () -> SwiftUI.StackLayout.Storage in SwiftUI.HVStack.updateLayoutComputer<τ_0_0 where τ_1_0: AttributeGraph.StatefulRule, τ_1_0.Value == SwiftUI.LayoutComputer>(rule: inout τ_1_0, layoutContext: SwiftUI.SizeAndSpacingContext, children: SwiftUI.LayoutProxyCollection) -> () + 44
  frame #87: 0x000000018bf304b0 SwiftUI`generic specialization <SwiftUI.StackLayout.Storage, SwiftUI.DynamicLayoutComputer<SwiftUI._FormVStackLayout>> of static SwiftUI.LayoutComputerDelegate.update<τ_0_0 where τ_1_0: AttributeGraph.StatefulRule, τ_1_0.Value == SwiftUI.LayoutComputer>(_: inout τ_1_0, maybeInPlace: (τ_0_0) -> Swift.Bool, create: () -> τ_0_0) -> () + 244
  frame #88: 0x000000018bfd1240 SwiftUI`merged generic specialization <SwiftUI.DynamicLayoutComputer<SwiftUI._HStackLayout>, SwiftUI._HStackLayout> of AttributeGraph.StatefulRule< where τ_0_0.Value == SwiftUI.LayoutComputer>.updateLayoutComputer<τ_0_0 where τ_1_0: SwiftUI._Layout>(layout: τ_1_0, environment: AttributeGraph.Attribute<SwiftUI.EnvironmentValues>, layoutComputers: Swift.Array<AttributeGraph.OptionalAttribute<SwiftUI.LayoutComputer>>) -> () + 100
  frame #89: 0x000000018be63acc SwiftUI`merged generic specialization <SwiftUI.LayoutComputer, SwiftUI.DynamicLayoutComputer<SwiftUI._HStackLayout>> of implicit closure #2 (Swift.UnsafeMutableRawPointer, __C.AGAttribute) -> () in implicit closure #1 (τ_1_0.Type) -> (Swift.UnsafeMutableRawPointer, __C.AGAttribute) -> () in closure #1 () -> (Swift.UnsafeMutableRawPointer, __C.AGAttribute) -> () in closure #1 (Swift.UnsafePointer<τ_1_0>) -> AttributeGraph.Attribute<τ_0_0> in AttributeGraph.Attribute.init<τ_0_0 where τ_0_0 == τ_1_0.Value, τ_1_0: AttributeGraph.StatefulRule>(τ_1_0) -> AttributeGraph.Attribute<τ_0_0> + 196
  frame #90: 0x000000018be323f4 SwiftUI`partial apply forwarder for generic specialization <SwiftUI.LayoutComputer, SwiftUI.DynamicLayoutComputer<SwiftUI._VStackLayout>> of implicit closure #2 (Swift.UnsafeMutableRawPointer, __C.AGAttribute) -> () in implicit closure #1 (τ_1_0.Type) -> (Swift.UnsafeMutableRawPointer, __C.AGAttribute) -> () in closure #1 () -> (Swift.UnsafeMutableRawPointer, __C.AGAttribute) -> () in closure #1 (Swift.UnsafePointer<τ_1_0>) -> AttributeGraph.Attribute<τ_0_0> in AttributeGraph.Attribute.init<τ_0_0 where τ_0_0 == τ_1_0.Value, τ_1_0: AttributeGraph.StatefulRule>(τ_1_0) -> AttributeGraph.Attribute<τ_0_0> + 40
  frame #91: 0x00000001b90dc114 AttributeGraph`AG::Graph::UpdateStack::update() + 516
  frame #92: 0x00000001b90db880 AttributeGraph`AG::Graph::update_attribute(AG::data::ptr<AG::Node>, unsigned int) + 392
  frame #93: 0x00000001b90da120 AttributeGraph`AG::Graph::value_ref(AG::AttributeID, AGSwiftMetadata const*, unsigned char&) + 188
  frame #94: 0x00000001b90da330 AttributeGraph`AGGraphGetValue + 312
  frame #95: 0x000000018c34fcb8 SwiftUI`SwiftUI.ViewGraph.layoutComputer.getter : Swift.Optional<SwiftUI.LayoutComputer> + 124
  frame #96: 0x000000018be80560 SwiftUI`SwiftUI.ViewGraph.sizeThatFits(SwiftUI._ProposedSize) -> __C.CGSize + 164
  frame #97: 0x000000018be660e4 SwiftUI`closure #1 (SwiftUI.ViewGraph) -> __C.CGSize in SwiftUI.ViewRendererHost.sizeThatFits(SwiftUI._ProposedSize) -> __C.CGSize + 52
  frame #98: 0x000000018bda2c5c SwiftUI`closure #1 () -> τ_1_0 in SwiftUI.ViewRendererHost.updateViewGraph<τ_0_0>(body: (SwiftUI.ViewGraph) -> τ_1_0) -> τ_1_0 + 88
  frame #99: 0x000000018bd9c9b0 SwiftUI`SwiftUI.ViewRendererHost.updateViewGraph<τ_0_0>(body: (SwiftUI.ViewGraph) -> τ_1_0) -> τ_1_0 + 92
  frame #100: 0x000000018be536b0 SwiftUI`SwiftUI.ViewRendererHost.sizeThatFits(SwiftUI._ProposedSize) -> __C.CGSize + 96
  frame #101: 0x000000018be217c4 SwiftUI`SwiftUI._UIHostingView.sizeThatFits(__C.CGSize) -> __C.CGSize + 112
  frame #102: 0x000000018bdfbe00 SwiftUI`merged @objc SwiftUI._UIHostingView._baselineOffsets(at: __C.CGSize) -> __C._UIBaselineOffsetPair + 48
  frame #103: 0x0000000186bed950 UIKitCore`-[UIView(_UIConstraintBasedLayoutEmbedding) _layoutSizeThatFits:fixedAxes:] + 84
  frame #104: 0x0000000186c3cc98 UIKitCore`-[UIView(UIConstraintBasedLayout) intrinsicContentSize] + 92
  frame #105: 0x0000000186be5a8c UIKitCore`-[UIView _generateContentSizeConstraints] + 56
  frame #106: 0x0000000186c94e50 UIKitCore`-[UIView _updateContentSizeConstraints] + 268
  frame #107: 0x0000000186d3f3e4 UIKitCore`-[UIView(AdditionalLayoutSupport) _updateSystemConstraints] + 124
  frame #108: 0x0000000186da3aa0 UIKitCore`-[UIView(AdditionalLayoutSupport) _sendUpdateConstraintsIfNecessaryForSecondPass:] + 480
  frame #109: 0x0000000186bc8544 UIKitCore`-[UIView(AdditionalLayoutSupport) _updateConstraintsIfNeededCollectingViews:forSecondPass:] + 996
  frame #110: 0x0000000186bc8424 UIKitCore`-[UIView(AdditionalLayoutSupport) _updateConstraintsIfNeededCollectingViews:forSecondPass:] + 708
  frame #111: 0x000000019c296bac CoreAutoLayout`-[NSISEngine withBehaviors:performModifications:] + 80
  frame #112: 0x0000000186f3f714 UIKitCore`-[UIView(AdditionalLayoutSupport) _recursiveUpdateConstraintsIfNeededCollectingViews:forSecondPass:] + 120
  frame #113: 0x0000000186bc8424 UIKitCore`-[UIView(AdditionalLayoutSupport) _updateConstraintsIfNeededCollectingViews:forSecondPass:] + 708
  frame #114: 0x0000000186bc8424 UIKitCore`-[UIView(AdditionalLayoutSupport) _updateConstraintsIfNeededCollectingViews:forSecondPass:] + 708
  frame #115: 0x0000000186bc8424 UIKitCore`-[UIView(AdditionalLayoutSupport) _updateConstraintsIfNeededCollectingViews:forSecondPass:] + 708
  frame #116: 0x0000000186bc8424 UIKitCore`-[UIView(AdditionalLayoutSupport) _updateConstraintsIfNeededCollectingViews:forSecondPass:] + 708
  frame #117: 0x000000019c296bac CoreAutoLayout`-[NSISEngine withBehaviors:performModifications:] + 80
  frame #118: 0x0000000186c2d8f0 UIKitCore`__100-[UIView(AdditionalLayoutSupport) _updateConstraintsIfNeededWithViewForVariableChangeNotifications:]_block_invoke + 84
  frame #119: 0x0000000186c5e578 UIKitCore`-[UIView(AdditionalLayoutSupport) _withUnsatisfiableConstraintsLoggingSuspendedIfEngineDelegateExists:] + 120
  frame #120: 0x0000000186ca58f8 UIKitCore`-[UIView(AdditionalLayoutSupport) _updateConstraintsIfNeededWithViewForVariableChangeNotifications:] + 160
  frame #121: 0x0000000186ea6ce4 UIKitCore`-[UIView(AdditionalLayoutSupport) _updateConstraintsAtEngineLevelIfNeededWithViewForVariableChangeNotifications:] + 516
  frame #122: 0x0000000186bcc500 UIKitCore`-[UIView _updateConstraintsAsNecessaryAndApplyLayoutFromEngine] + 360
  frame #123: 0x0000000186bc51e0 UIKitCore`-[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 2664
  frame #124: 0x0000000188245520 QuartzCore`CA::Layer::layout_if_needed(CA::Transaction*) + 528
  frame #125: 0x0000000188238294 QuartzCore`CA::Layer::layout_and_display_if_needed(CA::Transaction*) + 132
  frame #126: 0x000000018824bcc8 QuartzCore`CA::Context::commit_transaction(CA::Transaction*, double, double*) + 464
  frame #127: 0x000000018825479c QuartzCore`CA::Transaction::commit() + 708
  frame #128: 0x00000001882379a8 QuartzCore`CA::Transaction::flush_as_runloop_observer(bool) + 84
  frame #129: 0x000000018474c76c CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 32
  frame #130: 0x000000018471d974 CoreFoundation`__CFRunLoopDoObservers + 616
  frame #131: 0x0000000184718efc CoreFoundation`__CFRunLoopRun + 1012
  frame #132: 0x000000018472c174 CoreFoundation`CFRunLoopRunSpecific + 572
  frame #133: 0x00000001a506b988 GraphicsServices`GSEventRunModal + 160
  frame #134: 0x0000000186f2ea88 UIKitCore`-[UIApplication _run] + 1080
  frame #135: 0x0000000186cc7f78 UIKitCore`UIApplicationMain + 336
  frame #136: 0x000000018bf80d68 SwiftUI`closure #1 (Swift.UnsafeMutablePointer<Swift.Optional<Swift.UnsafeMutablePointer<Swift.Int8>>>) -> Swift.Never in SwiftUI.KitRendererCommon(Swift.AnyObject.Type) -> Swift.Never + 160
  frame #137: 0x000000018becb83c SwiftUI`SwiftUI.runApp<τ_0_0 where τ_0_0: SwiftUI.App>(τ_0_0) -> Swift.Never + 180
  frame #138: 0x000000018beb11dc SwiftUI`static SwiftUI.App.main() -> () + 96
  frame #139: 0x0000000100ee0448 purchases-kmp Sample`static iOSApp.$main(self=purchases_kmp_Sample.iOSApp) at <compiler-generated>:0
  frame #140: 0x0000000100ee04f8 purchases-kmp Sample`main at iOSApp.swift:4:8
  frame #141: 0x00000001056e04d0 dyld`start + 444

Reproducer

In PurchaseTester, using the Main RevenueCat Sample App RevenueCat project, there's a Paywall configured called template7_crash_ios_pr_4243. Trying to show this Paywall reproduces the crash. This is because the tiers are configured to show the weekly, monthly and lifetime packages, but only the yearly package is correctly configured for iOS in this offering.

Fix

The fix implemented in this PR is to check whether we have any tiers left after filtering out those without available products, and throwing the existing TemplateError.noTiers error.

locale: locale,
showZeroDecimalPlacePrices: showZeroDecimalPlacePrices
)
let filteredTiers: [(PaywallData.Tier, (MultiPackage, String))] = try tiers.compactMap { tier in
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I recommend hiding whitespace when reviewing this file.

Instead of filtering the tiers inline while creating the Dictionary, it is now filtering the tiers separately first. Then we can use the filtered list to grab the first item, for our firstTier. Then the filtered list is passed into the Dictionary constructor as before.

@JayShortway JayShortway marked this pull request as ready for review September 5, 2024 13:11
@JayShortway JayShortway requested review from vegaro and a team September 5, 2024 13:11
Copy link
Contributor

@jamesrb1 jamesrb1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice fix to catch the invalid configuration when it's constructed.

The initializer where this is used has a fatalError and a ! - in my opinion it's better if at all possible to avoid these unless there truly is no other choice. Some other undetected error upstream could cause the same crash, and if we can bow out more gracefully at that point, we ought to. Even if that were done, this change of course should still be added!

It all looks good to me, commented on some small nits.

)
}

let filteredTiersMap: [PaywallData.Tier: (package: MultiPackage, tierName: String)] = Dictionary(
Copy link
Contributor

@jamesrb1 jamesrb1 Sep 5, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Referring to a dictionary as a "map" isn't idiomatic swift.... our style guide would recommend something like packageAndTierNameByTier. Or you could use filteredTiersDict...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah right, thanks for pointing me to the style guide. Done in 24c1f68.

locale: locale,
showZeroDecimalPlacePrices: showZeroDecimalPlacePrices
)
let filteredTiers: [(PaywallData.Tier, (MultiPackage, String))] = try tiers.compactMap { tier in
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's helpful to maintain the labels on the tuple, (package: MultiPackage, tierName: String) rather than (MultiPackage, String).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree! 24c1f68

Comment on lines -279 to 283
guard let firstTier = tiers.first else {
guard let (firstTier, _) = filteredTiers.first else {
throw TemplateError.noTiers
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could be moved above the dictionary construction.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good one! Done in 24c1f68.

@JayShortway
Copy link
Member Author

Waiting for #4252 to be merged to fix lint.

@JayShortway JayShortway enabled auto-merge (squash) September 9, 2024 14:52
@JayShortway JayShortway merged commit 136639e into main Sep 9, 2024
5 checks passed
@JayShortway JayShortway deleted the no-tiers-crash branch September 9, 2024 15:00
This was referenced Sep 11, 2024
nyeu pushed a commit that referenced this pull request Oct 2, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
pr:fix A bug fix
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants