Swift 3中的Date._unconditionallyBridgeFromObjectiveC(NSDate?)崩溃

Vin*_*uta 7 date nsdate swift3

我在快速文件中具有以下功能。我是从Obj C文件中使用NSDate代替startDate来调用的。很多时候,不是每次,我的应用都会崩溃

Date._unconditionallyBridgeFromObjectiveC(NSDate?)

我怎样才能解决这个问题?

func trackMeetingEnded(_ name: String, startDate: Date, backgroundTime: TimeInterval) {}
Run Code Online (Sandbox Code Playgroud)

堆栈跟踪

崩溃:com.apple.main-thread
0 libswiftFoundation.dylib 0x102061e98​​静态Date._unconditionallyBridgeFromObjectiveC(NSDate?)-> Date + 72
1酸0x10017ece4 @objc静态ClusteredMixpanel.trackMeetingEnded(String,startDate:Date,backgroundTime:Double)->()(MixpanelMeeting.swift)
2 Acid 0x10073e1bc __56- [MeetingLifeCycleViewController stateInitialization] _block_invoke.221(MeetingLifeCycleViewController.m:267)
3酸0x1001ee5c4部分申请重击(StateMachine.swift)
4酸0x1001ea70c专用State.willLeaveState(State)->()(StateMachine.swift:238)
5酸0x1001ead90专门的StateMachine.transitionToState(State)-> Bool(StateMachine.swift)
6酸0x1001e1f18 @objc StateMachine.transitionToState(State)-> Bool(StateMachine.swift)
7酸0x10073ace0-[MeetingLifeCycleViewController dismissCall](MeetingLifeCycleViewController.m:538)
8 Acid 0x10086d648-[InMeetingViewController挂断](InMeetingViewController.m:531)

enter code here

Run Code Online (Sandbox Code Playgroud)

我相信在这种情况下,NSDate至Date的转换是由OS完成的。仅在迁移到Swift 3之后才能看到该问题。是否存在任何已知问题?我在网上找不到任何东西:(

Mar*_*rry 10

这个答案适用于那些使用 Core Data 和 Swift 遇到这个问题的人:

在 Core Data 中NSManagedObject,在 Swift 的数据模型中表示标记为非可选的类型时必须小心。

核心数据对象本质上是动态的,内存中的值是在运行时通过设计动态实现的。这与 Swift 的真正非可选类型的概念不兼容,除非您在数据模型中定义默认值。

请注意,默认情况下自动生成的类始终使用可选项,即使该属性在数据模型中被标记为非可选。要正确支持非可选项,您必须在模型中定义一个默认值

您可能认为这是 Apple 方面的错误,但事实并非如此。Core Data 对象可以被删除,并且您仍然可以在代码中的某处引用它(请参阅isDeleted属性),因此标记为非可选的东西可以在运行时消失,因为 Core Data 永远无法满足其动态期望。

例如,whileStringInt将“无条件地桥接”到 "" 和0when nilDate如本问题所示,将崩溃。

请注意,如果您将其标记为NSDate(即使标记为非可选,它也会返回 nil),情况并非如此,但这并不是一种解决方法,而是一个实现细节。

测试用例:

假设您的数据模型具有date1, 和date2,均非可选且没有默认值。

@NSManaged public var date1: Date?
@NSManaged public var date2: Date
Run Code Online (Sandbox Code Playgroud)
let myObject = ... 
// Assuming your object is valid, inserted, and the context is saved              
managedObjectContext.delete(myObject)
try managedObjectContext.save()
// This will be nil
NSLog("\(myObject.date1)")
// This will crash
NSLog("\(myObject.date2)")
Run Code Online (Sandbox Code Playgroud)

总之,您可以在 Core Data 中使用没有默认值的非可选类型,只是要小心,因为在运行时它们可能会在 Date 的情况下消失和崩溃,或者以您不期望的方式表示,例如字符串和整数。

注意:您仍然应该利用将属性标记为非可选的功能,即使在 Swift 中它被表示为可选。Core Data 的对象验证代码已考虑到这一点。


Des*_*erd 7

您可能需要仔细检查一下NSDate来自Objective-C的消息实际上不是非消息nil,因为没有什么东西像Swift那样积极地在Obj-C方面强制执行此操作。

我结束了将尽可能多的Dates 转换为s Date?的工作,我发现可以从Obj-C中调用它,然后进行大量guard let检查。

assertionFailure在开发过程中,您还可以大喊大叫,以了解那些nil不期望的日期来自何处。例如:

guard let date = passedInDate else {
    assertionFailure("Turns out the passed-in date was nil!")
    return 
}
Run Code Online (Sandbox Code Playgroud)

然后看一下堆栈跟踪何时被击中,以查看是否可以更好地了解为什么在那里获得了意外的nil值。

更新:是Swift源代码中发生崩溃的地方。