Adding datasource for Core Data

This commit is contained in:
Selim Mustafaev 2022-03-28 00:44:45 +03:00
parent 1c12fe5b40
commit 49046d5619
9 changed files with 293 additions and 6 deletions

View File

@ -59,6 +59,11 @@
7A49F51227D406CB00AEAAE0 /* VName.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A49F50B27D406CB00AEAAE0 /* VName.swift */; };
7A49F51527D40C6100AEAAE0 /* AutoCat2.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 7A49F51327D40C6100AEAAE0 /* AutoCat2.xcdatamodeld */; };
7A9F2AC327E71531006492A9 /* ACTabBarController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A9F2AC227E71531006492A9 /* ACTabBarController.swift */; };
7AE32D6427F05F89004EF6E0 /* VehicleCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AE32D6327F05F89004EF6E0 /* VehicleCell.swift */; };
7AE32D6627F063A1004EF6E0 /* UIEdgeInsets.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AE32D6527F063A1004EF6E0 /* UIEdgeInsets.swift */; };
7AE32D6927F06536004EF6E0 /* CoreDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AE32D6827F06536004EF6E0 /* CoreDataSource.swift */; };
7AE32D6E27F06D2D004EF6E0 /* SwiftDate in Frameworks */ = {isa = PBXBuildFile; productRef = 7AE32D6D27F06D2D004EF6E0 /* SwiftDate */; };
7AE32D7127F06DA4004EF6E0 /* DateSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AE32D7027F06DA4004EF6E0 /* DateSection.swift */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@ -167,6 +172,10 @@
7A49F50B27D406CB00AEAAE0 /* VName.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VName.swift; sourceTree = "<group>"; };
7A49F51427D40C6100AEAAE0 /* Shared.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = Shared.xcdatamodel; sourceTree = "<group>"; };
7A9F2AC227E71531006492A9 /* ACTabBarController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ACTabBarController.swift; sourceTree = "<group>"; };
7AE32D6327F05F89004EF6E0 /* VehicleCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VehicleCell.swift; sourceTree = "<group>"; };
7AE32D6527F063A1004EF6E0 /* UIEdgeInsets.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIEdgeInsets.swift; sourceTree = "<group>"; };
7AE32D6827F06536004EF6E0 /* CoreDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreDataSource.swift; sourceTree = "<group>"; };
7AE32D7027F06DA4004EF6E0 /* DateSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateSection.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -198,6 +207,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
7AE32D6E27F06D2D004EF6E0 /* SwiftDate in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -220,6 +230,7 @@
6841A709FA6B606978425A26 /* UIViewController.swift */,
7A28283027E721A70049BDBF /* UIView.swift */,
7A28283227E7263B0049BDBF /* UIStackView.swift */,
7AE32D6527F063A1004EF6E0 /* UIEdgeInsets.swift */,
);
path = Extensions;
sourceTree = "<group>";
@ -248,6 +259,7 @@
6841AEAC436660C91E968C9F /* Components */ = {
isa = PBXGroup;
children = (
7AE32D6727F06512004EF6E0 /* TableView */,
7A24C19927EE259000049E7F /* PlateView */,
7A28282D27E720830049BDBF /* ACTabBar */,
6841A0EB55A59DAC94129594 /* Extensions */,
@ -312,6 +324,7 @@
7A49F4A127D4061900AEAAE0 /* AutoCat2 */ = {
isa = PBXGroup;
children = (
7AE32D6227F05F5D004EF6E0 /* Cells */,
7A24C19427EE212E00049E7F /* Fonts */,
7A49F4A227D4061900AEAAE0 /* AppDelegate.swift */,
7A49F4A427D4061900AEAAE0 /* SceneDelegate.swift */,
@ -347,6 +360,7 @@
7A49F4D827D4064500AEAAE0 /* AutoCatCore */ = {
isa = PBXGroup;
children = (
7AE32D6F27F06D87004EF6E0 /* DataSource */,
7A49F51327D40C6100AEAAE0 /* AutoCat2.xcdatamodeld */,
7A49F50427D406CB00AEAAE0 /* Models */,
7A49F4FF27D406C300AEAAE0 /* Services */,
@ -407,6 +421,30 @@
path = Models;
sourceTree = "<group>";
};
7AE32D6227F05F5D004EF6E0 /* Cells */ = {
isa = PBXGroup;
children = (
7AE32D6327F05F89004EF6E0 /* VehicleCell.swift */,
);
path = Cells;
sourceTree = "<group>";
};
7AE32D6727F06512004EF6E0 /* TableView */ = {
isa = PBXGroup;
children = (
7AE32D6827F06536004EF6E0 /* CoreDataSource.swift */,
);
path = TableView;
sourceTree = "<group>";
};
7AE32D6F27F06D87004EF6E0 /* DataSource */ = {
isa = PBXGroup;
children = (
7AE32D7027F06DA4004EF6E0 /* DateSection.swift */,
);
path = DataSource;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXHeadersBuildPhase section */
@ -494,6 +532,9 @@
dependencies = (
);
name = AutoCatCore;
packageProductDependencies = (
7AE32D6D27F06D2D004EF6E0 /* SwiftDate */,
);
productName = AutoCatCore;
productReference = 7A49F4D727D4064500AEAAE0 /* AutoCatCore.framework */;
productType = "com.apple.product-type.framework";
@ -559,6 +600,7 @@
packageReferences = (
7A48B26527D9442A004D1A4B /* XCRemoteSwiftPackageReference "PKHUD" */,
7A28283427E74C110049BDBF /* XCRemoteSwiftPackageReference "SwiftEntryKit" */,
7AE32D6C27F06D2D004EF6E0 /* XCRemoteSwiftPackageReference "SwiftDate" */,
);
productRefGroup = 7A49F4A027D4061900AEAAE0 /* Products */;
projectDirPath = "";
@ -626,6 +668,8 @@
7A49F4A727D4061900AEAAE0 /* ViewController.swift in Sources */,
7A49F4A327D4061900AEAAE0 /* AppDelegate.swift in Sources */,
7A49F4A527D4061900AEAAE0 /* SceneDelegate.swift in Sources */,
7AE32D6427F05F89004EF6E0 /* VehicleCell.swift in Sources */,
7AE32D6927F06536004EF6E0 /* CoreDataSource.swift in Sources */,
6841AF924E165F1B3A3B5FB5 /* AuthController.swift in Sources */,
6841A592745CDD869709EFA7 /* MainTabController.swift in Sources */,
6841A8FF53F0AADF96B138C1 /* UIControl.swift in Sources */,
@ -634,6 +678,7 @@
6841A80BB89BFD8D18E79680 /* UITextField.swift in Sources */,
7A24C19F27EE26B900049E7F /* CenterTextLayer.swift in Sources */,
6841A5FE3E4927BF0EFF19F5 /* UIViewController.swift in Sources */,
7AE32D6627F063A1004EF6E0 /* UIEdgeInsets.swift in Sources */,
7A28282F27E720AC0049BDBF /* ACTabBarButton.swift in Sources */,
6841A0EE0ECCDB3519F728E6 /* HistoryController.swift in Sources */,
7A28283127E721A70049BDBF /* UIView.swift in Sources */,
@ -682,6 +727,7 @@
7A49F51527D40C6100AEAAE0 /* AutoCat2.xcdatamodeld in Sources */,
7A49F50E27D406CB00AEAAE0 /* User.swift in Sources */,
7A49F4FA27D406B200AEAAE0 /* ApiError.swift in Sources */,
7AE32D7127F06DA4004EF6E0 /* DateSection.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -1169,6 +1215,14 @@
minimumVersion = 5.0.0;
};
};
7AE32D6C27F06D2D004EF6E0 /* XCRemoteSwiftPackageReference "SwiftDate" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/malcommac/SwiftDate";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = 6.0.0;
};
};
/* End XCRemoteSwiftPackageReference section */
/* Begin XCSwiftPackageProductDependency section */
@ -1182,6 +1236,11 @@
package = 7A48B26527D9442A004D1A4B /* XCRemoteSwiftPackageReference "PKHUD" */;
productName = PKHUD;
};
7AE32D6D27F06D2D004EF6E0 /* SwiftDate */ = {
isa = XCSwiftPackageProductDependency;
package = 7AE32D6C27F06D2D004EF6E0 /* XCRemoteSwiftPackageReference "SwiftDate" */;
productName = SwiftDate;
};
/* End XCSwiftPackageProductDependency section */
/* Begin XCVersionGroup section */

View File

@ -9,6 +9,15 @@
"version" : "5.4.0"
}
},
{
"identity" : "swiftdate",
"kind" : "remoteSourceControl",
"location" : "https://github.com/malcommac/SwiftDate",
"state" : {
"revision" : "6190d0cefff3013e77ed567e6b074f324e5c5bf5",
"version" : "6.3.1"
}
},
{
"identity" : "swiftentrykit",
"kind" : "remoteSourceControl",

View File

@ -12,12 +12,33 @@
<key>AutoCat2.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>1</integer>
<integer>0</integer>
</dict>
<key>AutoCatCore.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>0</integer>
<integer>1</integer>
</dict>
<key>SwiftDate (Playground) 1.xcscheme</key>
<dict>
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>3</integer>
</dict>
<key>SwiftDate (Playground) 2.xcscheme</key>
<dict>
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>4</integer>
</dict>
<key>SwiftDate (Playground).xcscheme</key>
<dict>
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>2</integer>
</dict>
</dict>
</dict>

View File

@ -0,0 +1,37 @@
//
// VehicleCell.swift
// AutoCat2
//
// Created by Selim Mustafaev on 27.03.2022.
//
import UIKit
import AutoCatCore
class VehicleCell: UITableViewCell {
private let numberLabel = UILabel()
.disableTranslatesAutoresizingMaskIntoConstraints()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
setup()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setup() {
contentView.addSubview(numberLabel)
numberLabel.pin(to: contentView, insets: .init(all: 8))
}
}
extension VehicleCell: ConfigurableCell {
func configure(with item: CDVehicle) {
}
}

View File

@ -0,0 +1,20 @@
//
// UIEdgeInsets.swift
// AutoCat2
//
// Created by Selim Mustafaev on 27.03.2022.
//
import UIKit
extension UIEdgeInsets {
init(all: CGFloat) {
self.init(top: all, left: all, bottom: all, right: all)
}
init(vertical: CGFloat = 0, horizontal: CGFloat = 0) {
self.init(top: vertical, left: horizontal, bottom: vertical, right: horizontal)
}
}

View File

@ -0,0 +1,64 @@
//
// CoreDataSource.swift
// AutoCat2
//
// Created by Selim Mustafaev on 27.03.2022.
//
import UIKit
import CoreData
import AutoCatCore
protocol ConfigurableCell {
associatedtype Item
func configure(with item: Item)
}
typealias ConfigurableTableViewCell = UITableViewCell & ConfigurableCell
class CoreDataSource<Item: NSManagedObject, Cell: ConfigurableTableViewCell>: NSObject, NSFetchedResultsControllerDelegate where Cell.Item == Item {
private let tableView: UITableView
private let dataSource: UITableViewDiffableDataSource<DateSection<Item>, Item>
private let fetchedResults: NSFetchedResultsController<Item>
init(tableView: UITableView, context: NSManagedObjectContext) {
let cellIdentifier = String(describing: Cell.self)
self.tableView = tableView
self.dataSource = UITableViewDiffableDataSource(tableView: tableView) { tv, ip, item in
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier,
for: ip) as? Cell
cell?.configure(with: item)
return cell
}
if let fetchRequest = Item.fetchRequest() as? NSFetchRequest<Item> {
fetchRequest.sortDescriptors = [NSSortDescriptor(key: "number", ascending: true)]
let fr = NSFetchRequest<Item>(entityName: "Vehicle")
fr.sortDescriptors = []
self.fetchedResults = NSFetchedResultsController(fetchRequest: fr,
managedObjectContext: context,
sectionNameKeyPath: nil,
cacheName: nil)
} else {
self.fetchedResults = NSFetchedResultsController()
}
super.init()
self.tableView.dataSource = self.dataSource
self.fetchedResults.delegate = self
try? self.fetchedResults.performFetch()
}
// MARK: - NSFetchedResultsControllerDelegate
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChangeContentWith snapshot: NSDiffableDataSourceSnapshotReference) {
let snapshotBridged = snapshot as NSDiffableDataSourceSnapshot<DateSection<Item>, Item>
dataSource.apply(snapshotBridged)
}
}

View File

@ -11,10 +11,14 @@ class HistoryController: UIViewController {
private lazy var tableView: UITableView = {
let table = UITableView()
let cellIdentifier = String(describing: VehicleCell.self)
table.register(VehicleCell.self, forCellReuseIdentifier: cellIdentifier)
table.translatesAutoresizingMaskIntoConstraints = false
return table
}()
private var dataSource: CoreDataSource<CDVehicle, VehicleCell>?
override func viewDidLoad() {
super.viewDidLoad()
@ -22,6 +26,19 @@ class HistoryController: UIViewController {
view.addSubview(tableView)
tableView.pin(to: view)
showHistory()
}
func showHistory() {
Task {
do {
let storageService = try await StorageService.shared
dataSource = CoreDataSource(tableView: tableView, context: storageService.context)
} catch {
show(error: error)
}
}
}
func checkPlateNumber(_ number: String) async {

View File

@ -0,0 +1,60 @@
//
// DateSection.swift
// AutoCatCore
//
// Created by Selim Mustafaev on 27.03.2022.
//
import Foundation
import SwiftDate
public class DateSection<T: Hashable> {
private var timestamp: Double = 0
private var header: String
private var elements: [T]
public init(timestamp: Double, items: [T]) {
let formatter = DateFormatter()
formatter.dateStyle = .medium
formatter.timeStyle = .medium
let now = DateInRegion(Date(), region: Region.current)
let monthStart = now.dateAtStartOf(.month)
let weekStart = now.dateAtStartOf(.weekOfMonth)
let date = Date(timeIntervalSince1970: timestamp)
let dateInRegion = DateInRegion(date, region: Region.current)
if dateInRegion.isToday {
self.header = NSLocalizedString("Today", comment: "")
}
else if dateInRegion.isYesterday {
self.header = NSLocalizedString("Yesterday", comment: "")
} else if dateInRegion.isAfterDate(weekStart, granularity: .day) {
formatter.dateFormat = "EEEE"
self.header = formatter.string(from: date)
} else if dateInRegion.isAfterDate(monthStart, orEqual: false, granularity: .day) {
formatter.dateStyle = .medium
formatter.timeStyle = .none
self.header = formatter.string(from: date)
} else {
formatter.dateFormat = "LLLL yyyy"
self.header = formatter.string(from: date)
}
self.timestamp = timestamp
self.elements = items
}
}
extension DateSection: Hashable {
public static func == (lhs: DateSection<T>, rhs: DateSection<T>) -> Bool {
return lhs.timestamp == rhs.timestamp && lhs.elements == rhs.elements
}
public func hash(into hasher: inout Hasher) {
hasher.combine(self.timestamp)
hasher.combine(self.elements)
}
}

View File

@ -7,11 +7,11 @@ protocol StorageServiceProtocol {
func store(vehicle: Vehicle) throws -> CDVehicle
}
class StorageService: StorageServiceProtocol {
public class StorageService: StorageServiceProtocol {
private let container: NSPersistentCloudKitContainer
static var shared: StorageService {
public static var shared: StorageService {
get async throws {
print("!!!!!!!!!!!!!!!!!!!!!!!!! StorageService init")
let service = StorageService()
@ -59,11 +59,11 @@ class StorageService: StorageServiceProtocol {
// MARK: - StorageServiceProtocol
var context: NSManagedObjectContext {
public var context: NSManagedObjectContext {
container.viewContext
}
func store(vehicle: Vehicle) throws -> CDVehicle {
public func store(vehicle: Vehicle) throws -> CDVehicle {
let cdVehicle = CDVehicle(vehicle: vehicle, context: context)
try save()