🧐 문제 상황
경로가 그려지지 않는 상황
watchOS에서 경로가 그려지지 않는 문제가 발생했다. ☠️ Outline 앱에서 가장 중요한 경로가 그려지지 않는다는 것은 큰 문제였다...
사실 문제는 간단하게 해결이 가능했다. 바로 iOS, watchOS에서 공통으로 쓰는 LocationManager의 startUpdate()라는 메서드를 watchOS에서 호출하지 않아서 생긴 문제였다.
분명 이전에는 잘 작동했는데... iOS앱에서 변경사항이 생기자 그것이 watchOS앱까지 영향이 가버린 Side Effect 즉, 부작용이라고 생각되었다.
리팩토링의 필요성 ♻️
이전에는 공통으로 쓰이는 메서드들이 많다보니 시간이 부족하기도 하고, 큰 생각없이 당연하게 Target Membership을 iOS, watchOS 둘다 설정해놓고 편하게 메서드를 사용했었다.
하지만 기능이 추가되고, 코드에 변경사항이 생기면서 변경사항이 예상하지 않게 다른 곳에 영향을 주게 되어 iOS, watchOS의 확실한 분리가 필요하다고 느꼈다.
💡 해결 과정
어떠한 파일들이 같이 설정되는지 찾아보고 화살표로 그려보고 싶었는데 위에 Shared의 두 파일만 그려보고, 너무 거미줄처럼 얽혀있어서 다 그리는건 포기했다. 파일 하나하나를 차근차근 순서대로 분리하기로 했다.
WatchConnectivityManager iOS, watchOS 분리
미러링시 같이 사용하는 모델은 어쩔수 없이 같이 사용하게 되므로 모델 파일은 Shared에 유지했다.
하지만 WatchConnectivityManager 클래스는 아래의 코드처럼 프로퍼티도 같이 관리되고 있었고, 함수도 iOS, watchOS가 섞여있어서 구분이 필요하다는 것을 느꼈다. 또한 미러링에서 사용되는 메서드, 러닝 정보를 보내는 메서드의 구분처럼 역할 분리가 필요하다고 느껴 분리했다.
final class WatchConnectivityManager: NSObject, WCSessionDelegate, ObservableObject {
@Published var allCourses: [GPSArtCourse] = [] // iOS에서 쓰지 않는 프로퍼티
@Published var receivedCourse: GPSArtCourse = GPSArtCourse() // iOS에서 쓰지 않는 프로퍼티
@Published var runningState: RunningState?
@Published var runningInfo: MirroringRunningInfo = MirroringRunningInfo()
@Published var runningData: MirroringRunningData = MirroringRunningData()
@Published var isMirroring = false
static let shared = WatchConnectivityManager()
private let userDataModel = UserDataModel() // watchOS에서 쓰지 않는 인스턴스
let session = WCSession.default
override init() { }
func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {
if let error = error { }
#if os(iOS) // iOS에서만 사용하는 메서드
func sessionDidBecomeInactive(_ session: WCSession) { }
func sessionDidDeactivate(_ session: WCSession) { }
#endif
/// 보내는 부분에서 mirroring에 쓰이는 메서드와 데이터 전송에 쓰이는 메서드 구분 필요
func sendGPSArtCoursesToWatch(_ courses: [GPSArtCourse]) { }
func sendRunningRecordToPhone(_ record: RunningRecord) { }
func sendRunningState(_ runningState: RunningState) { }
func sendIsMirroring(_ isMirroring: Bool) { }
func sendRunningInfo(_ runningInfo: MirroringRunningInfo) { }
func sendRunningData(_ runningData: MirroringRunningData) { }
func session(_ session: WCSession, didReceiveUserInfo userInfo: [String: Any]) {
DispatchQueue.main.async {
// watchOS
if let data = userInfo["gpsArtCourses"] as? Data { }
if let data = userInfo["gpsArtCourse"] as? Data { }
// iOS
if let data = userInfo["newRunningRecord"] as? Data { }
// Mirroring
if let data = userInfo["runningState"] as? Data { }
if let data = userInfo["isMirroring"] as? Bool { }
if let data = userInfo["runningInfo"] as? Data { }
if let data = userInfo["runningData"] as? Data { }
}
}
}
불필요한 클래스 삭제
ConvertCoordinateManager의 경우 기존에 Array Extension과 역할이 중복되어 삭제해주었다.
🧐 이렇게 이전코드가 계속 재사용 되는 경우가 많기 때문에 새로운 익스텐션이 적용된다면 모두 바꿔주는게 중요할텐데, 사실 같이 작업하고 있다면 이렇게 수정하는 작업에서 충돌이 많이 발생할 것 같기 때문에 어떠한 식으로 이런것들을 진행해야 할지에 대한 고민을 하게 되었다. (진짜 어떻게 하면 좋을까...?)
final class ConvertCoordinateManager {
static func convertToCLLocationCoordinates(_ coordinates: [Coordinate]) -> [CLLocationCoordinate2D] { }
static func convertToCLLocationCoordinate(_ coordinate: Coordinate) -> CLLocationCoordinate2D { }
static func convertToCoordinates(_ CLLocationCoordinates: [CLLocationCoordinate2D]) -> [Coordinate] { }
static func convertToCoordinate(_ CLLocationCoordinate: CLLocationCoordinate2D) -> Coordinate { }
}
Extension 분리
같이 사용하고 있는 Extension이 많았다. Double, Array, Coordinate 등등... 이것들은 굳이 같이 관리해줘야 하는 것이 아니기 때문에 구분했다. 또한 쓰지않는 Extension도 정리해 주었다.
😇 결과
우선 1차적으로 리팩토링을 끝냈다. 우선 총 15개의 파일이 공유되고 있었는데, 꼭 필요한 5개의 파일을 남겨놓고 10개를 정리할 수 있었다!
또한 프로젝트 곳곳에 펼쳐져 있던 파일들을 아래과 같이 정리했다.
🎯 추후 목표
아직도 개선사항이 많이 보인다. Manager의 역할 분리도 필요해보이고, Path를 추출하는 기능의 보완도 필요해보인다. 계속 이렇게 유지보수를 해나가면 점점 깔끔하고 완벽한 앱이 되지 않을까...! 생각해본다.
'→ Outline' 카테고리의 다른 글
[Project-Outline] 뷰 구조 개선 (0) | 2024.08.18 |
---|---|
[Project-Outline] Smooth Algorithm 개선 (0) | 2024.08.04 |
[Project-Outline] MapSnapshot 적용 (0) | 2024.08.04 |