我在swift文件中有以下功能。我用Obj C文件用NSDate代替startDate来调用它。而且很多时候,不是每次,我的应用程序崩溃
Date._unconditionallyBridgeFromObjectiveC(的NSDate?)
我该如何解决这个问题?
func trackMeetingEnded(_ name: String, startDate: Date, backgroundTime: TimeInterval) {}
堆栈跟踪
Crashed: com.apple.main-thread
0 libswiftFoundation.dylib 0x102061e98 static Date._unconditionallyBridgeFromObjectiveC(NSDate?) -> Date + 72
1 Acid 0x10017ece4 @objc static ClusteredMixpanel.trackMeetingEnded(String, startDate : Date, backgroundTime : Double) -> () (MixpanelMeeting.swift)
2 Acid 0x10073e1bc __56-[MeetingLifeCycleViewController stateInitialization]_block_invoke.221 (MeetingLifeCycleViewController.m:267)
3 Acid 0x1001ee5c4 partial apply for thunk (StateMachine.swift)
4 Acid 0x1001ea70c specialized State.willLeaveState(State) -> () (StateMachine.swift:238)
5 Acid 0x1001ead90 specialized StateMachine.transitionToState(State) -> Bool (StateMachine.swift)
6 Acid 0x1001e1f18 @objc StateMachine.transitionToState(State) -> Bool (StateMachine.swift)
7 Acid 0x10073ace0 -[MeetingLifeCycleViewController dismissCall] (MeetingLifeCycleViewController.m:538)
8 Acid 0x10086d648 -[InMeetingViewController hangup] (InMeetingViewController.m:531)
enter code here
我相信在这种情况下,操作系统会完成NSDate to Date转换。只有在迁移到Swift 3之后才能看到这个问题。围绕此问题是否有任何已知问题?我在网上找不到任何东西:(
答案 0 :(得分:6)
您可能需要仔细检查来自Objective-C的NSDate
是否实际上是非nil
,因为没有任何内容可以在Obj-上积极执行C侧是Swift方面的方式。
我尽可能多地将Date
转换为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&#39}在Swift源代码中发生崩溃的地方。
答案 1 :(得分:0)
此答案适用于那些面临Core Data和Swift问题的人:
在Core Data NSManagedObject
中,在Swift的数据模型中表示标记为非可选的类型时,您必须要小心。
核心数据对象本质上是动态的,并且内存中的值是通过设计在运行时动态实现的。除非您在数据模型中定义默认值,否则这与Swift的真正非可选类型的概念不兼容。
请注意,即使在数据模型中将该属性标记为非可选的情况下,默认情况下,自动生成的类也总是求助于可选的。 要正确支持非可选选项,您必须在模型中定义一个默认值。
您可能会认为这是Apple的错误,但事实并非如此。可以删除Core Data对象,并且您仍然可以在代码中的某个位置对其进行引用(请参见isDeleted
属性),因此标记为非可选的内容可以在运行时消失,因为Core Data永远无法满足其动态期望。
例如,String
和Int
崩溃时,0
和nil
将“无条件地桥接”到“”和Date
这个问题。
请注意,如果您将其标记为NSDate
(即使标记为非可选,它将返回nil),情况并非如此,但这并不是解决方法,而是实现的详细信息。
测试用例:
假设您的数据模型具有date1
和date2
,均为非可选且没有默认值。
@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的情况下消失并崩溃,或者以您不期望的方式表示字符串和整数的情况。
注意:即使在Swift中将属性表示为可选,您仍应使用将属性标记为非可选的功能。 Core Data的对象验证代码已考虑到这一点。
答案 2 :(得分:0)
如果有人还在想办法解决这个问题:
nullable
。即
对象
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
后,崩溃将得到解决。
答案 3 :(得分:0)
为 swift & coreData + 多线程环境扩展 Marc Etcheverry 答案。
请注意,NSFetchRequest
有一个名为 returnsObjectsAsFaults
的属性,默认情况下为 true
(apple doc) 这意味着您将检索您的 NSManagedObject
但它的属性在您访问它们之前实际上不会被填充,因此,如果在您访问该属性(在本例中为日期 Date._unconditionallyBridgeFromObjectiveC
)时,其他线程万一从核心数据中删除了该实例,它可以为零而您的非可选 Date
可能会导致应用崩溃。
想象一下这个场景:
Thread 1
- [step 1] let values = Fetch [NSManagedObject]
- [step 3] let values[0].someDate // here app will crash
因为 returnsObjectsAsFaults
是 true
[默认] 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