Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Calculator [STEP 3] Joo, Lust3r #34

Open
wants to merge 29 commits into
base: 1_Lust3r
Choose a base branch
from

Conversation

llimental
Copy link

안녕하세요! 소대(@zdodev)! 이번 Calculator 프로젝트를 진행하게 된 Joo, Lust3r 입니다!
Step 2에서 구현한 틀을 바탕으로 Step 3에서 세부 내용을 구현해 보았습니다.

프로젝트 진행에 있어 문의사항이 있을 때 바로 확인해주시고, 2주간 PR 리뷰 해주셔서 감사합니다!🙌🏻

🧑🏼‍💻 작업 목록

STEP 3 : 스크럼

  • 사용자의 터치 이벤트 수신
  • 숫자 입력 및 계산 기능 구현
  • 계산 내역 표시
  • 내역 길이에 따라 스크롤 기능 구현
  • 계산내역 추가시 스크롤이 하단에 위치하도록 구현
  • 천단위 구분자 표시

💭 학습 키워드

  • IBOutlet
  • IBAction
  • StackView
  • ScrollView
  • NumberFormatter

🤔 고민과 해결

  • 계산 작업이 다양하다보니 예외처리가 많아 어떻게 하면 잘 정리할 수 있을지 고민했습니다.
    고민 끝에 isDecimal,isCalculated 변수를 통해 특정 상황을 통제하고, if/guard문으로 해결할 수 있었습니다.
  • ± 버튼을 어떻게 반영해야 할지에 대한 고민을 했었습니다. 최종적으로 입력된 값의 앞 부호가 음수면 제거하고, 양수라면 음수 기호를 추가하는 방식으로 구현했습니다.
  • 스크롤 뷰 내에 계산한 내용을 추가하는데 어려움이 있어 다양한 자료를 찾아보았습니다. 이후 UIStackViewUILabel을 생성하는 함수(addFormulaStackView)를 만들고, UIStackView 안에 UILabel을 담은 후 기존 계산내역을 담고 있던 StackView에 올리는 방법으로 해결하였습니다.
  • 천단위 구분자 표시를 위해서 numberFormatter 사용을 했으나 23.00 의 경우 23으로 변환을 하기에 해결을 위해서 정수부와 소수부로 나누고 정수부에서만 numberFormatter 적용을 하였습니다.

🙋🏻 질문 거리

  • scrollView에서 stackView 혹은 UILabel의 경우에는 이미 설정되어 있는 제약을 따르지만 UIView를 여러 개 넣었을 때에는 제약을 따르지 않고 겹쳐서 보였습니다. subView에 UIView를 넣기 위해서는 무엇을 해야되는 지 궁금합니다.
    subView 내에 UIView가 들어가는 게 일반적이지 않다면 어떤 Object가 들어가는지 궁금합니다.
  • 사용된 코드 중에서 아래와 같은 코드를 사용하였는데, guard문을 사용할 때 조건들은 몇 개가 적당한지 궁금하고 복잡하다 생각되는 부분은 Bool값으로 반환하는 함수를 만드는 게 나은 건지 궁금합니다
    guard isInitialOperand() == false || (number != "0" && number != "00") else {
        return
    }
    만약 함수로 만든다면 isZero(number: String) -> Bool과 같이 만들려고 했습니다
  • 정수부와 소수부를 나누어서 각각 처리를 하였습니다. 하지만 Swift에서는 String을 Index로 길이를 확인하거나 검색하는 과정이 단순하지 않았는데, Array로 변환해서 처리를 하고 String으로 변환하는 게 더 나은가요?
  • 위의 질문에 덧붙여, numberFormatter 적용을 해보니 *. 의 상황에서 0이나 00을 입력하면 뒷부분이 없이 앞의 정수부분만 보여주기에 정수부와 소수부를 나누고 정수부에만 Formatter 적용을 했습니다. 이처럼 각 부분을 나누지 않고 Formatter를 한 번 사용하여 .0과 .00도 표현할 수 있는 방법이 있을까요?

llimental and others added 25 commits January 25, 2023 16:55
- 연산자가 있다면, 0 또는 00 입력이 안되도록 설정
- 사용되지 않을 isNumber, isOperator 삭제
- 입력받은 숫자가 소수인지 확인하는 isDecimal 추가
- 입력된 연산자를 operatorLabel에 출력
- 이전 입력된 값을 calculationFomula에 삽입
- 입력된 operandLabel 초기화
- allClear 동작 시 operatorLabel 초기화
- 첫 연산자 입력받을 시 초기 연산자 삭제
- allClear에서 calculationFormula 초기화해주는 구문 추가
- clearEntry에서 nan의 경우 글자가 지워지는 현상 예외처리
- 정수가 가능한 결과값인 경우 정수로 표현 (13.0 -> 13)
- enteredOperand 입력을 받아서 천단위 구분자를 추가한 문자열 반환
- 정수부분 1000의 자리 구분자 추가
- 소수부분 20자리까지 입력 가능
- clearEntry에서 계산되어진 상태라면 지워지지 않도록 처리
- addNumber에서 숫자 입력 시 isCalculated 초기화
Copy link

@zdodev zdodev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

안녕하세요. @llimental , @ohdair !

Step 3 구현 잘 진행해주셨습니다!
쉽지 않으셨을텐데 기능 명세를 꼼꼼하게 구현해주셨네요!

질문에 대한 의견을 적어보았습니다!

❓scrollView에서 stackView 혹은 UILabel의 경우에는 이미 설정되어 있는 제약을 따르지만 UIView를 여러 개 넣었을 때에는 제약을 따르지 않고 겹쳐서 보였습니다. subView에 UIView를 넣기 위해서는 무엇을 해야되는 지 궁금합니다. subView 내에 UIView가 들어가는 게 일반적이지 않다면 어떤 Object가 들어가는지 궁금합니다.

  • 질문을 제가 이해하기로는 UIKit 의 intrinsicContentSize 키워드를 알아보면 질문의 현상을 파악하실 수 있지 않을까 싶습니다!

❓사용된 코드 중에서 아래와 같은 코드를 사용하였는데, guard문을 사용할 때 조건들은 몇 개가 적당한지 궁금하고 복잡하다 생각되는 부분은 Bool값으로 반환하는 함수를 만드는 게 나은 건지 궁금합니다

  • 개인적으로 guard 문의 조건은 보통 1개만 작성하고 최대한 3개를 넘기지 않으려고 합니다. 그 이상은 가독성이 많이 떨어진다고 생각됩니다!
    number != "0" 와 같은 조건식을 그대로 작성하기 보다는 말씀해주신 것 처럼, 메서드를 만들어서 사용하면(가독성 측면에서) 더욱 좋을 것 같습니다!

❓정수부와 소수부를 나누어서 각각 처리를 하였습니다. 하지만 Swift에서는 String을 Index로 길이를 확인하거나 검색하는 과정이 단순하지 않았는데, Array로 변환해서 처리를 하고 String으로 변환하는 게 더 나은가요?

  • 방법의 차이라고 보여집니다. Swift 의 String 연산이 단순하지는 않지만 여러 String 타입에 여러 extension 을 구현하여 보다 편리하게 사용하는 방법도 좋을 것 같습니다! 지금처럼 String 으로 구현한 방식도 좋습니다!👍

❓위의 질문에 덧붙여, numberFormatter 적용을 해보니 *. 의 상황에서 0이나 00을 입력하면 뒷부분이 없이 앞의 정수부분만 보여주기에 정수부와 소수부를 나누고 정수부에만 Formatter 적용을 했습니다. 이처럼 각 부분을 나누지 않고 Formatter를 한 번 사용하여 .0과 .00도 표현할 수 있는 방법이 있을까요?

  • NumberFormatter 만을 사용하여 소수점 000... 을 표현하기 어렵지 않을까 싶습니다! 지금처럼 정수부와 소수부를 나눠서 표현하신 방법도 좋습니다!👍

몇 가지 코멘트를 달아보았습니다!
확인해보고 다음 프로젝트에도 적용해보면 좋을 것 같습니다~🤗

Comment on lines 10 to 13
var calculationFormula: String = "+"
var isDecimal: Bool = false
var isCalculated: Bool = false
var enteredOperand: String = "0"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

외부에서 접근하지 않는다면 기본 접근 레벨을 private 으로 하는 것은 어떨까요?

guard isInitialOperand() == false, enteredOperand != String(Double.nan), isCalculated == false else {
return
}
if enteredOperand.removeLast() == "." {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

문자열을 그대로 사용하기 보다는 상수로 정의하고 사용하는 것은 어떨까요?

if enteredOperand.isEmpty {
enteredOperand = "0"
}
operandLabel.text = formattingNumber(enteredOperand)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

여러 메서드에서 해당 구문이 반복되고 있습니다. 이를 메서드로 분리해보면 하는 것은 어떨까요?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아래와 같이 메서드로 분리해서 사용했습니다

private func initializeOperand() {
    enteredOperand = zero
    operandLabel.text = zero
}

guard isInitialOperand() == false || (number != "0" && number != "00") else {
return
}
if isInitialOperand() {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

조건식을 나열하지 않고 메서드를 구현해보셨네요!👍

Comment on lines 171 to 178
extension UIStackView {
func removeAllArrangedSubviews() {
arrangedSubviews.forEach {
self.removeArrangedSubview($0)
$0.removeFromSuperview()
}
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

UIStackViewextension 을 추가해보셨네요!👍
다만 extension 을 따로 관리하도록 다른 파일에 작성하는 것은 어떨까요?

@ohdair
Copy link

ohdair commented Feb 2, 2023

guard문 내부의 가독성을 높이기 위해 조건문(number != "0" && number != "00")을 따로 메서드로 분리하여서 확인했습니다.

private func isZero(_ value: String) -> Bool {
    return value == zero || value == "00"
}

@ohdair
Copy link

ohdair commented Feb 2, 2023

말씀해주신 intrinsicContentSize 키워드는 이번 주에 공부를 하도록 하겠습니다. 감사합니다 😊

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants