Added dependency injection for better code reuse

This commit is contained in:
Raimund Wege
2017-08-21 15:43:29 +02:00
parent 57a00fba98
commit 5a23bdc7df
10 changed files with 73 additions and 39 deletions
@@ -23,7 +23,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
if let gpsFixes = checkIn.gpsFixes { if let gpsFixes = checkIn.gpsFixes {
if gpsFixes.count > 0 { if gpsFixes.count > 0 {
noData = false noData = false
let gpsFixController = GPSFixController(checkIn: checkIn) let gpsFixController = GPSFixController(checkIn: checkIn, coreDataManager: RegattaCoreDataManager.shared)
gpsFixController.sendAll(completion: { (withSuccess) in gpsFixController.sendAll(completion: { (withSuccess) in
allSuccess = allSuccess && withSuccess allSuccess = allSuccess && withSuccess
}) })
@@ -12,11 +12,6 @@ import CoreData
@objc(CheckIn) @objc(CheckIn)
class CheckIn: NSManagedObject { class CheckIn: NSManagedObject {
func initialize() {
event = RegattaCoreDataManager.shared.newEvent(checkIn: self)
leaderboard = RegattaCoreDataManager.shared.newLeaderboard(checkIn: self)
}
func updateWithCheckInData(checkInData: CheckInData) { func updateWithCheckInData(checkInData: CheckInData) {
serverURL = checkInData.serverURL serverURL = checkInData.serverURL
event.updateWithEventData(eventData: checkInData.eventData) event.updateWithEventData(eventData: checkInData.eventData)
@@ -18,10 +18,16 @@ import AVFoundation
class CheckInController : NSObject { class CheckInController : NSObject {
weak var coreDataManager: CoreDataManager!
weak var delegate: CheckInControllerDelegate? weak var delegate: CheckInControllerDelegate?
fileprivate var requestManager = RequestManager() fileprivate var requestManager = RequestManager()
init(coreDataManager: CoreDataManager) {
self.coreDataManager = coreDataManager
super.init()
}
// MARK: - CheckIn // MARK: - CheckIn
func checkIn(checkInData: CheckInData, completion: @escaping (_ withSuccess: Bool) -> Void) { func checkIn(checkInData: CheckInData, completion: @escaping (_ withSuccess: Bool) -> Void) {
@@ -92,23 +98,23 @@ class CheckInController : NSObject {
fileprivate func postCheckInSuccess(checkInData: CheckInData, completion: (_ withSuccess: Bool) -> Void) { fileprivate func postCheckInSuccess(checkInData: CheckInData, completion: (_ withSuccess: Bool) -> Void) {
switch checkInData.type { switch checkInData.type {
case .competitor: case .competitor:
let competitorCheckIn = RegattaCoreDataManager.shared.fetchCompetitorCheckIn( let competitorCheckIn = coreDataManager.fetchCompetitorCheckIn(
eventID: checkInData.eventID, eventID: checkInData.eventID,
leaderboardName: checkInData.leaderboardName, leaderboardName: checkInData.leaderboardName,
competitorID: checkInData.competitorID! competitorID: checkInData.competitorID!
) ?? RegattaCoreDataManager.shared.newCompetitorCheckIn() ) ?? coreDataManager.newCompetitorCheckIn()
competitorCheckIn.updateWithCheckInData(checkInData: checkInData) competitorCheckIn.updateWithCheckInData(checkInData: checkInData)
RegattaCoreDataManager.shared.saveContext() coreDataManager.saveContext()
checkInDidFinish(withSuccess: true, completion: completion) checkInDidFinish(withSuccess: true, completion: completion)
break break
case .mark: case .mark:
let markCheckIn = RegattaCoreDataManager.shared.fetchMarkCheckIn( let markCheckIn = coreDataManager.fetchMarkCheckIn(
eventID: checkInData.eventID, eventID: checkInData.eventID,
leaderboardName: checkInData.leaderboardName, leaderboardName: checkInData.leaderboardName,
markID: checkInData.markID! markID: checkInData.markID!
) ?? RegattaCoreDataManager.shared.newMarkCheckIn() ) ?? coreDataManager.newMarkCheckIn()
markCheckIn.updateWithCheckInData(checkInData: checkInData) markCheckIn.updateWithCheckInData(checkInData: checkInData)
RegattaCoreDataManager.shared.saveContext() coreDataManager.saveContext()
checkInDidFinish(withSuccess: true, completion: completion) checkInDidFinish(withSuccess: true, completion: completion)
break break
} }
@@ -31,6 +31,7 @@ class CompetitorViewController : SessionViewController, UINavigationControllerDe
@IBOutlet weak var announcementLabel: UILabel! @IBOutlet weak var announcementLabel: UILabel!
weak var competitorCheckIn: CompetitorCheckIn! weak var competitorCheckIn: CompetitorCheckIn!
weak var coreDataManager: CoreDataManager!
weak var countdownTimer: Timer? weak var countdownTimer: Timer?
@@ -173,7 +174,7 @@ class CompetitorViewController : SessionViewController, UINavigationControllerDe
teamImageView.image = image teamImageView.image = image
competitorCheckIn.teamImageRetry = false competitorCheckIn.teamImageRetry = false
competitorCheckIn.teamImageData = UIImageJPEGRepresentation(image, 0.8) competitorCheckIn.teamImageData = UIImageJPEGRepresentation(image, 0.8)
RegattaCoreDataManager.shared.saveContext() coreDataManager.saveContext()
success() success()
} }
@@ -300,7 +301,7 @@ class CompetitorViewController : SessionViewController, UINavigationControllerDe
// MARK: - Properties // MARK: - Properties
fileprivate lazy var competitorSessionController: CompetitorSessionController = { fileprivate lazy var competitorSessionController: CompetitorSessionController = {
return CompetitorSessionController(checkIn: self.competitorCheckIn) return CompetitorSessionController(checkIn: self.competitorCheckIn, coreDataManager: self.coreDataManager)
}() }()
} }
@@ -329,7 +330,7 @@ extension CompetitorViewController: UIImagePickerControllerDelegate {
fileprivate func pickedImage(image: UIImage) { fileprivate func pickedImage(image: UIImage) {
teamImageView.image = image teamImageView.image = image
competitorCheckIn.teamImageData = UIImageJPEGRepresentation(image, 0.8) competitorCheckIn.teamImageData = UIImageJPEGRepresentation(image, 0.8)
RegattaCoreDataManager.shared.saveContext() coreDataManager.saveContext()
if let data = competitorCheckIn.teamImageData { if let data = competitorCheckIn.teamImageData {
uploadTeamImageData(imageData: data) uploadTeamImageData(imageData: data)
} }
@@ -354,13 +355,13 @@ extension CompetitorViewController: UIImagePickerControllerDelegate {
fileprivate func uploadTeamImageDataSuccess(teamImageURL: String) { fileprivate func uploadTeamImageDataSuccess(teamImageURL: String) {
competitorCheckIn.teamImageRetry = false competitorCheckIn.teamImageRetry = false
competitorCheckIn.teamImageURL = teamImageURL competitorCheckIn.teamImageURL = teamImageURL
RegattaCoreDataManager.shared.saveContext() coreDataManager.saveContext()
refreshTeamImage() refreshTeamImage()
} }
fileprivate func uploadTeamImageDataFailure(error: Error) { fileprivate func uploadTeamImageDataFailure(error: Error) {
competitorCheckIn.teamImageRetry = true competitorCheckIn.teamImageRetry = true
RegattaCoreDataManager.shared.saveContext() coreDataManager.saveContext()
showUploadTeamImageFailureAlert(error: error) showUploadTeamImageFailureAlert(error: error)
refreshTeamImage() refreshTeamImage()
} }
@@ -391,8 +392,8 @@ extension CompetitorViewController: SessionViewControllerDelegate {
} }
fileprivate func performCheckOutCompleted(withSuccess: Bool) { fileprivate func performCheckOutCompleted(withSuccess: Bool) {
RegattaCoreDataManager.shared.deleteObject(object: competitorCheckIn) coreDataManager.deleteObject(object: competitorCheckIn)
RegattaCoreDataManager.shared.saveContext() coreDataManager.saveContext()
self.navigationController!.popViewController(animated: true) self.navigationController!.popViewController(animated: true)
} }
@@ -120,13 +120,15 @@ class CoreDataManager: NSObject {
func newCompetitorCheckIn() -> CompetitorCheckIn { func newCompetitorCheckIn() -> CompetitorCheckIn {
let checkIn = NSEntityDescription.insertNewObject(forEntityName: Entities.CompetitorCheckIn.rawValue, into: managedObjectContext) as! CompetitorCheckIn let checkIn = NSEntityDescription.insertNewObject(forEntityName: Entities.CompetitorCheckIn.rawValue, into: managedObjectContext) as! CompetitorCheckIn
checkIn.initialize() checkIn.event = newEvent(checkIn: checkIn)
checkIn.leaderboard = newLeaderboard(checkIn: checkIn)
return checkIn return checkIn
} }
func newMarkCheckIn() -> MarkCheckIn { func newMarkCheckIn() -> MarkCheckIn {
let checkIn = NSEntityDescription.insertNewObject(forEntityName: Entities.MarkCheckIn.rawValue, into: managedObjectContext) as! MarkCheckIn let checkIn = NSEntityDescription.insertNewObject(forEntityName: Entities.MarkCheckIn.rawValue, into: managedObjectContext) as! MarkCheckIn
checkIn.initialize() checkIn.event = newEvent(checkIn: checkIn)
checkIn.leaderboard = newLeaderboard(checkIn: checkIn)
return checkIn return checkIn
} }
@@ -40,9 +40,11 @@ class GPSFixController: NSObject {
} }
weak var checkIn: CheckIn! weak var checkIn: CheckIn!
weak var coreDataManager: CoreDataManager!
init(checkIn: CheckIn) { init(checkIn: CheckIn, coreDataManager: CoreDataManager) {
self.checkIn = checkIn self.checkIn = checkIn
self.coreDataManager = coreDataManager
} }
// MARK: - Send All // MARK: - Send All
@@ -127,8 +129,8 @@ class GPSFixController: NSObject {
DispatchQueue.main.async(execute: { DispatchQueue.main.async(execute: {
self.log(info: "Sending \(gpsFixes.count) GPS fixes was successful") self.log(info: "Sending \(gpsFixes.count) GPS fixes was successful")
self.postModeChangedNotification(mode: BatteryManager.sharedManager.batterySaving ? .BatterySaving : .Online) self.postModeChangedNotification(mode: BatteryManager.sharedManager.batterySaving ? .BatterySaving : .Online)
RegattaCoreDataManager.shared.deleteObjects(objects: gpsFixes) self.coreDataManager.deleteObjects(objects: gpsFixes)
RegattaCoreDataManager.shared.saveContext() self.coreDataManager.saveContext()
self.log(info: "\(gpsFixes.count) GPS fixes deleted") self.log(info: "\(gpsFixes.count) GPS fixes deleted")
success(gpsFixesLeft) success(gpsFixesLeft)
}) })
@@ -198,7 +198,7 @@ class HomeViewController: UIViewController {
fileprivate func reviewGPSFixes(checkIns: [CheckIn], completion: @escaping () -> Void) { fileprivate func reviewGPSFixes(checkIns: [CheckIn], completion: @escaping () -> Void) {
guard checkIns.count > 0 else { completion(); return } guard checkIns.count > 0 else { completion(); return }
let gpsFixController = GPSFixController.init(checkIn: checkIns[0]) let gpsFixController = GPSFixController.init(checkIn: checkIns[0], coreDataManager: RegattaCoreDataManager.shared)
gpsFixController.sendAll(completion: { (withSuccess) in gpsFixController.sendAll(completion: { (withSuccess) in
self.reviewGPSFixes(checkIns: Array(checkIns[1..<checkIns.count]), completion: completion) self.reviewGPSFixes(checkIns: Array(checkIns[1..<checkIns.count]), completion: completion)
}) })
@@ -340,22 +340,25 @@ class HomeViewController: UIViewController {
guard let competitorVC = segue.destination as? CompetitorViewController else { return } guard let competitorVC = segue.destination as? CompetitorViewController else { return }
guard let competitorCheckIn = selectedCheckIn as? CompetitorCheckIn else { return } guard let competitorCheckIn = selectedCheckIn as? CompetitorCheckIn else { return }
competitorVC.competitorCheckIn = competitorCheckIn competitorVC.competitorCheckIn = competitorCheckIn
competitorVC.coreDataManager = RegattaCoreDataManager.shared
selectedCheckIn = nil selectedCheckIn = nil
} else if (segue.identifier == Segue.Mark) { } else if (segue.identifier == Segue.Mark) {
guard let markVC = segue.destination as? MarkViewController else { return } guard let markVC = segue.destination as? MarkViewController else { return }
guard let markCheckIn = selectedCheckIn as? MarkCheckIn else { return } guard let markCheckIn = selectedCheckIn as? MarkCheckIn else { return }
markVC.markCheckIn = markCheckIn markVC.markCheckIn = markCheckIn
markVC.coreDataManager = RegattaCoreDataManager.shared
selectedCheckIn = nil selectedCheckIn = nil
} else if (segue.identifier == Segue.Scan) { } else if (segue.identifier == Segue.Scan) {
guard let scanVC = segue.destination as? ScanViewController else { return } guard let scanVC = segue.destination as? ScanViewController else { return }
scanVC.homeViewController = self scanVC.coreDataManager = RegattaCoreDataManager.shared
scanVC.delegate = self
} }
} }
// MARK: - Properties // MARK: - Properties
fileprivate lazy var checkInController: CheckInController = { fileprivate lazy var checkInController: CheckInController = {
let checkInController = CheckInController() let checkInController = CheckInController(coreDataManager: RegattaCoreDataManager.shared)
checkInController.delegate = self checkInController.delegate = self
return checkInController return checkInController
}() }()
@@ -368,6 +371,16 @@ class HomeViewController: UIViewController {
} }
// MARK: - ScanViewControllerDelegate
extension HomeViewController: ScanViewControllerDelegate {
func scanViewController(_ controller: ScanViewController, didScanCheckIn checkIn: CheckIn) {
selectedCheckIn = checkIn
}
}
// MARK: - UITableViewDataSource // MARK: - UITableViewDataSource
extension HomeViewController: UITableViewDataSource { extension HomeViewController: UITableViewDataSource {
@@ -13,6 +13,7 @@ class MarkViewController: SessionViewController {
@IBOutlet weak var markNameLabel: UILabel! @IBOutlet weak var markNameLabel: UILabel!
weak var markCheckIn: MarkCheckIn! weak var markCheckIn: MarkCheckIn!
weak var coreDataManager: CoreDataManager!
override func viewDidLoad() { override func viewDidLoad() {
super.viewDidLoad() super.viewDidLoad()
@@ -105,7 +106,7 @@ class MarkViewController: SessionViewController {
// MARK: - Properties // MARK: - Properties
fileprivate lazy var markSessionController: MarkSessionController = { fileprivate lazy var markSessionController: MarkSessionController = {
return MarkSessionController(checkIn: self.markCheckIn) return MarkSessionController(checkIn: self.markCheckIn, coreDataManager: self.coreDataManager)
}() }()
} }
@@ -121,8 +122,8 @@ extension MarkViewController: SessionViewControllerDelegate {
} }
fileprivate func performCheckOutCompleted(withSuccess: Bool) { fileprivate func performCheckOutCompleted(withSuccess: Bool) {
RegattaCoreDataManager.shared.deleteObject(object: markCheckIn) coreDataManager.deleteObject(object: markCheckIn)
RegattaCoreDataManager.shared.saveContext() coreDataManager.saveContext()
self.navigationController!.popViewController(animated: true) self.navigationController!.popViewController(animated: true)
} }
@@ -9,9 +9,16 @@
import UIKit import UIKit
import AVFoundation import AVFoundation
protocol ScanViewControllerDelegate: class {
func scanViewController(_ controller: ScanViewController, didScanCheckIn checkIn: CheckIn)
}
class ScanViewController: UIViewController { class ScanViewController: UIViewController {
weak var homeViewController: HomeViewController? weak var coreDataManager: CoreDataManager!
weak var delegate: ScanViewControllerDelegate?
@IBOutlet weak var previewView: UIView! @IBOutlet weak var previewView: UIView!
@IBOutlet weak var targetImageView: UIImageView! @IBOutlet weak var targetImageView: UIImageView!
@@ -137,7 +144,7 @@ class ScanViewController: UIViewController {
// MARK: - Properties // MARK: - Properties
fileprivate lazy var checkInController: CheckInController = { fileprivate lazy var checkInController: CheckInController = {
let checkInController = CheckInController() let checkInController = CheckInController(coreDataManager: self.coreDataManager)
checkInController.delegate = self checkInController.delegate = self
return checkInController return checkInController
}() }()
@@ -190,11 +197,16 @@ extension ScanViewController: AVCaptureMetadataOutputObjectsDelegate {
} }
} }
// TODO: remove completion and use a success and failure block
fileprivate func captureOutputSuccess(checkInData: CheckInData) { fileprivate func captureOutputSuccess(checkInData: CheckInData) {
checkInController.checkIn(checkInData: checkInData, completion: { (withSuccess) in checkInController.checkIn(checkInData: checkInData, completion: { (withSuccess) in
if withSuccess { if withSuccess {
self.homeViewController?.selectedCheckIn = RegattaCoreDataManager.shared.fetchCheckIn(checkInData: checkInData) if let checkIn = self.coreDataManager.fetchCheckIn(checkInData: checkInData) {
_ = self.navigationController?.popViewController(animated: true) self.delegate?.scanViewController(self, didScanCheckIn: checkIn)
_ = self.navigationController?.popViewController(animated: true)
} else {
self.startScanning()
}
} else { } else {
self.startScanning() self.startScanning()
} }
@@ -11,14 +11,16 @@ import UIKit
class SessionController: NSObject { class SessionController: NSObject {
weak var checkIn: CheckIn! weak var checkIn: CheckIn!
weak var coreDataManager: CoreDataManager!
var sendingBackgroundTask: UIBackgroundTaskIdentifier = UIBackgroundTaskInvalid var sendingBackgroundTask: UIBackgroundTaskIdentifier = UIBackgroundTaskInvalid
var sendingDate: Date = Date() var sendingDate: Date = Date()
fileprivate (set) var isTracking: Bool = false fileprivate (set) var isTracking: Bool = false
init(checkIn: CheckIn) { init(checkIn: CheckIn, coreDataManager: CoreDataManager) {
self.checkIn = checkIn self.checkIn = checkIn
self.coreDataManager = coreDataManager
super.init() super.init()
subscribeForNotifications() subscribeForNotifications()
} }
@@ -53,9 +55,9 @@ class SessionController: NSObject {
guard self.isTracking else { return } guard self.isTracking else { return }
guard let locationData = notification.userInfo?[LocationManager.UserInfo.LocationData] as? LocationData else { return } guard let locationData = notification.userInfo?[LocationManager.UserInfo.LocationData] as? LocationData else { return }
guard locationData.isValid else { return } guard locationData.isValid else { return }
let gpsFix = RegattaCoreDataManager.shared.newGPSFix(checkIn: self.checkIn) let gpsFix = self.coreDataManager.newGPSFix(checkIn: self.checkIn)
gpsFix.updateWithLocationData(locationData: locationData) gpsFix.updateWithLocationData(locationData: locationData)
RegattaCoreDataManager.shared.saveContext() self.coreDataManager.saveContext()
if self.sendingDate.compare(Date()) == .orderedAscending { if self.sendingDate.compare(Date()) == .orderedAscending {
self.sendingDate = Date().addingTimeInterval(BatteryManager.sharedManager.sendingPeriod) self.sendingDate = Date().addingTimeInterval(BatteryManager.sharedManager.sendingPeriod)
self.beginGPSFixSendingInBackgroundTask() self.beginGPSFixSendingInBackgroundTask()
@@ -105,7 +107,7 @@ class SessionController: NSObject {
checkIn.event.updateWithEventData(eventData: checkInData.eventData) checkIn.event.updateWithEventData(eventData: checkInData.eventData)
checkIn.leaderboard.updateWithLeaderboardData(leaderboardData: checkInData.leaderboardData) checkIn.leaderboard.updateWithLeaderboardData(leaderboardData: checkInData.leaderboardData)
checkIn.updateWithCheckInData(checkInData: checkInData) checkIn.updateWithCheckInData(checkInData: checkInData)
RegattaCoreDataManager.shared.saveContext() coreDataManager.saveContext()
completion() completion()
} }
@@ -139,7 +141,7 @@ class SessionController: NSObject {
// MARK: - Properties // MARK: - Properties
lazy var gpsFixController: GPSFixController = { lazy var gpsFixController: GPSFixController = {
let gpsFixController = GPSFixController(checkIn: self.checkIn) let gpsFixController = GPSFixController(checkIn: self.checkIn, coreDataManager: self.coreDataManager)
return gpsFixController return gpsFixController
}() }()