在工作表消失后将数据写入 UserDefaults 时崩溃 (SIGABRT)
Posted
技术标签:
【中文标题】在工作表消失后将数据写入 UserDefaults 时崩溃 (SIGABRT)【英文标题】:Crash (SIGABRT) when writing data to UserDefaults after Sheet disappears 【发布时间】:2021-04-29 15:09:47 【问题描述】:我收到了三个无法重现的类似崩溃报告(全部在 ios 14.4 上)。 stracktrace 说明如下(我只粘贴了我的应用程序启动的部分):
Exception Type: EXC_CRASH (SIGABRT)
Exception Codes: 0x0000000000000000, 0x0000000000000000
Exception Note: EXC_CORPSE_NOTIFY
Triggered by Thread: 0
Thread 0 name:
Thread 0 Crashed:
0 libsystem_kernel.dylib 0x00000001c077d414 __pthread_kill + 8
1 libsystem_pthread.dylib 0x00000001de2d8b50 pthread_kill + 272 (pthread.c:1392)
2 libsystem_c.dylib 0x000000019bc5bb74 abort + 104 (abort.c:110)
3 libswiftCore.dylib 0x0000000196795f20 swift::fatalError(unsigned int, char const*, ...) + 60 (Errors.cpp:393)
4 libswiftCore.dylib 0x0000000196796078 swift::swift_abortRetainUnowned(void const*) + 36 (Errors.cpp:460)
5 libswiftCore.dylib 0x00000001967e5844 swift_unknownObjectUnownedLoadStrong + 76 (SwiftObject.mm:895)
6 SwiftUI 0x00000001992b0cdc ViewGraph.graphDelegate.getter + 16 (ViewGraph.swift:234)
7 SwiftUI 0x00000001997e4d58 closure #1 in GraphHost.init(data:) + 80
8 SwiftUI 0x00000001997e6550 partial apply for closure #1 in GraphHost.init(data:) + 40 (<compiler-generated>:0)
9 AttributeGraph 0x00000001bbcc9b88 AG::Graph::Context::call_update() + 76 (ag-closure.h:108)
10 AttributeGraph 0x00000001bbcca1a0 AG::Graph::call_update() + 56 (ag-graph.cc:176)
11 AttributeGraph 0x00000001bbccfd70 AG::Subgraph::update(unsigned int) + 92 (ag-graph.h:709)
12 SwiftUI 0x00000001997e1cdc GraphHost.runTransaction() + 172 (GraphHost.swift:491)
13 SwiftUI 0x00000001997e4e1c GraphHost.runTransaction(_:) + 92 (GraphHost.swift:471)
14 SwiftUI 0x00000001997e37a8 GraphHost.flushTransactions() + 176 (GraphHost.swift:459)
15 SwiftUI 0x00000001997e2c78 specialized GraphHost.asyncTransaction<A>(_:mutation:style:) + 252 (<compiler-generated>:0)
16 SwiftUI 0x00000001993bd2fc AttributeInvalidatingSubscriber.invalidateAttribute() + 236 (AttributeInvalidatingSubscriber.swift:89)
17 SwiftUI 0x00000001993bd1f8 AttributeInvalidatingSubscriber.receive(_:) + 100 (AttributeInvalidatingSubscriber.swift:53)
18 SwiftUI 0x00000001993bd914 protocol witness for Subscriber.receive(_:) in conformance AttributeInvalidatingSubscriber<A> + 24 (<compiler-generated>:0)
19 SwiftUI 0x000000019956ba34 SubscriptionLifetime.Connection.receive(_:) + 100 (SubscriptionLifetime.swift:195)
20 Combine 0x00000001a6e67900 ObservableObjectPublisher.Inner.send() + 136 (ObservableObject.swift:115)
21 Combine 0x00000001a6e670a8 ObservableObjectPublisher.send() + 632 (ObservableObject.swift:153)
22 Combine 0x00000001a6e4ffdc PublishedSubject.send(_:) + 136 (PublishedSubject.swift:82)
23 Combine 0x00000001a6e76994 specialized static Published.subscript.setter + 388 (Published.swift:0)
24 Combine 0x00000001a6e75f74 static Published.subscript.setter + 40 (<compiler-generated>:0)
25 MyApp 0x00000001005d1228 counter.set + 32 (Preferences.swift:0)
26 MyApp 0x00000001005d1228 Preferences.counter.modify + 120 (Preferences.swift:0)
27 MyApp 0x00000001005ca440 MyView.changeCounter(decrease:) + 344 (MyView.swift:367)
28 MyApp 0x00000001005cf110 0x100584000 + 307472
29 MyApp 0x00000001005e65d8 thunk for @escaping @callee_guaranteed () -> () + 20 (<compiler-generated>:0)
30 MyApp 0x00000001005a8828 closure #2 in MySheet.body.getter + 140 (MySheet.swift:0)
正在发生的事情是,我有一个带有按钮的工作表,当单击它时,工作表消失,并且在主视图 MyView
中的 onDisappear
中调用 changeCounter
方法来更改 counter
.调用/打开工作表时,方法changeCounter
会从MyView
传递给工作表。
这是MyView
中的.sheet方法:
.sheet(item: $activeSheet) item in
switch item
case .MY_SHEET:
MySheet(changeCounter: changeCounter(decrease: true), changeTimer, item: $activeSheet)
这是工作表的(重要部分):
struct MySheet: View
var changeCounter: () -> Void
var changeTimer: () -> Void
@Binding var item: ActiveSheet?
@State var dismissAction: (() -> Void)?
var body: some View
GeometryReader metrics in
VStack
Button(action:
self.dismissAction = changeCounter
self.item = nil
, label:
Text("change_counter")
)
Button(action:
self.dismissAction = changeTimer
self.item = nil
, label:
Text("change_timer")
)
.frame(width: metrics.size.width, height: metrics.size.height * 0.85)
.onDisappear(perform:
if self.dismissAction != nil
self.dismissAction!()
)
这里是 changeCounter
和 preferences
对象:
struct MyView: View
@EnvironmentObject var preferences: Preferences
var body: some View ...
func changeCounter(decrease: Bool)
if decrease
preferences.counter -= COUNTER_INTERVAL
Preferences
是带有 counter
变量的 ObservableObject
:
class Preferences: ObservableObject
let userDefaults: UserDefaults
init(_ userDefaults: UserDefaults)
self.userDefaults = userDefaults
self.counter = 0
@Published var counter: Int
didSet
self.userDefaults.set(counter, forKey: "counter")
它会更改userDefaults
中的一个值,即UserDefaults.standard
。
任何人都知道崩溃是如何发生的以及在什么情况下发生?因为它现在只在用户设备上发生了 3 次,我无法重现。
【问题讨论】:
您是否完全删除了应用程序,可能重置了设备并再次测试?我怀疑这个问题会再次发生。 我的设备上没有发生这种情况。我用模拟器尝试过,但没有崩溃,我也尝试重新安装它。并且用户的描述看起来它也可以多次运行而没有崩溃。 现在发生了两次,都是在 iOS 14.4 上。 您能否展示您的代码,您的工作表是在哪里创建的以及 changeCounter 是在哪里调用的? 在一个动作中改变两个状态可能是问题的根源。众所周知,由于 SwiftUI 2.0 处理不好,所以尝试结合模型(替换、重构等)只改变一种状态。 【参考方案1】:我们来分析
Button(action:
self.dismissAction = changeCounter 1)
self.item = nil 2)
, label:
第 1 行)更改内部工作表状态,启动工作表视图的更新 第 2 行) 更改外部状态,开始关闭工作表(并且可能更新父视图)。
这甚至听起来像是两个冲突的过程(即使没有依赖的流程,但是第二个查看您的代码取决于第一个的结果)。所以,这是非常危险的逻辑,应该避免。
一般来说,正如我在评论中所写,在一个闭包中更改两个状态总是有风险的,所以我会重写逻辑以具有类似(草图)的内容:
Button(action:
self.result = changeCounter // one external binding !!
, label:
,即。启动某些外部活动的一种状态变化...
您的代码的可能解决方法(如果由于任何原因您无法更改逻辑)是及时分离这些状态的更改,例如
Button(action:
self.dismissAction = changeCounter // updates sheet
DispatchQueue.main.async // or after some min delay
self.item = nil // closes sheet after (!) update
, label:
【讨论】:
在您的第一个 cmets 之后,我首先将操作更改为:self.dismissAction = changeCounter; self.presentationMode.wrappedValue.dismiss()
其中presentationMode
是@Environment(\.presentationMode) var presentationMode
。这在我的设备上“有效”。它是否与我的原始代码具有相同的负面影响,还是您认为它是一个有效的解决方案?
几乎一样。以上是关于在工作表消失后将数据写入 UserDefaults 时崩溃 (SIGABRT)的主要内容,如果未能解决你的问题,请参考以下文章
从 Testflight 安装同一应用程序的不同构建版本时,UserDefaults 正在消失