【问题标题】:Date._unconditionallyBridgeFromObjectiveC(NSDate?) crash in Swift 3Date._unconditionallyBridgeFromObjectiveC(NSDate?) 在 Swift 3 中崩溃
【发布时间】:2017-05-17 17:54:03
【问题描述】:

我在 swift 文件中有以下功能。我用 NSDate 代替 startDate 从 Obj C 文件中调用它。而且,我的应用程序经常崩溃,而不是每次都发生

Date._unconditionallyBridgeFromObjectiveC(NSDate?)

我该如何解决这个问题?

func trackMeetingEnded(_ name: String, startDate: Date, backgroundTime: TimeInterval) {}

堆栈跟踪

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

我相信在这种情况下,NSDate 到日期的转换是由操作系统完成的。该问题仅在迁移到 Swift 3 后才会出现。是否有任何已知问题?我在网上找不到任何东西:(

【问题讨论】:

  • 粘贴你的函数或代码

标签: date swift3 nsdate


【解决方案1】:

您可能需要仔细检查来自 Objective-C 的 NSDate 实际上不是 nil,因为在 Obj-C 端没有任何东西像 Swift 端那样积极地强制执行它。

我最终将尽可能多的 Dates 转换为 Date?s,因为我可以找到从 Obj-C 调用的,然后进行大量的 guard let 检查。

您还可以在开发过程中输入assertionFailure 来对您大喊大叫,告诉您那些您没想到的nil 日期来自哪里。例如:

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

然后查看你的堆栈跟踪,看看你是否可以更好地理解为什么你在那里得到了一个意想不到的nil 值。

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

【讨论】:

  • 我必须将 startDate 设为可选。原来 nil 被通过了。
【解决方案2】:

这个答案是为那些在 Core Data 和 Swift 中遇到这个问题的人准备的:

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

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

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

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

虽然StringInt 将“无条件桥接”到“”和0,但当nil 时,Date 将崩溃,如本问题所示。

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

测试用例:

假设您的数据模型具有date1date2,它们都是非可选且没有默认值的。

@NSManaged public var date1: Date?
@NSManaged public var date2: Date
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)")

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

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

【讨论】:

  • 我正在使用具有默认值的非可选项,但在处理持久历史记录时,我仍然很少遇到这种崩溃。
  • 您没有指定它是哪种类型。通常,在 Swift 中将非可选参数与 NSManagedObject 一起使用并不是一个好主意,即使您设置了默认值。 Core Data 无法满足该属性的原因有很多。
  • 这可能失败的“许多”其他原因是什么?
  • 对象被删除,底层数据存储消失等。您必须查看有关 Core Data 如何将数据存储移动到内存并在必要时使用默认值的文档或实现细节.
【解决方案3】:

为 swift & coreData + 多线程环境扩展 Marc Etcheverry 答案。

请注意NSFetchRequest 有一个名为returnsObjectsAsFaults 的属性,默认为true (apple doc),这意味着您将检索您的NSManagedObject,但在您访问之前,它的属性实际上不会被填充它们,因此,如果在您访问属性时(在本例中为日期Date._unconditionallyBridgeFromObjectiveC),如果有任何不同的线程从核心数据中删除了该实例,则它可能是 nil 并且您的非可选 Date 可能会使应用程序崩溃.

想象一下这个场景:

Thread 1 

 - [step 1] let values = Fetch [NSManagedObject]

 - [step 3] let values[0].someDate // here app will crash

因为returnsObjectsAsFaultstrue [默认] someDate 属性在您尝试访问它之前不会被提取。

Thread 2 

 - [step 2] update coreData - hence removing objects fetched on Thread 1 - step 1

解决方案:如果您确实需要从 NSManagedObject 开始的所有属性,请确保在您的 fetchRequest 上进行设置:

let request = NSFetchRequest<T>(entityName: "someEntity")
...
request.returnsObjectsAsFaults = false

【讨论】:

    【解决方案4】:

    如果有人还在想办法解决这个问题:

    1. 确保在 Swift 中,您分配的值是可选的;
    2. 确保ObjC 类中的属性标记为nullable

    ObjC

    NS_ASSUME_NONNULL_BEGIN
    
    @interface Item : NSObject
    
    @property (nonatomic, nullable) NSDate *imageURL;
    
    @end
    
    NS_ASSUME_NONNULL_END
    

    在 Swift 中:

    var imageURL: Date? = itme.imageURL
    

    这将解决问题。 如果你没有在 ObjC 中将该属性标记为可为空,Swift 将假定它不能为 nil,尽管你正确地将其声明为 Date?。这将导致标题中提到的崩溃。 在 ObjC 中添加 nullable 后,崩溃将得到解决。

    【讨论】:

      猜你喜欢
      • 2018-07-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-10-27
      相关资源
      最近更新 更多