Skip to content

Commit

Permalink
Merge pull request #106 from boostcamp3-iOS/develop
Browse files Browse the repository at this point in the history
0.1.2
  • Loading branch information
presto95 authored Feb 11, 2019
2 parents 87b8df0 + 1903bac commit 4f89482
Show file tree
Hide file tree
Showing 71 changed files with 1,732 additions and 1,272 deletions.
1 change: 1 addition & 0 deletions .swiftlint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ excluded:
- FineDust/Supporting Files/AppDelegate.swift
- FineDust/Supporting Files/GeoConverter.swift
- Pods/
- FineDustTests/

line_length:
warning: 99
Expand Down
148 changes: 98 additions & 50 deletions FineDust.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

12 changes: 11 additions & 1 deletion FineDust/Common/Hour.swift
Original file line number Diff line number Diff line change
Expand Up @@ -84,5 +84,15 @@ enum Hour: Int, CaseIterable {
case twentyThree

/// 오류
case `default`
case `default`
}

extension Hour: Comparable {
static func < (lhs: Hour, rhs: Hour) -> Bool {
return lhs.rawValue < rhs.rawValue
}

static func == (lhs: Hour, rhs: Hour) -> Bool {
return lhs.rawValue == rhs.rawValue
}
}
78 changes: 78 additions & 0 deletions FineDust/Common/LocationObserver.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
//
// LocationObserver.swift
// FineDust
//
// Created by Presto on 06/02/2019.
// Copyright © 2019 boostcamp3rd. All rights reserved.
//

import Foundation
import UIKit

/// 위치 정보 관련 옵저버 프로토콜.
///
/// `registerLocationObserver()` 메소드를 `viewDidLoad()`에서 호출하여 옵저버 등록.
/// `unregisterLocationObserver()` 메소드를 `deinit`에서 호출하여 옵저버 해제.
protocol LocationObserver: class {

/// 위치 정보 갱신 작업이 성공했을 때의 핸들러.
func handleIfSuccess(_ notification: Notification)

/// 위치 정보 갱신 작업이 실패했을 때의 핸들러.
func handleIfFail(_ notification: Notification)

/// 위치 정보 권한이 허용되지 않았을 때의 핸들러.
func handleIfAuthorizationDenied(_ notification: Notification)

/// 위치 정보 옵저버 등록.
func registerLocationObserver()

/// 위치 정보 옵저버 해제.
func unregisterLocationObserver()
}

// MARK: - LocationObserver 프로토콜 초기 구현

extension LocationObserver where Self: UIViewController {

/// 위의 세 경우에 대한 옵저버 등록.
func registerLocationObserver() {
NotificationCenter.default.addObserver(
forName: .didSuccessUpdatingAllLocationTasks,
object: nil,
queue: nil) { [weak self] notification in
self?.handleIfSuccess(notification)
}
NotificationCenter.default.addObserver(
forName: .didFailUpdatingAllLocationTasks,
object: nil,
queue: nil) { [weak self] notification in
self?.handleIfFail(notification)
}
NotificationCenter.default.addObserver(
forName: .locationPermissionDenied,
object: nil,
queue: nil) { [weak self] notification in
self?.handleIfAuthorizationDenied(notification)
}
}

/// 위의 세 경우에 대한 옵저버 해제.
func unregisterLocationObserver() {
NotificationCenter.default.removeObserver(
self,
name: .didSuccessUpdatingAllLocationTasks,
object: nil
)
NotificationCenter.default.removeObserver(
self,
name: .didFailUpdatingAllLocationTasks,
object: nil
)
NotificationCenter.default.removeObserver(
self,
name: .locationPermissionDenied,
object: nil
)
}
}
2 changes: 2 additions & 0 deletions FineDust/Common/Typealias.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,5 @@ import Foundation

/// 시간대별 흡입량 타입 별칭.
typealias HourIntakePair = [Hour: Int]

typealias DateHourIntakePair = [Date: HourIntakePair]
4 changes: 0 additions & 4 deletions FineDust/Core Data/CoreData+Intake.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,3 @@ extension Intake {
/// 흡입량 Attribute
static let value = "value"
}

// MARK: - CoreDataIntakeManagerType 준수

extension Intake: CoreDataIntakeManagerType { }
8 changes: 2 additions & 6 deletions FineDust/Core Data/CoreData+User.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,6 @@ import Foundation
/// `User` Entity Attribute 상수 정리
extension User {

/// 설치 날짜 Attribute
static let installedDate = "installedDate"
/// 최근 접속 날짜 Attribute
static let lastAccessedDate = "lastAccessedDate"
}

// MARK: - CoreDataUserManagerType 준수

extension User: CoreDataUserManagerType { }
16 changes: 16 additions & 0 deletions FineDust/Core Data/CoreDataIntakeManager.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//
// CoreDataIntakeManager.swift
// FineDust
//
// Created by Presto on 11/02/2019.
// Copyright © 2019 boostcamp3rd. All rights reserved.
//

import Foundation

final class CoreDataIntakeManager: CoreDataIntakeManagerType {

static let shared = CoreDataIntakeManager()

private init() { }
}
21 changes: 10 additions & 11 deletions FineDust/Core Data/CoreDataIntakeManagerType.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,32 +13,31 @@ import Foundation
protocol CoreDataIntakeManagerType: CoreDataManagerType {

/// READ
func fetch(completion: (Intake?, Error?) -> Void)
func request(completion: ([Intake]?, Error?) -> Void)
}

// MARK: - CoreDataIntakeManagerType 프로토콜 초기 구현

extension CoreDataIntakeManagerType {

func fetch(completion: (Intake?, Error?) -> Void) {
let request = NSFetchRequest<NSFetchRequestResult>(entityName: Intake.classNameToString)
func request(completion: ([Intake]?, Error?) -> Void) {
do {
let results = try context.fetch(request) as? [Intake]
completion(results?.first, nil)
let results = try context.fetch(Intake.fetchRequest()) as? [Intake]
completion(results, nil)
} catch {
completion(nil, error)
}
}

/// CREATE
func save(_ dictionary: [String: Any], completion: (Error?) -> Void) {
guard let entity = NSEntityDescription.entity(forEntityName: Intake.classNameToString,
in: context)
else { return }
let newInstance = NSManagedObject(entity: entity, insertInto: context)
dictionary.forEach { newInstance.setValue($0.value, forKey: $0.key) }
do {
try context.save()
let users = try context.fetch(User.fetchRequest()) as? [User]
let lastUser = users?.last
let intake = Intake(context: context)
dictionary.forEach { intake.setValue($0.value, forKey: $0.key) }
lastUser?.addToIntake(intake)
completion(nil)
} catch {
completion(error)
}
Expand Down
65 changes: 55 additions & 10 deletions FineDust/Core Data/CoreDataService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,24 +10,69 @@ import Foundation

/// 코어데이터 서비스 클래스.
final class CoreDataService: CoreDataServiceType {

/// CoreDataService 싱글톤 객체.
static let shared = CoreDataService()

/// `User` Entity가 들어올, CoreDataManagerType을 준수하는 프로퍼티.
let user: CoreDataManagerType
let userManager: CoreDataUserManagerType

/// `Intake` Entity가 들어올, CoreDataManagerType을 준수하는 프로퍼티.
let intake: CoreDataManagerType
let intakeManager: CoreDataIntakeManagerType

private init(userManager: CoreDataUserManagerType = CoreDataUserManager.shared,
intakeManager: CoreDataIntakeManagerType = CoreDataIntakeManager.shared) {
self.userManager = userManager
self.intakeManager = intakeManager
}

func requestLastAccessedDate(completion: @escaping (Date?, Error?) -> Void) {
userManager.request { user, error in
// 최신 접속 날짜가 코어데이터에 저장되어 있으면 그 값을 내려줌
// 그렇지 않으면 최신 접속 날짜를 갱신한 후 그 값을 내려줌
if let lastAccessedDate = user?.lastAccessedDate {
completion(lastAccessedDate, error)
} else {
saveLastAccessedDate { error in
completion(Date(), error)
}
}
}
}

func saveLastAccessedDate(completion: @escaping (Error?) -> Void) {
userManager.save([User.lastAccessedDate: Date()], completion: completion)
}

private init() {
let context = CoreDataManager.shared.context
user = User(context: context)
intake = Intake(context: context)
func requestIntakes(from startDate: Date,
to endDate: Date,
completion: @escaping ([Date: Int?]?, Error?) -> Void) {
intakeManager.request { intakes, error in
if let error = error {
completion(nil, error)
return
}
guard let intakes = intakes else { return }
var result: [Date: Int?] = [:]
let startDate = startDate.start
let endDate = endDate.end
let intakesInDates = intakes.filter { (startDate...endDate).contains($0.date ?? Date()) }
var currentDate = startDate
// 인자에 들어온 날짜를 순회하면서
// 코어데이터에 해당 날짜에 대한 정보가 저장되어 있으면 그 정보를 내려주고
// 그렇지 않으면 nil을 내려주어 해당 부분은 통신으로 처리하게 함
while currentDate <= endDate.end {
let intakeInCurrentDate = intakesInDates.filter { $0.date?.start == currentDate }.first
if let currentIntake = intakeInCurrentDate {
result[currentDate] = Int(currentIntake.value)
}
currentDate = currentDate.after(days: 1).start
}
completion(result, nil)
}
}

func fetchIntakesInWeek(since date: Date, completion: @escaping ([Int]?, Error?) -> Void) {
let array = [1, 2, 3, 4, 5, 6, 7]
completion(array, nil)
func saveIntake(_ value: Int, at date: Date, completion: @escaping (Error?) -> Void) {
intakeManager.save([Intake.date: date, Intake.value: Int16(value)], completion: completion)
}
}
13 changes: 12 additions & 1 deletion FineDust/Core Data/CoreDataServiceType.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,17 @@ import Foundation
/// Core Data Service 프로토콜.
protocol CoreDataServiceType: class {

/// 최근 접속 날짜 가져오기.
func requestLastAccessedDate(completion: @escaping (Date?, Error?) -> Void)

/// 최근 접속 날짜 저장.
func saveLastAccessedDate(completion: @escaping (Error?) -> Void)

/// 일주일 미세먼지 흡입량 가져오기.
func fetchIntakesInWeek(since date: Date, completion: @escaping ([Int]?, Error?) -> Void)
func requestIntakes(from startDate: Date,
to endDate: Date,
completion: @escaping ([Date: Int?]?, Error?) -> Void)

/// 특정 날짜에 대한 미세먼지 흡입량 저장.
func saveIntake(_ value: Int, at date: Date, completion: @escaping (Error?) -> Void)
}
16 changes: 16 additions & 0 deletions FineDust/Core Data/CoreDataUserManager.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//
// CoreDataUserManager.swift
// FineDust
//
// Created by Presto on 11/02/2019.
// Copyright © 2019 boostcamp3rd. All rights reserved.
//

import Foundation

final class CoreDataUserManager: CoreDataUserManagerType {

static let shared = CoreDataUserManager()

private init() { }
}
17 changes: 7 additions & 10 deletions FineDust/Core Data/CoreDataUserManagerType.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,31 +13,28 @@ import Foundation
protocol CoreDataUserManagerType: CoreDataManagerType {

/// READ
func fetch(completion: (User?, Error?) -> Void)
func request(completion: (User?, Error?) -> Void)
}

// MARK: - CoreDataUserManagerType 프로토콜 초기 구현

extension CoreDataUserManagerType {

func fetch(completion: (User?, Error?) -> Void) {
let request = NSFetchRequest<NSFetchRequestResult>(entityName: User.classNameToString)
func request(completion: (User?, Error?) -> Void) {
do {
let results = try context.fetch(request) as? [User]
completion(results?.first, nil)
let results = try context.fetch(User.fetchRequest()) as? [User]
completion(results?.last, nil)
} catch {
completion(nil, error)
}
}

func save(_ dictionary: [String: Any], completion: (Error?) -> Void) {
guard let entity = NSEntityDescription.entity(forEntityName: User.classNameToString,
in: context)
else { return }
let newInstance = NSManagedObject(entity: entity, insertInto: context)
dictionary.forEach { newInstance.setValue($0.value, forKey: $0.key) }
do {
let user = User(context: context)
dictionary.forEach { user.setValue($0.value, forKey: $0.key) }
try context.save()
completion(nil)
} catch {
completion(error)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="14460.32" systemVersion="18C54" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="14460.32" systemVersion="18D109" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
<entity name="Intake" representedClassName="Intake" syncable="YES" codeGenerationType="class">
<attribute name="date" optional="YES" attributeType="Date" usesScalarValueType="NO" syncable="YES"/>
<attribute name="value" optional="YES" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="YES" syncable="YES"/>
<relationship name="intake" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="User" inverseName="intake" inverseEntity="User" syncable="YES"/>
</entity>
<entity name="User" representedClassName="User" syncable="YES" codeGenerationType="class">
<attribute name="installedDate" optional="YES" attributeType="Date" usesScalarValueType="NO" syncable="YES"/>
<attribute name="lastAccessedDate" optional="YES" attributeType="Date" usesScalarValueType="NO" syncable="YES"/>
<relationship name="intake" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="Intake" inverseName="intake" inverseEntity="Intake" syncable="YES"/>
</entity>
<elements>
<element name="User" positionX="-238.1171875" positionY="-28.01171875" width="128" height="73"/>
<element name="Intake" positionX="-18" positionY="27" width="128" height="88"/>
<element name="User" positionX="-238.1171875" positionY="-28.01171875" width="128" height="73"/>
</elements>
</model>
16 changes: 8 additions & 8 deletions FineDust/Dust/DustInfoManagerType.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,19 @@ import Foundation

/// 미세먼지 정보 관련 Dust Manager 프로토콜.
protocol DustInfoManagerType: DustManagerType {
func fetchDustInfo(term dataTerm: DataTerm,
numberOfRows numOfRows: Int,
pageNumber pageNo: Int,
completion: @escaping (DustResponse?, Error?) -> Void)
func request(dataTerm: DataTerm,
numberOfRows numOfRows: Int,
pageNumber pageNo: Int,
completion: @escaping (DustResponse?, Error?) -> Void)
}

// MARK: - DustInfoManagerType 프로토콜 초기 구현

extension DustInfoManagerType {
func fetchDustInfo(term dataTerm: DataTerm,
numberOfRows numOfRows: Int,
pageNumber pageNo: Int,
completion: @escaping (DustResponse?, Error?) -> Void) {
func request(dataTerm: DataTerm,
numberOfRows numOfRows: Int,
pageNumber pageNo: Int,
completion: @escaping (DustResponse?, Error?) -> Void) {
let observatory = SharedInfo.shared.observatory.percentEncoded
let urlString = baseURL
.appending("/ArpltnInforInqireSvc/getMsrstnAcctoRltmMesureDnsty")
Expand Down
Loading

0 comments on commit 4f89482

Please sign in to comment.