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
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
153253c
feat: isOperator 함수 추가
llimental Jan 25, 2023
42383b0
feat: addNumber() 추가
ohdair Jan 25, 2023
8b2d40f
feat: isNumber 추가
llimental Jan 25, 2023
43e351e
refactor: 연산자를 button의 title과 동일하게 변경
ohdair Jan 26, 2023
35e810d
feat: 입력받은 숫자로 operandLabel에 반영
llimental Jan 26, 2023
32cafa3
feat: 소수점을 추가해주는 addDecimalPoint 구현
ohdair Jan 26, 2023
2e7e8a4
feat: operandLabel의 마지막 자리 삭제하는 clearEntry 추가
llimental Jan 26, 2023
a71dd15
feat: 계산기를 초기화하는 allClear 추가
ohdair Jan 26, 2023
36bde4c
feat: 입력된 숫자의 부호를 바꿔주는 changeSign 추가
llimental Jan 26, 2023
90611aa
feat: 연산자를 더해주는 addOperator 구현
ohdair Jan 26, 2023
ca7c043
refactor: 예외사항에 따른 코드 수정
llimental Jan 26, 2023
026be83
feat: calculateResult 추가
llimental Jan 26, 2023
98b992a
feat: 입력 내용을 보여주는 addFormulaStackView 추가
llimental Jan 26, 2023
d512e51
feat: allClear할 떄 scrollView의 subViews 삭제 기능 추가
ohdair Jan 26, 2023
e1f8c7e
feat: scrollView 하단 고정 시키는 기능 추가
ohdair Jan 26, 2023
5ce428d
refactor: enteredOperand 변수 추가
llimental Jan 27, 2023
87d918e
fix: calculateResult가 stack에 반영되는 문제 해결
llimental Jan 27, 2023
fccdbbd
feat: 천단위 구분 표시하는 formattingNumber 추가
ohdair Jan 27, 2023
38e437b
feat: convertOperand 추가
llimental Jan 27, 2023
faf9cbf
feat: isCalculated 추가
ohdair Jan 27, 2023
f0ddc89
refactor: formattingNumber 반환값을 String? 에서 String 반환하도록 변경
ohdair Jan 27, 2023
f7bfe21
refactor: enteredOperand가 초기값인지 확인하는 isInitialOperand 추가
llimental Jan 27, 2023
ae1c748
refactor: 불필요한 프로퍼티 생성
ohdair Jan 27, 2023
0575851
refactor: addNumber를 addOperand로 네이밍 변경
llimental Jan 27, 2023
20c0e0c
Update README.md
llimental Jan 27, 2023
a71f398
refactor: 속성 은닉화
ohdair Feb 2, 2023
3da6cdf
refactor: 자주 사용하는 "."을 상수로 정의
ohdair Feb 2, 2023
c5e735e
refactor: guard문의 가독성을 위해 isZero 함수로 분리
ohdair Feb 2, 2023
173c537
refactor: 반복되는 구문을 메서드로 분리
ohdair Feb 2, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions Calculator/Calculator.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
objects = {

/* Begin PBXBuildFile section */
90A26ED9298BB29000A9C749 /* UIStackView+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90A26ED8298BB29000A9C749 /* UIStackView+Extension.swift */; };
C713D9422570E5EB001C3AFC /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C713D9412570E5EB001C3AFC /* AppDelegate.swift */; };
C713D9442570E5EB001C3AFC /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C713D9432570E5EB001C3AFC /* SceneDelegate.swift */; };
C713D9462570E5EB001C3AFC /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C713D9452570E5EB001C3AFC /* ViewController.swift */; };
Expand Down Expand Up @@ -35,6 +36,7 @@
/* End PBXContainerItemProxy section */

/* Begin PBXFileReference section */
90A26ED8298BB29000A9C749 /* UIStackView+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIStackView+Extension.swift"; sourceTree = "<group>"; };
C713D93E2570E5EB001C3AFC /* Calculator.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Calculator.app; sourceTree = BUILT_PRODUCTS_DIR; };
C713D9412570E5EB001C3AFC /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
C713D9432570E5EB001C3AFC /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -105,6 +107,7 @@
D94FF8362974D9B100F7A551 /* CalculateItemQueue.swift */,
D94FF84A29751BD500F7A551 /* CalculateItem.swift */,
D94BC7B5297670DD00186B6A /* ExpressionParser.swift */,
90A26ED8298BB29000A9C749 /* UIStackView+Extension.swift */,
);
path = Model;
sourceTree = "<group>";
Expand Down Expand Up @@ -184,7 +187,7 @@
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 1420;
LastUpgradeCheck = 1210;
LastUpgradeCheck = 1420;
TargetAttributes = {
C713D93D2570E5EB001C3AFC = {
CreatedOnToolsVersion = 12.1;
Expand Down Expand Up @@ -239,6 +242,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
90A26ED9298BB29000A9C749 /* UIStackView+Extension.swift in Sources */,
C713D9462570E5EB001C3AFC /* ViewController.swift in Sources */,
D94BC7B6297670DD00186B6A /* ExpressionParser.swift in Sources */,
C713D9422570E5EB001C3AFC /* AppDelegate.swift in Sources */,
Expand Down Expand Up @@ -345,7 +349,7 @@
IPHONEOS_DEPLOYMENT_TARGET = 14.1;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = NO;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = "iphonesimulator iphoneos macosx";
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
Expand Down Expand Up @@ -463,6 +467,7 @@
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "-";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 1;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = "";
GENERATE_INFOPLIST_FILE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 16.2;
Expand All @@ -488,6 +493,7 @@
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 1;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = "";
GENERATE_INFOPLIST_FILE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 16.2;
Expand Down
165 changes: 163 additions & 2 deletions Calculator/Calculator/Controller/ViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,173 @@
import UIKit

class ViewController: UIViewController {
private let zero: String = "0"
private let point: String = "."
private var calculationFormula: String = "+"
private var isDecimal: Bool = false
private var isCalculated: Bool = false
private var enteredOperand: String = "0"

override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}

@IBOutlet weak var scrollView: UIScrollView!
@IBOutlet weak var operatorLabel: UILabel!
@IBOutlet weak var operandLabel: UILabel!
@IBOutlet weak var formulaStackViews: UIStackView!

}
@IBAction func allClear(_ sender: UIButton) {
operandLabel.text?.removeAll()
isDecimal = false
operatorLabel.text = ""
calculationFormula = "+"
initializeOperand()
formulaStackViews.removeAllArrangedSubviews()
}

@IBAction func clearEntry(_ sender: UIButton) {
guard isInitialOperand() == false, enteredOperand != String(Double.nan), isCalculated == false else {
return
}
if enteredOperand.removeLast() == Character(point) {
isDecimal = false
}
guard enteredOperand.isEmpty == false else {
initializeOperand()
return
}
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
}

}

@IBAction func changeSign(_ sender: UIButton) {
guard isInitialOperand() == false else {
return
}
if enteredOperand.first == "-" {
enteredOperand.removeFirst()
} else {
enteredOperand = "-" + enteredOperand
}
operandLabel.text = formattingNumber(enteredOperand)
}

@IBAction func addDecimalPoint(_ sender: UIButton) {
guard isDecimal == false, isCalculated == false else {
return
}
enteredOperand += point
isDecimal = true
operandLabel.text = formattingNumber(enteredOperand) + point
}

@IBAction func addOperand(_ sender: UIButton) {
guard let number = sender.currentTitle else {
return
}
if isCalculated {
enteredOperand = zero
isCalculated = false
}
guard isInitialOperand() == false || isZero(number) == false 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.

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

enteredOperand = number
} else {
enteredOperand += number
}
operandLabel.text = convertOperand(enteredOperand)
}

@IBAction func addOperator(_ sender: UIButton) {
guard let `operator` = sender.currentTitle,
let enteredOperator = operatorLabel.text else {
return
}
guard isInitialOperand() == false else {
if calculationFormula == "+" {
calculationFormula.removeAll()
}
operatorLabel.text = `operator`
return
}
if enteredOperand.hasSuffix(point) {
enteredOperand += zero
}
calculationFormula += enteredOperator + enteredOperand
addFormulaStackView(operator: enteredOperator, operand: enteredOperand)
operatorLabel.text = `operator`
initializeOperand()
isDecimal = false
scrollView.contentOffset.y = scrollView.contentSize.height
}

@IBAction func calculateResult(_ sender: UIButton) {
guard let enteredOperator = operatorLabel.text, calculationFormula != "+" else {
return
}
calculationFormula += enteredOperator + enteredOperand
operatorLabel.text = ""
isDecimal = false
isCalculated = true
var formula = ExpressionParser.parse(from: calculationFormula)
addFormulaStackView(operator: enteredOperator, operand: enteredOperand)
enteredOperand = String(formula.result())
operandLabel.text = formattingNumber(enteredOperand)
calculationFormula = "+"
scrollView.contentOffset.y = scrollView.contentSize.height
}

private func addFormulaStackView(`operator`: String, operand: String) {
let formulaStackView = UIStackView()
let enteredOperatorLabel = UILabel()
let enteredOperandLabel = UILabel()

enteredOperandLabel.text = formattingNumber(operand)
enteredOperatorLabel.text = `operator`
enteredOperandLabel.textColor = .white
enteredOperatorLabel.textColor = .white
formulaStackView.axis = .horizontal
formulaStackView.spacing = 8
formulaStackView.addArrangedSubview(enteredOperatorLabel)
formulaStackView.addArrangedSubview(enteredOperandLabel)

formulaStackViews.addArrangedSubview(formulaStackView)
}

private func formattingNumber(_ number: String) -> String {
let formatter = NumberFormatter()
formatter.maximumFractionDigits = 20
formatter.numberStyle = .decimal
return formatter.string(for: Double(number)) ?? number
}

private func convertOperand(_ operand: String) -> String {
if let indexOfPoint = operand.firstIndex(of: Character(point)) {
let integerOfOperand = String(operand[operand.startIndex..<indexOfPoint])
var decimalOfOperand: String
if operand.distance(from: indexOfPoint, to: operand.endIndex) > 20 {
let twentyIndex = operand.index(indexOfPoint, offsetBy: 20)
decimalOfOperand = String(operand[indexOfPoint...twentyIndex])
} else {
decimalOfOperand = String(operand[indexOfPoint..<operand.endIndex])
}
return formattingNumber(integerOfOperand) + decimalOfOperand
}
return formattingNumber(operand)
}

private func isInitialOperand() -> Bool {
return enteredOperand == zero
}

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

private func initializeOperand() {
enteredOperand = zero
operandLabel.text = zero
}
}
6 changes: 3 additions & 3 deletions Calculator/Calculator/Model/CalculateItem.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ protocol CalculateItem {

enum Operator: Character, CalculateItem, CaseIterable {
case add = "+"
case subtract = "-"
case divide = "/"
case multiply = "*"
case subtract = ""
case divide = "÷"
case multiply = "×"

func calculate(lhs: Double, rhs: Double) -> Double {
switch self {
Expand Down
17 changes: 17 additions & 0 deletions Calculator/Calculator/Model/UIStackView+Extension.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
//
// UIStackView+Extension.swift
// Calculator
//
// Created by 박재우 on 2023/02/02.
//

import UIKit

extension UIStackView {
func removeAllArrangedSubviews() {
arrangedSubviews.forEach {
self.removeArrangedSubview($0)
$0.removeFromSuperview()
}
}
}
Loading