날씨 클론코딩 스터디인 '무더'.. 브랜딩을 한게 엊그제 같은데, 벌써 4주의 시간이 지났다.
일단 우리의 계획은 다음과 같았다.
4주간 애플 기본날씨앱 클론 코딩을 하면서 새로 알게된점이 무엇이 있는지 적어보려고 한다
설명을 적을건 아니고 간단하게 한두줄 정도만! 그냥 일기같은 글,, 임다..
CLLocationManager
를 통해 현재 위치의 위도, 경도를 받아왔다. (정말.. 정확하게 나오더라..)
import CoreLocation
var locationManager: CLLocationManager = CLLocationManager()
var latitude: Double? // 위도
var longitude: Double?// 경도
locationManager.delegate = self
locationManager.requestWhenInUseAuthorization()
locationManager.desiredAccuracy = kCLLocationAccuracyBest
if CLLocationManager.locationServicesEnabled() {
locationManager.startUpdatingLocation()
/// 현재 위도와 경도 가져오기
let location = locationManager.location?.coordinate
/// 가져온 현재 위도와 경도 저장
latitude = location?.latitude!
longitude = location?.longitude!
// ...
}
info.plist에서 앱 사용중 위치 가져오기 관련 내용도 추가해줍니다.
근데 시뮬에서는 지역 받아오기가 안된다,, 현재 지역 받으려면 무조건 실기기에서 해야함! 시뮬에서 하니까 무슨 샌프란시스코 나오더라,,
현재 위도, 경도를 가져오면 그 정보를 가지고 주소로 변환해서 화면에 보여줘야 했기에, CLGeocoder
를 이용해 주소로 변환해 주었다. 여러 속성들이 있는데 .locality
로 해주면 전체 주소가 아니라 지역 이름만 나오게 할 수 있다.! (ex. 용산구 청파동 -> '용산구'만 나오도록)
날씨 클론코딩 전까지 주변에서 Moya에 대한 이야기를 굉장히 많이 들었기에,, 이번에 처음으로 Moya 라이브러리를 사용하여 서버통신을 해보았다. Moya는 Alamofire를 사용하기 좋게 한번 더 감싼 라이브러리인것 같은데 확실히 눈에 잘 보이는 방식으로 필요한 모든 것을 설정할 수 있어서 편했던 것 같다. 앞으로 자주 애용할 것 같다. (하지만 다음번엔 URLSession을 이용한 서버통신에 도전해보기로,,)
검색뷰에서 지역들을 가져오기 위해 Swift에 기본으로 들어있는 mapkit을 사용해보았다.
guard let placeMark = response?.mapItems[0].placemark else {
return
}
print("가져온 주소", placeMark.coordinate)
print("나라이름", placeMark.countryCode!)
print("지역이름", placeMark.locality ?? "없어요..없어..")
print("위도", placeMark.coordinate.latitude)
print("경도", placeMark.coordinate.longitude)
요렇게 다양한 정보들을 가져올 수 있다!
로티를 사용해본건 iOS 세미나때 뿐이었는데, 직접 로티 파일을 다운받고 프로젝트에 적용해본건 처음이었다. 확실히 그냥 배경만 있는 것보다 귀여운..로티가 들어가니까 훨씬 맘에 들었다.
새롭게 검색해서 알게된 로티무한재생 방법은 아래와 같다.
animationView.loopMode = .loop
나는 테이블뷰의 section을 이용해서 Sticky Header를 구현했는데, 테이블뷰 전체가 투명한 애플 날씨앱의 (킹받는..) 특징 때문에 문제가 생겼다. 바로 tableview를 스크롤해서 위로 올리면 Section 뒤에 row가 올라가면서 내용이 다 비쳐보였다는 것..!
이 문제를 아무리 찾아도 해결할 수 없어서 상단은 UIView + 하단은 TableView 조합도 써봤지만, 애플 날씨앱은 화면 어느 위치에서나 스크롤이 되는 앱이었기 때문에.. 이렇게 할 수가 없었다. (UIView + UITableview를 쓰면 UIView부분은 스크롤이 안되기 때문..)
그래서 일단 넘기고 다른거부터 구현하자! 했는데 예지윤언니가 해답을 찾아왔다. 바로 Mask를 이용해 섹션 뒷부분으로 올라가는 부분을 안보이게 해주는 것.. ! 아직 Mask에 대한 내용은 모르는 부분이 많아서 다시 공부해서 정리해보려고 한다. 이부분을 구현하면서 스터디의 집단지성과 위대함을.. 다시한번 더 깨달았다
처음으로 Open API 를 사용해서 구현을 해보았다. 우리는 날씨에 대한 정보를 받아와야 했기에 OpenWeatherMap API 의 One Call 을 사용했다.
개인키도 처음 발급받아보고,,
baseURL과 개인키는 유출되지 않도록 gitignore에 올린 파일(GeneralAPI.swift)에 static으로 선언한 후, 필요할때마다 GeneralAPI.baseURL
혹은 GerneralAPI.appid
로 불러와서 사용했다.
https://openweathermap.org/api
평소 앱에서 page controller를 많이 봤던 것 같은데, 직접 사용해본건 이번이 처음이다! 나는 처음엔 커스텀 탭바 했던 것처럼 직접해줘야되는 건줄 알았는데 기본적으로 제공하는 것이었더라..
암튼 pageController의 사용법은 그리 어렵지 않았다!
@IBAction func pageChanged(_ sender: Any) {
UIView.animate(withDuration: 0.3){
self.scrollview.contentOffset.x = UIScreen.main.bounds.width * CGFloat(self.pagecontrol.currentPage)
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
pagecontrol.currentPage = Int(floor(scrollview.contentOffset.x / UIScreen.main.bounds.width))
}
pagecontrol.setIndicatorImage(UIImage(systemName: "location.fill"), forPage: 0)
나라마다 시간이 다르기에 timeZone을 이용하여 각각 다른 시간을 설정해주었다. (timeZone은 API에서 가져왔다.)
아래와 같은 String Extension을 만들어 사용해주었다.
/// 현재시간
extension String {
func nowTime(_ format: String, _ timezone: Int) -> String {
let date = Date()
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = format
dateFormatter.locale = Locale(identifier: "ko_KR")
dateFormatter.timeZone = TimeZone(secondsFromGMT: timezone)
return dateFormatter.string(from: date as Date)
}
}
힘들었지만 돌아보니 새로 해본것도 많고 뿌듯하다~!
하다보니 비동기 처리, RxSwift, MVVM 필요성을 좀 많이 느껴서
이제 슬슬 이 내용에 대해 공부해보려고 한다. 빠이팅.!
일단 클론코딩은 10일간 쉬고.. 잠시 재충전의 시간을 가지기로..
다음 클코 기대된다
글고.. 사랑하는 무더위들 덕분에 끝까지 할 수 있었던 것 같아서 넘 감사하고..
스터디의 위대함 (집단지성..중간공유..짜릿해)을 몸소느꼈던 4주였다~~!
수고했다 김셰후 !