@@ -21,7 +21,7 @@ private let SQLITE_TRANSIENT = unsafeBitCast(-1, to:sqlite3_destructor_type.self
2121// MARK:- SQLiteDB Class - Does all the work
2222@objc ( SQLiteDB)
2323class SQLiteDB : NSObject {
24- let DB_NAME = " data.db "
24+ var DB_NAME = " data.db "
2525 let QUEUE_LABEL = " SQLiteDB "
2626 static let shared = SQLiteDB ( )
2727 private var db : OpaquePointer ? = nil
@@ -31,61 +31,80 @@ class SQLiteDB:NSObject {
3131
3232 private override init ( ) {
3333 super. init ( )
34+ // Set up essentials
35+ queue = DispatchQueue ( label: QUEUE_LABEL, attributes: [ ] )
36+ // You need to set the locale in order for the 24-hour date format to work correctly on devices where 24-hour format is turned off
37+ fmt. locale = Locale ( identifier: " en_US_POSIX " )
38+ fmt. timeZone = TimeZone ( secondsFromGMT: 0 )
39+ fmt. dateFormat = " yyyy-MM-dd HH:mm:ss "
40+ }
41+
42+ deinit {
43+ closeDB ( )
44+ }
45+
46+ override var description : String {
47+ return " SQLiteDB: \( path) "
48+ }
49+
50+ // MARK:- Public Methods
51+ func openDB( copyFile: Bool = true ) -> Bool {
52+ if db != nil {
53+ closeDB ( )
54+ }
3455 // Set up for file operations
3556 let fm = FileManager . default
3657 // Get path to DB in Documents directory
3758 var docDir = NSSearchPathForDirectoriesInDomains ( FileManager . SearchPathDirectory. documentDirectory, FileManager . SearchPathDomainMask. userDomainMask, true ) [ 0 ]
3859 // If macOS, add app name to path since otherwise, DB could possibly interfere with another app using SQLiteDB
39- #if os(OSX)
40- let info = Bundle . main. infoDictionary!
41- let appName = info [ " CFBundleName " ] as! String
42- docDir = ( docDir as NSString ) . appendingPathComponent ( appName)
43- // Create folder if it does not exist
44- if !fm. fileExists ( atPath: docDir) {
45- do {
46- try fm. createDirectory ( atPath: docDir, withIntermediateDirectories: true , attributes: nil )
47- } catch {
48- assert ( false , " SQLiteDB: Error creating DB directory: \( docDir) on macOS " )
49- return
60+ #if os(OSX)
61+ let info = Bundle . main. infoDictionary!
62+ let appName = info [ " CFBundleName " ] as! String
63+ docDir = ( docDir as NSString ) . appendingPathComponent ( appName)
64+ // Create folder if it does not exist
65+ if !fm. fileExists ( atPath: docDir) {
66+ do {
67+ try fm. createDirectory ( atPath: docDir, withIntermediateDirectories: true , attributes: nil )
68+ } catch {
69+ assert ( false , " SQLiteDB: Error creating DB directory: \( docDir) on macOS " )
70+ return false
71+ }
5072 }
51- }
52- #endif
73+ #endif
5374 let path = ( docDir as NSString ) . appendingPathComponent ( DB_NAME)
54- // Check if copy of DB is there in Documents directory
55- if !( fm. fileExists ( atPath: path) ) {
56- // The database does not exist, so copy to Documents directory
57- guard let rp = Bundle . main. resourcePath else { return }
75+ // Check if DB is there in Documents directory
76+ if !( fm. fileExists ( atPath: path) ) && copyFile {
77+ // The database does not exist, so copy it
78+ guard let rp = Bundle . main. resourcePath else { return false }
5879 let from = ( rp as NSString ) . appendingPathComponent ( DB_NAME)
5980 do {
6081 try fm. copyItem ( atPath: from, toPath: path)
6182 } catch let error {
6283 assert ( false , " SQLiteDB: Failed to copy writable version of DB! Error - \( error. localizedDescription) " )
63- return
84+ return false
6485 }
6586 }
66- openDB ( path: path)
67- }
68-
69- private init ( path: String ) {
70- super. init ( )
71- openDB ( path: path)
72- }
73-
74- deinit {
75- closeDB ( )
76- }
77-
78- override var description : String {
79- return " SQLiteDB: \( path) "
87+ // Open the DB
88+ let cpath = path. cString ( using: String . Encoding. utf8)
89+ let error = sqlite3_open ( cpath!, & db)
90+ if error != SQLITE_OK {
91+ // Open failed, close DB and fail
92+ NSLog ( " SQLiteDB - failed to open DB! " )
93+ sqlite3_close ( db)
94+ return false
95+ }
96+ NSLog ( " SQLiteDB opened! " )
97+ return true
8098 }
8199
82- // MARK:- Public Methods
100+ // Return an ISO-8601 date string
83101 func dbDate( dt: Date ) -> String {
84102 return fmt. string ( from: dt)
85103 }
86104
87105 // Execute SQL with parameters and return result code
88- func execute( sql: String , parameters: [ Any ] ? = nil ) -> Int {
106+ func execute( sql: String , parameters: [ Any ] ? = nil ) -> Int {
107+ assert ( db != nil , " Database has not been opened! Use the openDB() method before any DB queries. " )
89108 var result = 0
90109 queue. sync {
91110 if let stmt = self . prepare ( sql: sql, params: parameters) {
@@ -96,7 +115,8 @@ class SQLiteDB:NSObject {
96115 }
97116
98117 // Run SQL query with parameters
99- func query( sql: String , parameters: [ Any ] ? = nil ) -> [ [ String : Any ] ] {
118+ func query( sql: String , parameters: [ Any ] ? = nil ) -> [ [ String : Any ] ] {
119+ assert ( db != nil , " Database has not been opened! Use the openDB() method before any DB queries. " )
100120 var rows = [ [ String: Any] ] ( )
101121 queue. sync {
102122 if let stmt = self . prepare ( sql: sql, params: parameters) {
@@ -108,6 +128,7 @@ class SQLiteDB:NSObject {
108128
109129 // Versioning
110130 func getDBVersion( ) -> Int {
131+ assert ( db != nil , " Database has not been opened! Use the openDB() method before any DB queries. " )
111132 var version = 0
112133 let arr = query ( sql: " PRAGMA user_version " )
113134 if arr. count == 1 {
@@ -118,34 +139,16 @@ class SQLiteDB:NSObject {
118139
119140 // Sets the 'user_version' value, a user-defined version number for the database. This is useful for managing migrations.
120141 func set( version: Int ) {
142+ assert ( db != nil , " Database has not been opened! Use the openDB() method before any DB queries. " )
121143 _ = execute ( sql: " PRAGMA user_version= \( version) " )
122144 }
123145
124146 // MARK:- Private Methods
125- private func openDB( path: String ) {
126- // Set up essentials
127- queue = DispatchQueue ( label: QUEUE_LABEL, attributes: [ ] )
128- // You need to set the locale in order for the 24-hour date format to work correctly on devices where 24-hour format is turned off
129- fmt. locale = Locale ( identifier: " en_US_POSIX " )
130- fmt. timeZone = TimeZone ( secondsFromGMT: 0 )
131- fmt. dateFormat = " yyyy-MM-dd HH:mm:ss "
132- // Open the DB
133- let cpath = path. cString ( using: String . Encoding. utf8)
134- let error = sqlite3_open ( cpath!, & db)
135- if error != SQLITE_OK {
136- // Open failed, close DB and fail
137- NSLog ( " SQLiteDB - failed to open DB! " )
138- sqlite3_close ( db)
139- return
140- }
141- NSLog ( " SQLiteDB opened! " )
142- }
143-
144147 private func closeDB( ) {
145148 if db != nil {
146149 // Get launch count value
147150 let ud = UserDefaults . standard
148- var launchCount = ud. integer ( forKey: " LaunchCount " )
151+ var launchCount = ud. integer ( forKey: " LaunchCount " )
149152 launchCount -= 1
150153 NSLog ( " SQLiteDB - Launch count \( launchCount) " )
151154 var clean = false
@@ -167,6 +170,7 @@ class SQLiteDB:NSObject {
167170 NSLog ( " SQLiteDB - Error cleaning DB " )
168171 }
169172 sqlite3_close ( db)
173+ self . db = nil
170174 }
171175 }
172176
@@ -188,9 +192,9 @@ class SQLiteDB:NSObject {
188192 if params != nil {
189193 // Validate parameters
190194 let cntParams = sqlite3_bind_parameter_count ( stmt)
191- let cnt = CInt ( params!. count)
192- if cntParams != cnt {
193- let msg = " SQLiteDB - failed to bind parameters, counts did not match. SQL: \( sql) , Parameters: \( params) "
195+ let cnt = params!. count
196+ if cntParams != CInt ( cnt) {
197+ let msg = " SQLiteDB - failed to bind parameters, counts did not match. SQL: \( sql) , Parameters: \( params! ) "
194198 NSLog ( msg)
195199 return nil
196200 }
@@ -220,7 +224,7 @@ class SQLiteDB:NSObject {
220224 if flag != SQLITE_OK {
221225 sqlite3_finalize ( stmt)
222226 if let error = String ( validatingUTF8: sqlite3_errmsg ( self . db) ) {
223- let msg = " SQLiteDB - failed to bind for SQL: \( sql) , Parameters: \( params) , Index: \( ndx) Error: \( error) "
227+ let msg = " SQLiteDB - failed to bind for SQL: \( sql) , Parameters: \( params! ) , Index: \( ndx) Error: \( error) "
224228 NSLog ( msg)
225229 }
226230 return nil
0 commit comments