2017-04-24 3 views
2

Ich habe erreicht und es geschafft, einen Absturzbericht für meine iOS-App zu symbolisieren. Wenn ich jedoch auf die Stack-Spur schaue, kann ich keinen Sinn darin finden.iOS-Crash-Stack-Trace macht wenig Sinn

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) 
(......) 

Was ich meinen Kopf kratzen macht, ist, wie auf der Erde es von Stufe 4 bis Stufe 3 In meinem undertanding bekommen hat, es bedeutet, dass Database.checkSchemaVersion(connection : Connection) ->() an einem gewissen Punkt nennt PersonRepository.hydrate(Row) -> Person - was überhaupt keinen Sinn macht.

Hier ist meine vollständige Datenbank-Klasse (es ist nicht zu groß)

// 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)") 
     } 
    } 
} 

Irgendwelche Ideen, was der Stack-Trace (nicht sehr Stacky ist, nicht wahr?) Sollte bedeuten, oder, wie es in dieser Situation ankommt ? Kein Wunder, dass es abstürzt, wenn die Dinge so laufen.

UPDATE Obwohl ich, dass Stack-Trace sagt, dass irgendwo in Database.checkSchemaVersion(connection : Connection) ->() es glauben zu PersonRepository.hydrate(Row) -> Person ein direkter Aufruf ist und dies zusätzlich Fremd, hier ist der entsprechende Abschnitt von 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

sieht so aus, als ob diese Crash-Logs gelöscht werden. kannst du bitte auch den Code für PersonRepository posten. sieht aus wie es zu 'PersonRepository.getInstance() kommt. UpdateSchema (von: schemaVersion, zu: build)' Linie – dRAGONAIR

+0

@dRAGONAIR - Ich habe einen Abschnitt dieser Klasse hinzugefügt, aber ich finde es nicht relevant. Aus der Stack-Trace sollte folgen, dass es einen direkten Aufruf von 'Database.checkSchemaVersion (Verbindung: Verbindung)' zu 'PersonRepository.hydrate (Zeile) 'gibt - aber es gibt keinen solchen. Und wenn es nicht direkt ist, dann sollten Zwischenstufen zwischen diesen beiden bestehen. So funktionieren Anruflisten, oder? – mkilmanas

Antwort

1

Ein Tipp - vermeiden ! so viel wie möglich. Speziell für die Ausnahmebehandlung mit try. Es sollte einen guten Grund geben, warum Dinge werfen können und ich glaube, das ist der Grund für deinen Absturz.

Der Stack-Trace ist möglicherweise nicht vollständig offensichtlich, da einige der Methodenaufrufe vom Compiler für Release-Builds inline/optimiert werden können. In Ihrem Fall ist es passiert wahrscheinlich auf diese Weise:

  1. checkSchemaVersion(connection : Connection)
  2. PersonRepository.getInstance()
  3. PersonRepository.init()
  4. try! db.run()
  5. Exception geworfen wird, weil etwas faul ist passiert in Database

Wenn Sie sich nicht reproduzieren den Crash, den mein Rat wäre schreibe diesen Code ohne Kraftaufwand um und denke darüber nach, was zu tun ist, falls etwas schief geht. Eine Lösung könnte darin bestehen, failable Initialisierer zu verwenden und mögliche Werte stromaufwärts zu behandeln, d. H.

+0

Danke, Punkt in Bezug auf die "versuchen!". Ich habe diesen Fehler auf andere Weise herausgefunden - es stellte sich heraus, dass ich eine neue Spalte sowohl in 'init()' als auch 'updateSchema()' in 'TaskRepository' definiert hatte (also nicht einmal dieses Repository) und es funktionierte gut für Apps Aktualisierung von der vorherigen Version, aber es würde wegen der 'try!' abstürzen, wenn die App neu installiert ist. Wie bei der Hauptaufgabe, den Sprung von Level 4 zu Level 3 im Stack Trace zu erklären, macht es immer noch keinen Sinn, da 'hydrate()' nur für Daten verwendet wird, die von DB geladen werden meine App. – mkilmanas