본문 바로가기

프로젝트

[iOS] 계산기

Storyboard 를 활용한 간단한 계산기입니다.

 


완료 : O , 예정: E , 보류 : H

일차 목표 결과 비고
프로젝트 시작
1 프로토타입 제작 O  
시뮬레이터에서 구현 O
계산기 로직 구현 O
2

이슈 해결 O  
개선 사항 확인 O

3

이슈 해결 O  
개선 사항 해결 O
평가 O
프로젝트 종료

1일 차 ↓

더보기
계산기_001

프로토타입으로 iOS 의 계산기에 픽셀체를 입혀봤습니다.

프로토타입을 토대로 XCode 에서 구현한 모습입니다.

1일 차 정리

  • StackView 를 사용해서 편하게 Layout 조절이 가능합니다.
계산기_002
  • 여러 개의 버튼을 하나의 변수/ 함수로 관리할 수 있습니다. 
@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 적용
     
계산기_003

 

  • 계산기 로직을 구현했습니다.
    • 사칙연산( +, -, x, / ), 백분율계산, 음수/양수 변경, 소수점 입력, 클리어

 

1일차 이슈

  1. 픽셀체를 입히는 과정에서 UIButton 의 Title 이 Plain 일 경우 폰트가 입혀지지 않았습니다.
  2. UIButton 의 currenttitle 을 가져올 때, Title 이 Attributed 할 경우 원하는 문자열이 아닌 Button 이 반환되었습니다.
  3. UIButton 애니메이션을 주기 위해 DispatchQueue 를 사용했는데 적합한지 확인이 필요합니다.
  4. UIButton 애니메이션이 멈추는 현상이 발생합니다.
  5. UILabel 이 문자열의 길이가 길어지면 축약형으로 표시됩니다.
  6. 소수점이 길어지면 지수형태로 바뀝니다.

 

2일 차 ↓

더보기

 

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 로 변경.
     
계산기_004

 

  • 소수점이 길어지면 지수형태로 바뀝니다.
    • 다른 계산기를 여럿 참고한 결과 통상적으로 소수점이 길어지면 지수형태로 바뀌기에 변경하지 않음.

 

2일차 이슈

  • 테스트 도중 ' 01234' 와 같은 입력이 가능함. 계산기 로직 수정 필요.
  • 정수부 실수부 구분점이 여러개 입력이 가능함. 계산기 로직 수정 필요.

 

개선해야 하는 부분

  • 프로젝트 MVC 패턴으로 리팩토링 필요
  • 앱 아이콘 등록 필요
  • 정수부 3자리 마다 구분 기호, 계산기 로직 수정 필요.

 

3일 차 ↓

더보기

 

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 - 사용자와 상호작용으로 모인 데이터를 바탕으로 계산( 계산기 로직 )
계산기_005
  •  MVC 패턴으로 리팩토링한 결과
    • View/ Controller - [ ViewController, Design ]
      • 사용자 인터페이스와 관련된 요소를 관리한다.
      • 모델과 뷰를 연결하여 사용자의 입력과 이벤트에 대한 응답을 처리한다.
    • Model - [ Calculate ]
      • 계산과 관련된 데이터와 로직을 담당한다.

 

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

 

  • 정수부 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 는 테스트 영상입니다.

 

계산기_010

 

2023. 02. 18 ~ 2023. 02. 20 [ 完 ]

'프로젝트' 카테고리의 다른 글

[iOS] 메트로놈  (0) 2023.02.20