CleanArchitectureの分割例

MapViewController

import UIKit
import FirebaseAuth
import FirebaseDatabase
import GoogleMaps
import CoreLocation

class MapViewController: UIViewController, GMSMapViewDelegate, CLLocationManagerDelegate {

var locationManager = CLLocationManager()

let gateRepository = GateRepositoryImpl()
var markers = [GMSMarker]()

@IBOutlet weak var mapView: GMSMapView!

override func loadView() {
super.loadView()
FIRAuth.auth()?.signInAnonymously() { (user, error) in
self.Repository.findAll()
}
}

override func viewDidLoad() {
super.viewDidLoad()
self.initialMapView()

self.Repository.Delegate = self

self.locationManager.delegate = self
self.locationManager.requestAlwaysAuthorization()
self.locationManager.startUpdatingLocation()
}

private func initialMapView() {
let camera = GMSCameraPosition.camera(withLatitude: 0, longitude: 0, zoom: 15)
self.mapView.camera = camera
self.mapView.mapType = kGMSTypeNormal
self.mapView.accessibilityElementsHidden = false
self.mapView.isMyLocationEnabled = true
self.mapView.settings.compassButton = true
self.mapView.settings.myLocationButton = true
self.mapView.settings.scrollGestures = true
self.mapView.settings.zoomGestures = true
self.mapView.settings.rotateGestures = true
self.mapView.delegate = self
}

public func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if let location = locations.last {
let camera = GMSCameraPosition.camera(withLatitude: location.coordinate.latitude,
longitude: location.coordinate.latitude,
zoom: 6)

self.mapView.camera = camera
self.locationManager.stopUpdatingLocation()
}
}

// MARK: GMSMapViewDelegate
func mapView(_ mapView: GMSMapView, didTap marker: GMSMarker) -> Bool {
//let viewModel = ViewModel()
//gateViewModel.tapMarker(marker: marker)

if let viewModel = marker.userData as? viewModel {
viewModel.toggleStatus()
marker.icon = UIImage(named: gateViewModel.imageName )
self.gateRepository.update(gateEntity: gateViewModel.entity)
}
return true
}

func mapView(_ mapView: GMSMapView, didEndDragging marker: GMSMarker) {
if let gateViewModel = marker.userData as? GateViewModel {
gateViewModel.lat = marker.position.latitude
gateViewModel.lng = marker.position.longitude
self.gateRepository.update(gateEntity: gateViewModel.entity)
}
}
}

extension MapViewController: GateDelegate {

func foundAll(gates: [GateEntity]) {
for gate in gates {
self.gateRepository.listenUpdate(gateEntity: gate)
let gateViewModel = GateViewModel.generate(gateEntity: gate)
let marker = gateViewModel.createMarker()
marker.map = self.mapView
marker.userData = gateViewModel
gateViewModel.attachMarker(marker: marker)
self.markers.append(marker)
}
}

func updated(gate: GateEntity) {
for marker in self.markers {
guard let gateViewModel = marker.userData as? GateViewModel else {
return
}
if gateViewModel.uniqueKey == gate.uniqueKey {
if gateViewModel.update(gateEntity: gate) == true {
gateViewModel.updateMarker()
}

}
}
}

}

Model

import Foundation
import FirebaseDatabase
import GoogleMaps
import SwiftyJSON

class GateViewModel {

var uniqueKey: String!
var name: String!
var lat: Double!
var lng: Double!
var inOutType: GateInOutType!
var status: GateStatus!

var marker: GMSMarker? = nil

static func generate(gateEntity: GateEntity) -> GateViewModel {
return GateViewModel(
uniqueKey: gateEntity.uniqueKey,
name: gateEntity.name,
lat: gateEntity.lat,
lng: gateEntity.lng,
inOutType: gateEntity.inOutType,
status: gateEntity.status
)
}

public init(uniqueKey: String, name: String, lat: Double, lng: Double, inOutType: GateInOutType, status: GateStatus) {
self.uniqueKey = uniqueKey
self.name = name
self.lat = lat
self.lng = lng
self.inOutType = inOutType
self.status = status
}

var imageName: String {
return (self.inOutType).rawValue + "_" + (self.status).rawValue
}

var entity: GateEntity {
return GateEntity(
uniqueKey: self.uniqueKey,
name: self.name,
lat: self.lat,
lng: self.lng,
inOutType: self.inOutType,
status: self.status)
}

func update(gateEntity: GateEntity) -> Bool {
if self.uniqueKey != gateEntity.uniqueKey {
return false
}

self.uniqueKey = gateEntity.uniqueKey
self.name = gateEntity.name
self.lat = gateEntity.lat
self.lng = gateEntity.lng
self.inOutType = gateEntity.inOutType
self.status = gateEntity.status
return true
}

func createMarker() -> GMSMarker {
let position = CLLocationCoordinate2DMake(self.lat, self.lng)
let marker = GMSMarker(position: position)
marker.icon = UIImage(named: self.imageName )
marker.title = self.name
marker.isTappable = true
marker.isDraggable = true
return marker
}

func updateMarker() {
guard let marker = self.marker else {
return
}
marker.position.latitude = self.lat
marker.position.longitude = self.lng
marker.icon = UIImage(named: self.imageName)
marker.title = self.name
}

func toggleStatus() {
if self.status == GateStatus.open {
self.status = GateStatus.close
} else {
self.status = GateStatus.open
}
}

func attachMarker(marker: GMSMarker) {
self.marker = marker
}

}

Entity

import Foundation
import FirebaseDatabase
import SwiftyJSON

private struct Key {
static let name = "gateName"
static let lat = "lat"
static let lng = "lng"
static let inOutType = "inOutType"
static let status = "status"
}

struct GateEntity {

var uniqueKey: String!

var name: String
var lat: Double
var lng: Double
var inOutType: GateInOutType

var status: GateStatus

static func deserialize(snapshot: FIRDataSnapshot) -> GateEntity? {
let json = JSON(snapshot.value!)
guard
let uniqueKey = snapshot.key as String!,
let name = json[Key.name].stringValue as String!,
let lat = json[Key.lat].doubleValue as Double!,
let lng = json[Key.lng].doubleValue as Double!,
let inOutType = GateInOutType(rawValue: json[Key.inOutType].stringValue),
let status = GateStatus(rawValue: json[Key.status].stringValue) else {return nil}

return GateEntity(uniqueKey: uniqueKey, name: name, lat: lat, lng: lng, inOutType: inOutType, status: status)
}

func getDictionary() -> Dictionary<string, any=""> {
return [
Key.name: self.name,
Key.lat: self.lat,
Key.lng: self.lng,
Key.inOutType: self.inOutType.rawValue,
Key.status: self.status.rawValue
]
}</string,>

}

RepositoryImpl

import Foundation
import FirebaseDatabase

class GateRepositoryImpl: GateRepository {

var gateDelegate: GateDelegate?

// GateRepositoryImpl.reference()でreferenceが呼べる
private static func reference() -> FIRDatabaseReference {
return FIRDatabase.database().reference().child("Gates")
}

func update(gateEntity: GateEntity) {
let rootRef = GateRepositoryImpl.reference()
rootRef.child(gateEntity.uniqueKey).updateChildValues(gateEntity.getDictionary())
}

func findAll() {
let rootRef = GateRepositoryImpl.reference()
rootRef.observeSingleEvent(of: .value, with: { (snapshot) in
if let childSnapshots = snapshot.children.allObjects as? [FIRDataSnapshot] {
// delegateがnilであればreturn
guard let delegate = self.gateDelegate else {return}
var gates = [GateEntity]()

for childSnapshot in childSnapshots {

guard let gateEntity = GateEntity.deserialize(snapshot: childSnapshot) else {return}
gates.append(gateEntity)
}
delegate.foundAll(gates: gates)
}
})
}

func listenUpdate(gateEntity: GateEntity) {
let rootRef = GateRepositoryImpl.reference()
rootRef.child(gateEntity.uniqueKey).observe(FIRDataEventType.value, with: {(snapshot) in
guard let delegate = self.gateDelegate else {return}
guard let gate = GateEntity.deserialize(snapshot: snapshot) else {return}
delegate.updated(gate: gate)
})

}

}

Repository

import Foundation

protocol GateRepository: class {
func update(gateEntity: GateEntity)
func findAll()
}

Delegate

import Foundation

protocol GateDelegate {
func updated(gate: GateEntity)
func foundAll(gates: [GateEntity])
}

【スポンサーサイト】





【参考テキスト】

広告

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中