diff --git a/YeolpumtaClone.xcodeproj/project.pbxproj b/YeolpumtaClone.xcodeproj/project.pbxproj index 942a3cc..8f30a23 100644 --- a/YeolpumtaClone.xcodeproj/project.pbxproj +++ b/YeolpumtaClone.xcodeproj/project.pbxproj @@ -8,6 +8,7 @@ /* Begin PBXBuildFile section */ 2296F3E462DE79581FEF0FD7 /* Pods_YeolpumtaClone.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F240E6EDDA8440264E1F9D6E /* Pods_YeolpumtaClone.framework */; }; + 4246D06D268DFC2900676BD2 /* ObjectForAdd.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4246D06C268DFC2900676BD2 /* ObjectForAdd.swift */; }; 428C96FB2680CBB3009B8E0D /* CalendarCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 428C96F62680CBB3009B8E0D /* CalendarCell.swift */; }; 428C96FC2680CBB3009B8E0D /* StatisticsCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 428C96F72680CBB3009B8E0D /* StatisticsCell.swift */; }; 428C96FD2680CBB3009B8E0D /* MenuBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 428C96F82680CBB3009B8E0D /* MenuBar.swift */; }; @@ -37,6 +38,7 @@ /* Begin PBXFileReference section */ 03174D305EDA1C3BA6C26926 /* Pods-YeolpumtaClone.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-YeolpumtaClone.release.xcconfig"; path = "Target Support Files/Pods-YeolpumtaClone/Pods-YeolpumtaClone.release.xcconfig"; sourceTree = ""; }; 15BB2CD8CEE5BA889310A14D /* Pods-YeolpumtaClone.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-YeolpumtaClone.debug.xcconfig"; path = "Target Support Files/Pods-YeolpumtaClone/Pods-YeolpumtaClone.debug.xcconfig"; sourceTree = ""; }; + 4246D06C268DFC2900676BD2 /* ObjectForAdd.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ObjectForAdd.swift; sourceTree = ""; }; 428C96F62680CBB3009B8E0D /* CalendarCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CalendarCell.swift; sourceTree = ""; }; 428C96F72680CBB3009B8E0D /* StatisticsCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StatisticsCell.swift; sourceTree = ""; }; 428C96F82680CBB3009B8E0D /* MenuBar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MenuBar.swift; sourceTree = ""; }; @@ -87,6 +89,14 @@ path = Pods; sourceTree = ""; }; + 4246D06A268DFC0900676BD2 /* Model */ = { + isa = PBXGroup; + children = ( + 4246D06C268DFC2900676BD2 /* ObjectForAdd.swift */, + ); + path = Model; + sourceTree = ""; + }; 428C96F52680CB3D009B8E0D /* Insights */ = { isa = PBXGroup; children = ( @@ -120,9 +130,9 @@ 6B3A20B3267606B800F3D04C /* YeolpumtaClone */ = { isa = PBXGroup; children = ( + 4246D06A268DFC0900676BD2 /* Model */, 6BC6F02E267B63010080A172 /* Extension */, 6B3A20DA267611E700F3D04C /* Constant */, - 6B3A20CB2676073C00F3D04C /* Model */, 6B3A20CA2676073A00F3D04C /* View */, 6B3A20C92676073800F3D04C /* Controller */, 6B3A20CD2676074800F3D04C /* Service */, @@ -164,13 +174,6 @@ path = View; sourceTree = ""; }; - 6B3A20CB2676073C00F3D04C /* Model */ = { - isa = PBXGroup; - children = ( - ); - path = Model; - sourceTree = ""; - }; 6B3A20CD2676074800F3D04C /* Service */ = { isa = PBXGroup; children = ( @@ -356,6 +359,7 @@ 428C96FF2680CBB3009B8E0D /* Statistics.swift in Sources */, 6B3A20B7267606B800F3D04C /* SceneDelegate.swift in Sources */, BD6A4530268184C1001F4808 /* EmailRegisterViewController.swift in Sources */, + 4246D06D268DFC2900676BD2 /* ObjectForAdd.swift in Sources */, BD6A4526267B1EF9001F4808 /* FirstViewController.swift in Sources */, 428C96FD2680CBB3009B8E0D /* MenuBar.swift in Sources */, 6B3A20CF2676077900F3D04C /* InsightsViewController.swift in Sources */, diff --git a/YeolpumtaClone/Controller/Home/AddObjectController.swift b/YeolpumtaClone/Controller/Home/AddObjectController.swift index 70bacc4..c14c557 100644 --- a/YeolpumtaClone/Controller/Home/AddObjectController.swift +++ b/YeolpumtaClone/Controller/Home/AddObjectController.swift @@ -7,10 +7,11 @@ import UIKit import SnapKit +import SQLite3 class AddObjectController: UIViewController { // MARK: - Properties - + private let objectLabel: UILabel = { let label = UILabel() label.text = "측정할 과목 이름" @@ -43,10 +44,18 @@ class AddObjectController: UIViewController { bt.layer.cornerRadius = 40 / 2 bt.backgroundColor = .red bt.addTarget(self, action: #selector(didTapColorButton), for: .touchUpInside) - return bt }() + // for SQLite + var objectList = [ObjectForAdd]() { + didSet { HomeViewController().tableView.reloadData() } + } + + let tableOne = "TableOne" + let tableTwo = "TableTwo" + + var db: OpaquePointer? // MARK: - Lifecycle override func viewDidLoad() { @@ -56,6 +65,9 @@ class AddObjectController: UIViewController { configureNavBar() configureUI() + makeQuery() + +// deleteAll() } // MARK: - Helpers @@ -67,9 +79,8 @@ class AddObjectController: UIViewController { navigationItem.leftBarButtonItem = UIBarButtonItem(image: UIImage(systemName: "chevron.backward"), style: .done, target: self, action: #selector(handleDismissal)) navigationItem.leftBarButtonItem?.tintColor = .white - navigationItem.rightBarButtonItem = UIBarButtonItem(title: "추가", style: .done, target: self, action: #selector(handleDismissal)) + navigationItem.rightBarButtonItem = UIBarButtonItem(title: "추가", style: .done, target: self, action: #selector(makeTable)) navigationItem.rightBarButtonItem?.tintColor = .white - } private func configureUI() { @@ -100,6 +111,112 @@ class AddObjectController: UIViewController { } } + // MARK: - SQLite + + func makeQuery() { + let fileURL = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false) + .appendingPathComponent("\(tableOne)Database.sqlite") + + if sqlite3_open(fileURL.path, &db) != SQLITE_OK { + print("error opening database") + } + + + let createTableString = """ + CREATE TABLE IF NOT EXISTS \(tableOne) ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + name TEXT) + """ + + if sqlite3_exec(db, createTableString, nil, nil, nil) != SQLITE_OK { + let errmsg = String(cString: sqlite3_errmsg(db)!) + print("error creating table: \(errmsg)") + } + } + + @objc func makeTable() { + let name = textField.text?.trimmingCharacters(in: .whitespacesAndNewlines) + + if(name?.isEmpty)!{ + textField.layer.borderColor = UIColor.red.cgColor + return + } + + var stmt: OpaquePointer? + let queryString = "INSERT INTO \(tableOne) (name) VALUES (?)" + + if sqlite3_prepare(db, queryString, -1, &stmt, nil) != SQLITE_OK{ + let errmsg = String(cString: sqlite3_errmsg(db)!) + print("error preparing insert: \(errmsg)") + return + } + + if sqlite3_bind_text(stmt, 1, name, -1, nil) != SQLITE_OK{ + let errmsg = String(cString: sqlite3_errmsg(db)!) + print("failure binding name: \(errmsg)") + return + } + + if sqlite3_step(stmt) != SQLITE_DONE { + let errmsg = String(cString: sqlite3_errmsg(db)!) + print("failure inserting hero: \(errmsg)") + return + } + + textField.text = "" + + readValues() + + print("Hero saved successfully") + + handleDismissal() + } + + func readValues(){ + + objectList.removeAll() + + let queryString = "SELECT * FROM \(tableOne)" + + var stmt:OpaquePointer? + + if sqlite3_prepare(db, queryString, -1, &stmt, nil) != SQLITE_OK{ + let errmsg = String(cString: sqlite3_errmsg(db)!) + print("error preparing insert: \(errmsg)") + return + } + + while(sqlite3_step(stmt) == SQLITE_ROW){ + let id = sqlite3_column_int(stmt, 0) + let name = String(cString: sqlite3_column_text(stmt, 1)) + + objectList.append(ObjectForAdd(id: Int(id), name: String(describing: name))) + } + } + + // 모든 테이블 삭제 + func deleteAll() { + var deleteStatement: OpaquePointer? + let deleteStatementString = "DROP TABLE \(tableOne)" + + if sqlite3_prepare_v2(db, deleteStatementString, -1, &deleteStatement, nil) == + SQLITE_OK { + + if sqlite3_step(deleteStatement) == SQLITE_DONE { + print("\nSuccessfully deleted table.") + + } else { + print("\nCould not delete table.") + } + } else { + let errmsg = String(cString: sqlite3_errmsg(db)!) + print("error creating table: \(errmsg)") + print("\nDELETE statement could not be prepared") + } + sqlite3_finalize(deleteStatement) + } + + // MARK: - Actions @objc private func handleDismissal() { @@ -122,3 +239,14 @@ extension AddObjectController: UIColorPickerViewControllerDelegate { } } +// color를 데이터로 저장할 때 사용 - https://stackoverflow.com/questions/17230720/best-way-to-save-and-retrieve-uicolors-to-core-data +//extension UIColor { +// +// class func color(data:Data) -> UIColor? { +// return try? NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data) as? UIColor +// } +// +// func encode() -> Data? { +// return try? NSKeyedArchiver.archivedData(withRootObject: self, requiringSecureCoding: false) +// } +//} diff --git a/YeolpumtaClone/Controller/Home/HomeViewController.swift b/YeolpumtaClone/Controller/Home/HomeViewController.swift index df21be6..4f27301 100644 --- a/YeolpumtaClone/Controller/Home/HomeViewController.swift +++ b/YeolpumtaClone/Controller/Home/HomeViewController.swift @@ -7,11 +7,17 @@ import SnapKit import UIKit +import SQLite3 -@available(iOS 14.0, *) class HomeViewController: UIViewController { // MARK: - Property + + static let homeViewController = HomeViewController() + var objectList = [ObjectForAdd]() { + didSet { tableView.reloadData() } + } + private let addButton: UIButton = { let button = UIButton(type: .system) button.setImage(UIImage(named: Constants.ImageName.plus), for: .normal) @@ -51,11 +57,18 @@ class HomeViewController: UIViewController { return label }() - private let tableView: UITableView = { + let tableView: UITableView = { let tableView = UITableView() tableView.separatorStyle = .none return tableView }() + + // for SQLite + + let tableOne = "TableOne" + let tableTwo = "TableTwo" + + var db: OpaquePointer? // MARK: - Lifecycle @@ -63,6 +76,8 @@ class HomeViewController: UIViewController { super.viewDidLoad() setupUI() + makeQuery() + readValues() } // MARK: - Helper @@ -112,13 +127,159 @@ class HomeViewController: UIViewController { tableView.register(HomeSectionCell.self, forCellReuseIdentifier: HomeSectionCell.cellIdentifier) tableView.register(HomeTimerCell.self, forCellReuseIdentifier: HomeTimerCell.cellIdentifier) - + tableView.delegate = self tableView.dataSource = self } + // MARK: - SQLite + func makeQuery() { + let fileURL = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false) + .appendingPathComponent("\(tableOne)Database.sqlite") + + if sqlite3_open(fileURL.path, &db) != SQLITE_OK { + print("error opening database") + } + + let createTableString = """ + CREATE TABLE IF NOT EXISTS \(tableOne) ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + name TEXT) + """ + + if sqlite3_exec(db, createTableString, nil, nil, nil) != SQLITE_OK { + let errmsg = String(cString: sqlite3_errmsg(db)!) + print("error creating table: \(errmsg)") + } + } + + func readValues(){ + + objectList.removeAll() + + let queryString = "SELECT * FROM \(tableOne)" + + var stmt:OpaquePointer? + + if sqlite3_prepare(db, queryString, -1, &stmt, nil) != SQLITE_OK{ + let errmsg = String(cString: sqlite3_errmsg(db)!) + print("error preparing insert: \(errmsg)") + return + } + + while(sqlite3_step(stmt) == SQLITE_ROW){ + let id = sqlite3_column_int(stmt, 0) + let name = String(cString: sqlite3_column_text(stmt, 1)) + + objectList.append(ObjectForAdd(id: Int(id), name: String(describing: name))) + } + } + + func delete(itemId: Int32) { + var deleteStatement: OpaquePointer? + let deleteStatementString = "DELETE FROM \(tableOne) WHERE Id = ?;" + + if sqlite3_prepare_v2(db, deleteStatementString, -1, &deleteStatement, nil) == + SQLITE_OK { + sqlite3_bind_int(deleteStatement, 1, itemId) + + if sqlite3_step(deleteStatement) == SQLITE_DONE { + print("\nSuccessfully deleted row.") + } else { + print("\nCould not delete row.") + } + } else { + print("\nDELETE statement could not be prepared") + } +// change() + } + + // Updating... + func change() { + createTwoTable() + insert() + drop() + changeName() + } + + func createTwoTable() { + var changeStatement: OpaquePointer? + let createStatementString = """ + CREATE TABLE IF NOT EXISTS \(tableTwo) ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + name TEXT) + """ + + if sqlite3_prepare_v2(db, createStatementString, -1, &changeStatement, nil) == + SQLITE_OK { + + if sqlite3_step(changeStatement) == SQLITE_DONE { + print("\nSuccessfully create new row.") + } else { + print("\nCould not create new row.") + } + } else { + print("\nCREATE statement could not be prepared") + } + + sqlite3_finalize(changeStatement) + } + + func insert() { + var changeStatement: OpaquePointer? + let insertStatementString = "INSERT INTO \(tableTwo) (id, name) select id, name from \(tableOne) o(id, name);" + + if sqlite3_prepare_v2(db, insertStatementString, -1, &changeStatement, nil) == + SQLITE_OK { + + if sqlite3_step(changeStatement) == SQLITE_DONE { + print("\nSuccessfully insert new row.") + } else { + print("\nCould not insert new row.") + } + } else { + print("\nCREATE22 statement could not be prepared") + } + sqlite3_finalize(changeStatement) + } + + func drop() { + var changeStatement: OpaquePointer? + let dropStatementString = "DROP TABLE \(tableOne)" + + if sqlite3_prepare_v2(db, dropStatementString, -1, &changeStatement, nil) == + SQLITE_OK { + + if sqlite3_step(changeStatement) == SQLITE_DONE { + print("\nSuccessfully drop old row.") + } else { + print("\nCould not drop old row.") + } + } else { + print("\nCREATE statement could not be prepared") + } + sqlite3_finalize(changeStatement) + } + + func changeName() { + var changeStatement: OpaquePointer? + let alterStaatementString = "ALTER TABLE \(tableTwo) rename to \(tableOne);" + + if sqlite3_prepare_v2(db, alterStaatementString, -1, &changeStatement, nil) == + SQLITE_OK { + + if sqlite3_step(changeStatement) == SQLITE_DONE { + print("\nSuccessfully alter row.") + } else { + print("\nCould not alter row.") + } + } else { + print("\nCREATE statement could not be prepared") + } + sqlite3_finalize(changeStatement) + } + // MARK: - Actions - @available(iOS 14.0, *) @objc func addObject() { let controller = AddObjectController() navigationController?.pushViewController(controller, animated: true) @@ -126,26 +287,41 @@ class HomeViewController: UIViewController { } } -@available(iOS 14.0, *) -extension HomeViewController: UITableViewDataSource { - func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - return 1 + 4 +extension HomeViewController: UITableViewDataSource, UITableViewDelegate { + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return 1 + objectList.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - switch indexPath.row { - case 0: + + if indexPath.row == 0 { guard let cell = tableView.dequeueReusableCell(withIdentifier: HomeSectionCell.cellIdentifier, for: indexPath) as? HomeSectionCell else { fatalError("tableView에서 HomeSectionCell을 dequeue하던 과정에서 에러가 발생하였습니다") } return cell - default: + } else { guard let cell = tableView.dequeueReusableCell(withIdentifier: HomeTimerCell.cellIdentifier, for: indexPath) as? HomeTimerCell else { fatalError("tableView에서 HomeTimerCell을 dequeue하던 과정에서 에러가 발생하였습니다") } + cell.goalLabel.text = "\(objectList[indexPath.row - 1].name)" + print("\(objectList[indexPath.row - 1])") + return cell } } - + func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) { + if editingStyle == .delete { + + tableView.beginUpdates() + + objectList.remove(at: indexPath.row - 1) + tableView.deleteRows(at: [indexPath], with: .fade) + print("done") + // * 현재 delete시 SQLite table의 정확한 데이터를 삭제하지 못합니다. 디버깅 필요 + delete(itemId: Int32(indexPath.row)) + readValues() + + } + } } diff --git a/YeolpumtaClone/Model/ObjectForAdd.swift b/YeolpumtaClone/Model/ObjectForAdd.swift new file mode 100644 index 0000000..50707b9 --- /dev/null +++ b/YeolpumtaClone/Model/ObjectForAdd.swift @@ -0,0 +1,18 @@ +// +// ObjectForAdd.swift +// YeolpumtaClone +// +// Created by 김태균 on 2021/07/01. +// + +import Foundation + +struct ObjectForAdd: Codable { + let id: Int + let name: String + + init(id: Int, name: String){ + self.id = id + self.name = name + } +} diff --git a/YeolpumtaClone/View/Home/HomeTimerCell.swift b/YeolpumtaClone/View/Home/HomeTimerCell.swift index a6a80b9..a2c5acf 100644 --- a/YeolpumtaClone/View/Home/HomeTimerCell.swift +++ b/YeolpumtaClone/View/Home/HomeTimerCell.swift @@ -9,9 +9,12 @@ import UIKit class HomeTimerCell: UITableViewCell { // MARK: - Initializer + + var objectList = [ObjectForAdd]() + static let cellIdentifier = String(describing: HomeTimerCell.self) - private let playButton: UIButton = { + let playButton: UIButton = { let button = UIButton(type: .system) button.setImage(UIImage(systemName: "play.fill"), for: .normal) button.tintColor = .white @@ -19,7 +22,7 @@ class HomeTimerCell: UITableViewCell { return button }() - private let goalLabel: UILabel = { + let goalLabel: UILabel = { let label = UILabel() label.text = "자소서" label.font = UIFont.systemFont(ofSize: 17, weight: .bold)