일단 라이징 테스트 전에
가이드라인(?)을 주셔서
그동안 공부했던 거랑 가이드라인 같이 복습해보도록 하겠습니다!
struct Constant{
static let BASE_URL = "URL 주소 입력하기"
static let KOBIS_BASE_URL = "http://www.kobis.or.kr/kobisopenapi////"
}
폰트 적용 방법
extension UIFont {
public enum NotoSansType: String {
case bold = "Bold"
case medium = "Medium"
case regular = "Regular"
}
static func NotoSans(_ type: NotoSansType, size: CGFloat) -> UIFont {
return UIFont(name: "NotoSansCJKkr-\(type.rawValue)", size: size)!
}
}
Navigation Bar
Navigation touchBar
self.navigationController?.navigationBar.titleTextAttributes = [ .font : UIFont.NotoSans(.medium, size: 16), ]
self.view.backgroundColor = .white
디바이스 크기 여백 등의 정보를 담은 Struct
아래와 같은 방식으로 width, height, 노치 디자인, 상태바, 네비게이션 바, 탭 바, 디바이스 위쪽 아래쪽 여백 코드로 조절!
// MARK: 디바이스의 위쪽 여백 (Safe Area 위쪽 여백)
// ** 위쪽 여백의 전체 높이 : topInset + statusBarHeight + navigationBarHeight(존재하는 경우) **
static var topInset: CGFloat {
return UIApplication.shared.windows.first?.safeAreaInsets.top ?? 0
}
[참고 사이트]
https://kapeli.com/cheat_sheets/iOS_Design.docset/Contents/Resources/Documents/index
extension Date {
init(year: Int, month: Int, day: Int) {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy:MM:dd"
self = dateFormatter.date(from: "\(year):\(month):\(day)") ?? Date()
}
멘토님이 강조하셨던 것!
// MARK: comma
//숫자 표현하는 법
// ex. "1234567890".insertComma == "1,234,567,890"
var insertComma: String {
let numberFormatter = NumberFormatter()
numberFormatter.numberStyle = .decimal
if let _ = self.range(of: ".") {
let numberArray = self.components(separatedBy: ".")
if numberArray.count == 1 {
var numberString = numberArray[0]
if numberString.isEmpty {
numberString = "0"
}
guard let doubleValue = Double(numberString)
else { return self }
return numberFormatter.string(from: NSNumber(value: doubleValue)) ?? self
} else if numberArray.count == 2 {
var numberString = numberArray[0]
if numberString.isEmpty {
numberString = "0"
}
guard let doubleValue = Double(numberString)
else {
return self
}
return (numberFormatter.string(from: NSNumber(value: doubleValue)) ?? numberString) + ".\(numberArray[1])"
}
}
else {
guard let doubleValue = Double(self)
else {
return self
}
return numberFormatter.string(from: NSNumber(value: doubleValue)) ?? self
}
return self
}
Color, Button
extension UIColor {
// MARK: hex code를 이용하여 정의
// ex. UIColor(hex: 0xF5663F)
convenience init(hex: UInt, alpha: CGFloat = 1.0) {
self.init(
red: CGFloat((hex & 0xFF0000) >> 16) / 255.0,
)
}
extension UIButton {
func showIndicator() {
let indicator = UIActivityIndicatorView()
let buttonHeight = self.bounds.size.height
let buttonWidth = self.bounds.size.width
indicator.center = CGPoint(x: buttonWidth / 2, y: buttonHeight / 2)
self.addSubview(indicator)
indicator.startAnimating()
}
func dismissIndicator() {
for view in self.subviews {
if let indicator = view as? UIActivityIndicatorView {
indicator.stopAnimating()
indicator.removeFromSuperview()
}
}
}
화면 전환, 경고창/팝업 띄우기,화면 전환 닫기, NavigationBar
화면 전환
// MARK: RootViewController로 이동
@IBAction func changeRootViewControllerButtonTouchUpInside(_ sender: UIButton) {
self.navigationController?.popToRootViewController(animated: true)
}
// MARK: 새로운 window로 화면전환
@IBAction func changeWindowButtonTouchUpInside(_ sender: UIButton) {
let splashStoryboard = UIStoryboard(name: "SplashStoryboard", bundle: nil)
let splashViewController = splashStoryboard.instantiateViewController(identifier: "SplashViewController")
self.changeRootViewController(splashViewController)
}
화면 닫기
// MARK: RootViewController로 이동
@IBAction func changeRootViewControllerButtonTouchUpInside(_ sender: UIButton) {
self.navigationController?.popToRootViewController(animated: true)
}
// MARK: 새로운 window로 화면전환
@IBAction func changeWindowButtonTouchUpInside(_ sender: UIButton) {
let splashStoryboard = UIStoryboard(name: "SplashStoryboard", bundle: nil)
let splashViewController = splashStoryboard.instantiateViewController(identifier: "SplashViewController")
self.changeRootViewController(splashViewController)
}
경고창, 팝업 띄우기
// MARK: 제목만 있는 경고창
@IBAction func alertWithTitleButtonTouchUpInside(_ sender: UIButton) {
self.presentAlert(title: "제목만 있는 경고창")
//나머지도 이런 식으로 작성하면 됩니다!
로그인 데이터 따로 관리
class SignInDataManager {
func postSignIn(_ parameters: SignInRequest, delegate: SignInViewController) {
AF.request("\(Constant.BASE_URL)/signin", method: .post, parameters: parameters, encoder: JSONParameterEncoder(), headers: nil)
.validate()
.responseDecodable(of: SignInResponse.self) { response in
switch response.result {
case .success(let response):
// 성공했을 때
if response.isSuccess, let result = response.result {
delegate.didSuccessSignIn(result)
}
// 실패했을 때
else {
switch response.code {
case 2000: delegate.failedToRequest(message: "상황에 맞는")
case 3000: delegate.failedToRequest(message: "에러 메시지로")
case 4000: delegate.failedToRequest(message: "사용자에게 적절한")
default: delegate.failedToRequest(message: "피드백을 주세요")
}
}
case .failure(let error):
print(error.localizedDescription)
delegate.failedToRequest(message: "서버와의 연결이 원활하지 않습니다")
}
}
}
}
엔티티 타입 적는 법
struct SignInRequest: Encodable {
var id: String
var password: String
}
API 데이터 관리
class BoxOfficeDataManager {
func searchDailyBoxOfficeList(targetDt: String, delegate: BoxOfficeViewController) {
let url = "\(Constant.KOBIS_BASE_URL)/boxoffice/searchDailyBoxOfficeList.json"
+ "?key=\(KobisKey.DAILY_BOXOFFICE_KEY)"
+ "&targetDt=\(targetDt)"
AF.request(url, method: .get, parameters: nil, encoding: JSONEncoding.default, headers: nil)
.validate()
.responseDecodable(of: BoxOfficeResponse.self) { response in
switch response.result {
case .success(let response):
delegate.didRetrieveBoxOffice(result: response.boxOfficeResult)
case .failure(let error):
print(error.localizedDescription)
delegate.failedToRequest(message: "서버와의 연결이 원활하지 않습니다")
}
}
}
}
가이드라인으로 주신 부분들 복습했고,
이외에도 내가 개발하면서 터득했던 라이브러리 사용법, 각종 오류 해결법 등도 참고해서 라이징테스트 할 때 꼭 도움이 되었으면 좋겠다!!
(1) 2주차 과제 오류 모음
https://velog.io/@yoogail/내가자주-겪는-오류-this-class-is-not-key-value-coding-compliant-for-the-key
https://seungchan.tistory.com/entry/Swift-Storyboard-doesnt-contain-a-view-controller-with-identifier
https://youjean.tistory.com/3
(2) 3주차 과제 오류 모음
Multiple commands produce Error 해결법
[iOS / Error] Unable to load contents of file list... 에러 해결
[Swift] Storyboard doesn't contain a view controller with identifier
Invalid nib registered for identifier
xcode invalid redeclaration of type name - Google Search
[iOS - Error] setValue:forUndefinedKey 에러
Swift - "[ setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key ~ ."
[iOS - swift] storyboard 에러- 1. NSUnknownKeyException, this class is not key value coding-compliant for the key // 2. Unexpectedly found nil while implicitly unwrapping an Optional value
Swift - "[ setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key ~ ."
IOS) TableView의 Section을 다뤄보자
(3) 4주차 과제 오류
Could not insert new outlet connection 해결법
[Swift 5] ViewController has no initializers
Label hide very slow
(내가)자주 겪는 오류들: #this class is not key value coding-compliant for the key
Programming Log: [iOS] "loaded the ~ nib but the view outlet was not set." 문제
iOS 레이아웃이 깨졌을때 할 수 있는 방법?!
[Swift] UIButton의 title을 확인하는 방법(강제 추출, 옵셔널 바인딩)
(4) 5주차 과제 오류
로그인 구현 오류
Swift 카카오 연동 로그인
Expected declaration
swift Thread 1 signal Sigabrt 에러 해결 방법
[iOS / Error] Unable to load contents of file list... 에러 해결
네이버 지도 오류
Main thread warning with CLLocationManager.locationServicesEnabled()
NMapsMap 네이버 맵 링크 에러
기타 오류
Xcode Buildtime Error: 'Unable to load contents of file list: '.../Info.plist' (in target 'xxxx')
'Method' is ambiguous for type lookup in this context, Error in Alamofire
[swift] unrecognized selector sent to instance 오류
iOS 시작 가이드
Main thread warning with CLLocationManager.locationServicesEnabled()
5주내내 과제 구현하면서 완전 저 표정으로 지냈던 것 같다...
완전 ???????????????????????? 그 잡채...
그래도 5주동안 오류 해결하는 능력도 길러지고
과제 완성도도 눈에 띄게 좋아지면서(잘난척이 아니라 정말 사실이다...오토레이아웃도 못 했었는데....)
iOS에 더 흥미를 붙였던 것 같다.
라이징테스트 볼 수 있다고 들었을 때 속으로 얼마나 기뻤는 지 모른다.
라이징캠프 1차 목표가 라이징테스트 보기였기 때문에...
과제를 열심히 한 보람이 있었따...😭
종강하고 나서 바로 시작하기도 했고, 매일 방학이 방학이 아닌 것처럼
살다보니 번아웃이 밥 먹듯이 찾아왔었는데
어찌저찌 잘 이겨내고 여기까지 와서 뿌듯하다.
이왕 여기까지 온 거 완주가 최종 목표니까
라이징캠프 처음 시작했을 때 마음가짐 잊지 말고,
끝까지 최선을 다해서 잘 해내고 싶다...!
경험이 주는 힘을 얻어가는 이번 방학이 되고 싶다