SQLite implementation of substitution plan persistence added, working in simulator, untested on real devices

This commit is contained in:
Deniz Duezgoeren
2019-07-11 18:37:14 +02:00
parent 2488d9690d
commit 92a01a83c7
24 changed files with 1141 additions and 651 deletions
+54 -1
View File
@@ -7,6 +7,7 @@
//
import UIKit
import CoreData
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
@@ -39,8 +40,60 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
func applicationWillTerminate(_ application: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
self.saveContext()
}
// MARK: - Core Data stack
lazy var persistentContainer: NSPersistentContainer = {
/*
The persistent container for the application. This implementation
creates and returns a container, having loaded the store for the
application to it. This property is optional since there are legitimate
error conditions that could cause the creation of the store to fail.
*/
let container = NSPersistentContainer(name: "Model")
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
// Replace this implementation with code to handle the error appropriately.
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
/*
Typical reasons for an error here include:
* The parent directory does not exist, cannot be created, or disallows writing.
* The persistent store is not accessible, due to permissions or data protection when the device is locked.
* The device is out of space.
* The store could not be migrated to the current model version.
Check the error message to determine what the actual problem was.
*/
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
return container
}()
// MARK: - Core Data Saving support
func saveContext () {
let context = persistentContainer.viewContext
if context.hasChanges {
do {
try context.save()
} catch {
// Replace this implementation with code to handle the error appropriately.
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
let nserror = error as NSError
fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
}
}
}
static var persistentContainer: NSPersistentContainer {
return (UIApplication.shared.delegate as! AppDelegate).persistentContainer
}
static var viewContext: NSManagedObjectContext {
return persistentContainer.viewContext
}
}
+46 -3
View File
@@ -6,13 +6,24 @@
// Copyright © 2019 Deniz Duezgoeren. All rights reserved.
//
import Foundation
import UIKit
import Alamofire
import SwiftSoup
import SQLite
class DataFetcher {
let path = Bundle.main.path(forResource: "db", ofType: "sqlite3")
let substitutions = Table("substitutions")
let id = Expression<Int64>("id")
let group = Expression<String>("group")
let course = Expression<String>("course")
let additional = Expression<String>("additional")
let date = Expression<String>("date")
let time = Expression<String>("time")
let room = Expression<String>("room")
func doAsync(completionHandler: @escaping (_ substitutions: Array<SubstModel>) -> ()) {
DispatchQueue(label: "work-queue").async {
let url = "https://djd4rkn355.github.io/subst_test.html"
@@ -31,13 +42,34 @@ class DataFetcher {
let doc: Document = try SwiftSoup.parse(html)
let rows: Elements = try doc.select("tr")
let db = try Connection(path!)
try db.run(substitutions.create { t in
t.column(id, primaryKey: true)
t.column(group)
t.column(course)
t.column(additional)
t.column(date)
t.column(time)
t.column(room)
})
for i in (0..<rows.size()) {
let row = rows.get(i)
let cols = try row.select("th")
subst.append(SubstModel(group: try cols.get(0).text(), course: try cols.get(3).text(), additional: try cols.get(5).text(),
date: try cols.get(1).text(), time: try cols.get(2).text(), room: try cols.get(4).text()))
let mGroup = try cols.get(0).text()
let mCourse = try cols.get(3).text()
let mAdditional = try cols.get(5).text()
let mDate = try cols.get(1).text()
let mTime = try cols.get(2).text()
let mRoom = try cols.get(4).text()
subst.append(SubstModel(group: mGroup, course: mCourse, additional: mAdditional,
date: mDate, time: mTime, room: mRoom))
let insert = substitutions.insert(group <- mGroup, course <- mCourse, additional <- mAdditional,
date <- mDate, time <- mTime, room <- mRoom)
_ = try db.run(insert)
}
} catch Exception.Error(let type, let message) {
@@ -49,6 +81,17 @@ class DataFetcher {
return subst
}
func getFromDatabase() -> [SubstModel] {
var substs = [SubstModel]()
do {
let db = try Connection(path!)
for subst in try db.prepare(substitutions) {
substs.append(SubstModel(group: subst[group], course: subst[course], additional: subst[additional], date: subst[date], time: subst[time], room: subst[room]))
}
} catch {}
return substs
}
func getImage(from icon: String) -> UIImage? {
var imagePath = ""
let i = icon.lowercased()
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="14490.98" systemVersion="18D109" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
<entity name="Meal" representedClassName=".Meal" syncable="YES" codeGenerationType="category">
<attribute name="priority" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES" syncable="YES"/>
<attribute name="text" optional="YES" attributeType="String" syncable="YES"/>
</entity>
<entity name="Substitution" representedClassName=".Substitution" syncable="YES" codeGenerationType="category">
<attribute name="additional" optional="YES" attributeType="String" syncable="YES"/>
<attribute name="course" optional="YES" attributeType="String" syncable="YES"/>
<attribute name="date" optional="YES" attributeType="String" syncable="YES"/>
<attribute name="group" optional="YES" attributeType="String" syncable="YES"/>
<attribute name="priority" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES" syncable="YES"/>
<attribute name="room" optional="YES" attributeType="String" syncable="YES"/>
<attribute name="time" optional="YES" attributeType="String" syncable="YES"/>
</entity>
<elements>
<element name="Substitution" positionX="-54" positionY="-9" width="128" height="148"/>
<element name="Meal" positionX="176.953125" positionY="26.046875" width="128" height="73"/>
</elements>
</model>
+6 -10
View File
@@ -7,9 +7,6 @@
//
import UIKit
import SwiftSoup
import Alamofire
import SQLite3
class PlanViewController : UIViewController, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
@@ -17,7 +14,6 @@ class PlanViewController : UIViewController, UICollectionViewDataSource, UIColle
@IBOutlet weak var collectionView: UICollectionView!
var substs = Array<SubstModel>()
private let refreshControl = UIRefreshControl()
var db: OpaquePointer?
let df = DataFetcher()
override func viewWillAppear(_ animated: Bool) {
@@ -43,6 +39,9 @@ class PlanViewController : UIViewController, UICollectionViewDataSource, UIColle
override func viewDidLoad() {
super.viewDidLoad()
collectionView.backgroundColor = UIColor(red: 0.8, green: 0.8, blue: 0.8, alpha: 1.0)
self.substs = self.df.getFromDatabase()
self.collectionView.reloadData()
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
@@ -76,17 +75,14 @@ class PlanViewController : UIViewController, UICollectionViewDataSource, UIColle
}
}
// cell.courseIcon.frame = CGRect(x: 0, y: 0, width: cell.course.frame.height, height: cell.course.frame.height)
// cell.backgroundColor = UIColor(red: 0.39, green: 0.71, blue: 0.96, alpha: 1.0)
cell.backgroundColor = UIColor(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
cell.tintView.backgroundColor = cell.backgroundColor
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print("You selected cell#\(indexPath.item)!")
}
// func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
// print("You selected cell#\(indexPath.item)!")
// }
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: view.frame.size.width, height: 108)
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="14490.98" systemVersion="18D109" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
<entity name="Entity" representedClassName="Entity" syncable="YES" codeGenerationType="class"/>
<elements>
<element name="Entity" positionX="-63" positionY="-18" width="128" height="45"/>
</elements>
</model>
View File