我已经获得并设法为我的iOS应用程序表示崩溃报告。但是,看看堆栈跟踪,我似乎无法理解它。
Thread 0 Crashed:
0 libswiftCore.dylib 0x00000001005d330c specialized _assertionFailure(StaticString, String, file : StaticString, line : UInt, flags : UInt32) -> Never (__hidden#17347_:134)
1 libswiftCore.dylib 0x00000001004d7d2c Error<A where ...>._code.getter (__hidden#18979_:221)
2 libswiftCore.dylib 0x00000001004d7bf4 swift_errorInMain + 0
3 MyAppName 0x00000001000c2190 specialized PersonRepository.hydrate(Row) -> Person (PersonRepository.swift:0)
4 MyAppName 0x00000001000fbebc specialized Database.checkSchemaVersion(connection : Connection) -> () (Database.swift:0)
5 MyAppName 0x00000001000fc254 _TTSf4d_g__TZFC6MyAppName8DatabaseP33_909B711B8156620EE1EFE30EC21C4C0C11getInstancefT_S0_ (Database.swift:0)
6 MyAppName 0x00000001000fade8 static Database.getInstance() -> Database (Database.swift:0)
7 MyAppName 0x00000001000a7a6c TaskRepository.init() -> TaskRepository (TaskRepository.swift:38)
(......)
让我头疼的是地球上从第4级到第3级的过程。
在我的承诺中,它暗示Database.checkSchemaVersion(connection : Connection) -> ()
在某些时候会调用PersonRepository.hydrate(Row) -> Person
- 这没有任何意义。
这是我的完整数据库类(它不是太大)
// Database.swift
import SQLite
import Foundation
class Database
{
private var connection : Connection?
private static var instance : Database?
private static func getInstance() -> Database
{
if (instance == nil) {
instance = Database()
instance!.checkSchemaVersion(connection: instance!.connection!)
}
return instance!
}
private init()
{
let path = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first!
connection = try! Connection("(path)/myappname.sqlite3");
}
deinit {
connection = nil
}
static func getConnection() -> Connection
{
return getInstance().connection!
}
func checkSchemaVersion(connection : Connection)
{
guard let buildString = Bundle.main.infoDictionary?["CFBundleVersion"] as? String else {
Application.debug("Database: could not convert Build to String")
return
}
guard let build = Int64(buildString) else {
Application.debug("Database: could not convert Build from String to Int64")
return
}
let schemaVersion = try! connection.scalar("PRAGMA user_version") as? Int64 ?? 0
Application.debug("Database: checking schema version - DB=(schemaVersion) vs app=(build)")
if schemaVersion < build {
Application.debug("Database: old schema version detected - updating now")
PersonRepository.getInstance().updateSchema(from: schemaVersion, to: build)
PictureRepository.getInstance().updateSchema(from: schemaVersion, to: build)
TaskRepository.getInstance().updateSchema(from: schemaVersion, to: build)
TaskCommentRepository.getInstance().updateSchema(from: schemaVersion, to: build)
VenueRepository.getInstance().updateSchema(from: schemaVersion, to: build)
try! connection.run("PRAGMA user_version = (build)")
}
}
}
任何想法是什么堆栈跟踪(不是很堆叠,是吧?)应该是什么意思,或者它是如何达到这种情况的?难怪如果事情确实以这种方式发生,它就会崩溃。
更新
虽然我认为堆栈跟踪表明Database.checkSchemaVersion(connection : Connection) -> ()
中的某个位置有PersonRepository.hydrate(Row) -> Person
的直接调用,但此添加是无关紧要的,这里是PersonRepository
的相关部分
private init()
{
db = Database.getConnection()
table = Table("persons")
pictureRepository = PictureRepository.getInstance()
try! db.run(table.create(ifNotExists: true) {
t in
t.column(id, primaryKey: true)
t.column(name)
t.column(email)
t.column(phone)
t.column(company)
t.column(pictureId)
})
}
public func updateSchema(from: Int64, to: Int64)
{
if from < 2016121201 {
try! db.run(table.addColumn(active, defaultValue: 1))
}
}
static func getInstance() -> PersonRepository
{
if (instance == nil) {
instance = PersonRepository()
}
return instance!
}
答案 0 :(得分:1)
一个提示 - 尽可能避免!
。特别是对于try
的异常处理。应该有一个很好的理由让事情发生,我相信这就是你崩溃的原因。
堆栈跟踪可能不完全明显,因为编译器可以为发布版本内联/优化某些方法调用。在你的情况下,它可能就是这样:
checkSchemaVersion(connection : Connection)
PersonRepository.getInstance()
PersonRepository.init()
try! db.run()
Database
如果你无法重现崩溃,我的建议就是重写这段代码而不用强制解包并思考如果出现问题该怎么做。一种解决方案可以是使用可用的初始化器并在上游处理可能的nil
值,即
private init?()
{
db = Database.getConnection()
table = Table("persons")
pictureRepository = PictureRepository.getInstance()
do {
try db.run(table.create(ifNotExists: true) {
t in
t.column(id, primaryKey: true)
t.column(name)
t.column(email)
t.column(phone)
t.column(company)
t.column(pictureId)
})
} catch {
return nil
}
}