-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathLocationRepository.swift
More file actions
97 lines (82 loc) · 3.42 KB
/
LocationRepository.swift
File metadata and controls
97 lines (82 loc) · 3.42 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
//
// LocationRepository.swift
// DataSource
//
// Created by 이동현 on 11/9/25.
//
import CoreLocation
import Domain
final class LocationRepository: NSObject, LocationRepositoryProtocol {
private let networkService = NetworkService.shared
private let locationManager = CLLocationManager()
private var continuation: CheckedContinuation<LocationEntity?, Never>?
private var authContinuation: CheckedContinuation<CLAuthorizationStatus, Never>?
override init() {
super.init()
locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
locationManager.delegate = self
}
func fetchCoordinate() async -> LocationEntity? {
guard CLLocationManager.locationServicesEnabled() else { return nil }
let currentStatus = await requestAuthorizationIfNeeded()
if currentStatus == .authorizedAlways || currentStatus == .authorizedWhenInUse {
return await withCheckedContinuation { continuation in
self.continuation = continuation
locationManager.requestLocation()
}
} else {
return nil
}
}
func fetchAddress(coordinate: LocationEntity) async throws -> LocationEntity? {
guard
let longitude = coordinate.longitude,
let latitude = coordinate.latitude
else { return nil }
let endpoint = LocationEndpoint.fetchAddress(longitude: longitude, latitude: latitude)
do {
guard let response = try await networkService.request(endpoint: endpoint, type: KakaoLocationResponseDTO.self)
else { return nil }
let location = response.toLocationEntity(fallbackLongitude: coordinate.longitude, fallbackLatitude: coordinate.latitude)
return location
} catch let error as NetworkError {
switch error {
case .needRetry, .invalidURL, .emptyData:
throw DomainError.requireRetry
default:
throw DomainError.business(error.description)
}
} catch {
throw DomainError.unknown
}
}
private func requestAuthorizationIfNeeded() async -> CLAuthorizationStatus {
let currentStatus = locationManager.authorizationStatus
switch currentStatus {
case .authorizedAlways, .authorizedWhenInUse:
return currentStatus
case .denied, .restricted:
return currentStatus
case .notDetermined:
return await withCheckedContinuation { (continuation: CheckedContinuation<CLAuthorizationStatus, Never>) in
self.authContinuation?.resume(returning: currentStatus)
self.authContinuation = continuation
self.locationManager.requestWhenInUseAuthorization()
}
default:
return currentStatus
}
}
}
extension LocationRepository: CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let coordinate = locations.last?.coordinate
let entity = coordinate.map { LocationEntity(longitude: $0.longitude, latitude: $0.latitude, address: nil) }
continuation?.resume(returning: entity)
continuation = nil
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
continuation?.resume(returning: nil)
continuation = nil
}
}