swift sqlite 예제 feat : FileManager, Bundle.main, defer
sqlite import
import SQLite3
주요 구문
var db : OpaquePointer? = nil //SQLite 연결 정보 - 구조체
var stmt : OpaquePointer? = nil //컴파일된 SQL을 담을 객체
sqlite3_open(dbPath, &db) // db연결함수 - db 객체가 생성
sqlite3_prepare(db, sql, -1, &stmt, nil) //구문을 전달 준비 - 컴파일된 sql 구문 객체가 생성됨
sqlite3_step(stmt) //컴파일된 sql 객체를 db에 전달 - stmt에는 db 연결 정보와 컴파일된 SQL 객체가 포함되어 있다
//위 함수의 호출이 끝나면 작성한 sql 쿼리문이 실행되어 테이블이 생성된다.
sqlite3_finalize(stmt) //컴파일된 sql 구문 객체를 삭제
sqlite3_close(db) //db 연결 종료 - db 객체가 해제됨
[1] db.sqlite 파일의 경로를 찾아서 반환
func getDBPath() -> String {
//데이터베이스 파일의 경로를 읽어오는 내용
//urls(for:in:) 메서드는 배열 형태로 반환하기 때문에 인덱스를 사용해서 접근해야 합니다.
//문서 디렉터리는 하나만 존재하기 때문에 first 속성을 사용하면 됩니다.
let fileMgr = FileManager()
let docPathURL = fileMgr.urls(for: .documentDirectory, in: .userDomainMask).first!
let dbPath = docPathURL.appendingPathComponent("db.sqlite").path
//dbPath 경로에 파일이 없다면, 앱 번들의 db.sqlite를 가져와 복사
if fileMgr.fileExists(atPath: dbPath) == false {
do {
//번들 경로
guard let dbSource = Bundle.main.path(forResource: "db", ofType: "sqlite")
else{
print("Bundle에 db.sqlite 파일이 존재하지 않습니다.")
return "error"
}
try fileMgr.copyItem(atPath: dbSource, toPath: dbPath)
} catch {
print("fail.. copying file...")
}
}
print("db.sqlite 파일 경로 : \(dbPath)")
return dbPath
}
guard 구문을 사용하면 sqlite3_finalize(), sqlite3_close() 함수를 처리할 위치가 애매해집니다.
guard else 블록 내에 구현해 줄 수 있지만 같은 코드를 중복으로 작성해야 하기 때문에
defer 블록을 사용해서 구현합니다.
defer 블록은 코드의 흐름과 관계없이 가장 마지막에 실행되는 블록입니다.
함수의 종료 직전에 실행되며 종료 시점에 처리해야 할 내용이 있다면 defer 블록 내에 작성하면 됩니다.
이 블록은 함수에서 사용된 리소스의 해제를 할 때 사용됩니다.
defer 블록은 sqlite3_open()의 실패로 인해 return을 만나서 함수가 종료되면 실행되지 않습니다.
함수의 종료문보다 먼저 작성이 되어야 하며 작성된 순서의 역순으로 호출됩니다.
[2] 데이터 베이스 관련 코드
func dbExecute(dbPath : String){
var db : OpaquePointer? = nil //SQLite 연결 정보 - 구조체
//db 연결 성공 확인
guard sqlite3_open(dbPath, &db) == SQLITE_OK else {
print("database connect fail...")
return
}
//데이터 베이스 연결 종료
defer {
print("close database connection")
sqlite3_close(db)
}
var stmt : OpaquePointer? = nil //컴파일된 SQL을 담을 객체
let sql = "CREATE TABLE IF NOT EXISTS sequence (num INTEGER)" //SQL 구문
guard sqlite3_prepare(db, sql, -1, &stmt, nil) == SQLITE_OK else {
print("prepare statment fail...")
return
}
//stmt 변수 해제
defer {
print("Finalize Statment")
sqlite3_finalize(stmt)
}
//테이블 생성
if sqlite3_step(stmt) == SQLITE_DONE {
print("create table success..")
}
}
[3] 호출
override func viewDidLoad() {
super.viewDidLoad()
let dbPath = self.getDBPath()
self.dbExecute(dbPath: dbPath)
}
참고
https://blog.naver.com/go4693/221388274001
https://blog.naver.com/go4693/221389139215
'아이폰 개발 > Swift' 카테고리의 다른 글
swift socket io 예제 (0) | 2021.03.31 |
---|---|
swift fmdb 예제 1 - feat: tableview , typealias , 튜플, do catch (0) | 2021.03.30 |
swift MVVM 패턴 예제 (0) | 2021.03.29 |
swift AutoLayout 7 - AutoLayout Landscape 이슈 (0) | 2021.03.29 |
swift AutoLayout 6 - UIButton 이벤트와 UIPageControl속성 (0) | 2021.03.29 |