Storyboard 를 활용한 간단한 계산기입니다.
완료 : O , 예정: E , 보류 : H
일차 | 목표 | 결과 | 비고 |
프로젝트 시작 | |||
1 | 프로토타입 제작 | O | |
시뮬레이터에서 구현 | O | ||
계산기 로직 구현 | O | ||
2 |
이슈 해결 | O | |
개선 사항 확인 | O | ||
3 |
이슈 해결 | O | |
개선 사항 해결 | O | ||
평가 | O | ||
프로젝트 종료 |
1일 차 ↓
더보기

계산기_001

계산기_002

계산기_003

프로토타입으로 iOS 의 계산기에 픽셀체를 입혀봤습니다.
프로토타입을 토대로 XCode 에서 구현한 모습입니다.
1일 차 정리
- StackView 를 사용해서 편하게 Layout 조절이 가능합니다.

- 여러 개의 버튼을 하나의 변수/ 함수로 관리할 수 있습니다.
@IBOutlet calcBtns: [UIButtons]
@IBAction btnPressed(_ sender: UIButton) { sender.tag ... }
- UIButton/ UILabel 에 Custom Font 를 입힐 수 있습니다.
- 프로젝트에 font.ttf 파일 등록
- font.ttf 의 File Inspactor 에서 Target Membership 적용
- UIButton/ UILabel 의 Attributes Inspactor 에서 Font 적용

- 계산기 로직을 구현했습니다.
- 사칙연산( +, -, x, / ), 백분율계산, 음수/양수 변경, 소수점 입력, 클리어
1일차 이슈
- 픽셀체를 입히는 과정에서 UIButton 의 Title 이 Plain 일 경우 폰트가 입혀지지 않았습니다.
- UIButton 의 currenttitle 을 가져올 때, Title 이 Attributed 할 경우 원하는 문자열이 아닌 Button 이 반환되었습니다.
- UIButton 애니메이션을 주기 위해 DispatchQueue 를 사용했는데 적합한지 확인이 필요합니다.
- UIButton 애니메이션이 멈추는 현상이 발생합니다.
- UILabel 이 문자열의 길이가 길어지면 축약형으로 표시됩니다.
- 소수점이 길어지면 지수형태로 바뀝니다.
2일 차 ↓
더보기

계산기_004
2일 차 정리
이슈해결
- 픽셀체를 입히는 과정에서 UIButton 의 Title 이 Plain 일 경우 커스텀 폰트가 입혀지지 않았습니다.
- UIButton 의 Title 을 Plain 에서 Attributed 로 변경함.
- UIButton 의 currenttitle 을 가져올 때, Title 이 Attributed 할 경우 원하는 문자열이 아닌 Button 이 반환되었습니다.
- 아래 코드를 사용하면 원하는 문자열이 반환된다.
- 상태에 따라 반환되는 Title 이 다르다. 이러한 이유로 sender.tag 를 사용했다.
// Attributed 한 Title 을 가져오는 방법
let attributedTitle = sender.attributedTitle(for: .normal)?.string
// 아래와 같이 sender.tag 사용
if sender.tag <= 9 && sender.tag >= 0{
...
} else if sender.tag == 11 || sender.tag == 12 || sender.tag == 18 {
...
}
- UIButton 애니메이션을 주기 위해 DispatchQueue 를 사용했는데 적합한지 확인이 필요합니다.
- 메인 스레드 이외의 스레드에서 UI 업데이트를 수행할 경우, 화면 갱신과 관련된 문제가 발생할 수 있다. UI 업데이트가 메인 스레드 에서만 수행되도록 보장하기 위해 DispatchQueue.main.async 를 사용하는 것이 중요하다.
- 애니메이션 코드가 복잡하고 실행 시간이 긴 경우, DispatchQueue 를 사용하면 버튼을 반복해서 누를 경우 중복된 애니메이션이 발생할 수 있다. 딜레이를 사용하여 방지할 수 있지만, 코드의 복잡도를 증가시키고 딜레이가 너무 길어지면 UI 의 반응성을 떨어뜨릴 수 있다.
- DispatchQueue 보다는 UIView.animate 와 같은 Core Animation 기반의 API 를 사용하는 것이 좋다. UI 업데이트가 메인 스레드 에서 수행되며, 애니메이션 효과를 보다 안정적이고 효율적으로 처리할 수 있다.
- UIButton 애니메이션이 멈추는 현상이 발생합니다.
- DispatchQueue 대신 UIView.animate 를 사용함.
let tmp: UIColor = sender.backgroundColor!
// DispatchQueue 를 사용한 기존 애니메이션 코드
sender.backgroundColor? = UIColor.clear
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.1) {
sender.backgroundColor? = tmp
}
// UIView.animate 를 사용한 변경된 애니메이션 코드
UIView.animate(withDuration: 0.1, animations: {
sender.backgroundColor = UIColor.clear
}, completion: { _ in
sender.backgroundColor = tmp
})
- UILabel 이 문자열의 길이가 길어지면 축약형으로 표시됩니다.
- UILabel 의 Attributes Inspactor 에서 AutoShrink 를 Fixed Font Size 에서 Minnimum Font Size 로 변경.

- 소수점이 길어지면 지수형태로 바뀝니다.
- 다른 계산기를 여럿 참고한 결과 통상적으로 소수점이 길어지면 지수형태로 바뀌기에 변경하지 않음.
2일차 이슈
- 테스트 도중 ' 01234' 와 같은 입력이 가능함. 계산기 로직 수정 필요.
- 정수부 실수부 구분점이 여러개 입력이 가능함. 계산기 로직 수정 필요.
개선해야 하는 부분
- 프로젝트 MVC 패턴으로 리팩토링 필요
- 앱 아이콘 등록 필요
- 정수부 3자리 마다 구분 기호, 계산기 로직 수정 필요.
3일 차 ↓
더보기

계산기_005

계산기_006

계산기_007

계산기_008

계산기_009


계산기_010
3일 차 정리
이슈해결
- 테스트 도중 ' 01234' 와 같은 입력이 가능함. 계산기 로직 수정 필요.
- 첫 번째 글자가 0이 아니거나 맨 앞 두 글자가 0. 로 시작한다면 입력을 진행시키게 변경함
if txtNumber.first != "0" || txtNumber.prefix(2) == "0." {
txtNumber = txtNumber + String(tag)
currentNumber = Double(txtNumber)!
} else {
txtNumber = String(tag)
}
- 정수부 실수부 구분점이 여러개 입력이 가능함. 계산기 로직 수정 필요.
- 텍스트에 구분점이 이미 포함되어 있다면 입력을 무시하게 변경함
guard !(txtNumber.contains(".")) else { break }
txtNumber = txtNumber + String(".")
개선 사항
- 프로젝트 MVC 패턴으로 리팩토링 필요
- 지금은 아래 그림처럼 나누어져 있다.
- ViewController - 사용자와 상호작용 ( UILabel, UIButton )
- Design - 사용자와 상호작용할 때 디자인의 변경( 애니메이션 등 )
- Calculate - 사용자와 상호작용으로 모인 데이터를 바탕으로 계산( 계산기 로직 )

- MVC 패턴으로 리팩토링한 결과
- View/ Controller - [ ViewController, Design ]
- 사용자 인터페이스와 관련된 요소를 관리한다.
- 모델과 뷰를 연결하여 사용자의 입력과 이벤트에 대한 응답을 처리한다.
- Model - [ Calculate ]
- 계산과 관련된 데이터와 로직을 담당한다.
- View/ Controller - [ ViewController, Design ]

- 앱 아이콘 등록 필요
- 포토샵으로 간단하게 만들어서 앱 아이콘 등록했다.
- 예전엔 [ 계산기_006 ] 그림처럼 하나하나 다 넣어줬어야 하는데 현재는 [ 계산기_007 ] 그림 처럼 1024 * 1024 한 장으로 해결 가능하다.



- 정수부 3자리 마다 구분 기호, 계산기 로직 수정 필요.
- 아래 코드를 사용해서 txtNumber 에 콤마( , ) 기호를 표시한다.
- .numberStyle = .decimal 만 적용하면 실수부가 3자리만 표시되는 현상이 발생한다.
- .maximumFractionDigits = -2 를 해줌으로써 실수부 자리수 제한을 막을 수 있다.
let numFormat = NumberFormatter()
numFormat.numberStyle = .decimal
numFormat.maximumFractionDigits = -2
let result = numFormat.string(from: NSNumber(value: Double(txtNumber) ?? 0))
평가
생각보다 더 오래 걸려서 많이 놀랐다.
사실 1일 차에 로직 구현하고 끝을 봤어야 했는데 이런저런 일정이 많아서 실질적으로 하루에 두 시간 안쪽으로 밖에 작업을 할 수 없다..
재미있는 경험이었고 앞으론 꼭 DispatchQueue 대신 UIView.animate 를 사용해야겠다.
Storyboard 기반의 프로젝트라 조만간 SwiftUI 를 사용해서 다시 만들어봐야겠다.
기획 없이 무작정 계산기를 만들어보자 하며 시작한 프로젝트라 별 다른 기능은 없는 것이 아쉽다.
환율이나 날짜, 단위 등 실생활에서 필요한 기능을 넣으면 좋을 것 같다.
MVC 패턴으로 리팩토링 하는 과정에서 이전의 패턴도 MVC 와 유사하다는 사실을 발견했다.
MVC 패턴이 자칫하면 컨트롤러 부분이 매시브 해질 수 있다고 들었는데 프로젝트 규모가 워낙 작아서 그런 일은 다행히 발생하지 않았다.
다음 프로젝트에서는 MVVM 패턴도 사용해 봐야겠다.
아래 GIF 는 테스트 영상입니다.



2023. 02. 18 ~ 2023. 02. 20 [ 完 ]
'프로젝트' 카테고리의 다른 글
[iOS] 메트로놈 (0) | 2023.02.20 |
---|