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

Week5 Assignment - Fix Calculator & Make NetworkModel #13

Open
wants to merge 17 commits into
base: kyungsoo
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
8 changes: 4 additions & 4 deletions week4/Calculator/Calculator.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
A67D5A3228AB573F00624B25 /* CalculatorManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = A67D5A3128AB573F00624B25 /* CalculatorManager.swift */; };
A67D5A3428AB68B200624B25 /* PadView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A67D5A3328AB68B200624B25 /* PadView.swift */; };
A67D5A3A28ADC86000624B25 /* ScreenView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A67D5A3928ADC86000624B25 /* ScreenView.swift */; };
A67D5A3C28ADCA6C00624B25 /* EachButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = A67D5A3B28ADCA6C00624B25 /* EachButton.swift */; };
A67D5A3C28ADCA6C00624B25 /* PadButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = A67D5A3B28ADCA6C00624B25 /* PadButton.swift */; };
A67D5A3E28ADD28D00624B25 /* ButtonStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = A67D5A3D28ADD28D00624B25 /* ButtonStyle.swift */; };
A67D5A5628B7024800624B25 /* String+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = A67D5A5528B7024800624B25 /* String+Extension.swift */; };
A67D5A5928B74B3200624B25 /* Numeric+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = A67D5A5828B74B3200624B25 /* Numeric+Extension.swift */; };
Expand All @@ -32,7 +32,7 @@
A67D5A3128AB573F00624B25 /* CalculatorManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CalculatorManager.swift; sourceTree = "<group>"; };
A67D5A3328AB68B200624B25 /* PadView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PadView.swift; sourceTree = "<group>"; };
A67D5A3928ADC86000624B25 /* ScreenView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScreenView.swift; sourceTree = "<group>"; };
A67D5A3B28ADCA6C00624B25 /* EachButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EachButton.swift; sourceTree = "<group>"; };
A67D5A3B28ADCA6C00624B25 /* PadButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PadButton.swift; sourceTree = "<group>"; };
A67D5A3D28ADD28D00624B25 /* ButtonStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonStyle.swift; sourceTree = "<group>"; };
A67D5A5528B7024800624B25 /* String+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+Extension.swift"; sourceTree = "<group>"; };
A67D5A5828B74B3200624B25 /* Numeric+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Numeric+Extension.swift"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -103,7 +103,7 @@
A67D5A2028AB566600624B25 /* CalculatorView.swift */,
A67D5A3328AB68B200624B25 /* PadView.swift */,
A67D5A3928ADC86000624B25 /* ScreenView.swift */,
A67D5A3B28ADCA6C00624B25 /* EachButton.swift */,
A67D5A3B28ADCA6C00624B25 /* PadButton.swift */,
);
path = View;
sourceTree = "<group>";
Expand Down Expand Up @@ -206,7 +206,7 @@
files = (
A67D5A5628B7024800624B25 /* String+Extension.swift in Sources */,
A67D5A5928B74B3200624B25 /* Numeric+Extension.swift in Sources */,
A67D5A3C28ADCA6C00624B25 /* EachButton.swift in Sources */,
A67D5A3C28ADCA6C00624B25 /* PadButton.swift in Sources */,
A67D5A3E28ADD28D00624B25 /* ButtonStyle.swift in Sources */,
A67D5A3428AB68B200624B25 /* PadView.swift in Sources */,
A67D5A2128AB566600624B25 /* CalculatorView.swift in Sources */,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ import Foundation

extension Numeric {
var exponentialNotation: String {
return Formatter.exponentialNotation.string(for: self) ?? ""
guard let exponentialNotationString = Formatter.exponentialNotation.string(for: self) else {
return "오류"

Choose a reason for hiding this comment

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

Error 를 정의해서 처리하면 어떨까요?

}
return exponentialNotationString
}
}
22 changes: 9 additions & 13 deletions week4/Calculator/Calculator/Extensions/String+Extension.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,17 @@
import Foundation

extension String {
var insertComma: String {
var decimalFormat: String {
let numberFormatter = NumberFormatter();
numberFormatter.numberStyle = .decimal
if self.contains(".") {
let numberArray = self.components(separatedBy: ".")
let numberString = numberArray.first ?? "0"
guard let doubleValue = Double(numberString) else {
return self
}
return (numberFormatter.string(from: NSNumber(value: doubleValue)) ?? numberString) + ".\(numberArray[numberArray.index(numberArray.startIndex, offsetBy: 1)])"
} else {
guard let doubleValue = Double(self) else {
return self
}
return numberFormatter.string(from: NSNumber(value: doubleValue)) ?? self
let decimalFractionComponents = components(separatedBy: ".")
guard let decimalString = decimalFractionComponents.first,
let decimal = Int(decimalString),
var decimalFormat = numberFormatter.string(from: NSNumber(value: decimal))
else { return "오류"}
if 1 < decimalFractionComponents.count, let fractionString = decimalFractionComponents.last {

Choose a reason for hiding this comment

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

1 < decimalFractionComponents.count
decimalFractionComponents.count > 1
위 두 코드를 우리는 어떻게 읽을까요?

  • 1 보다 값이 큰 경우
  • 값이 1보다 큰 경우

가독성을 고려해볼까요?

Choose a reason for hiding this comment

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

적절한 줄바꿈은 가독성을 증가시킬 수 있습니다

decimalFormat += ".\(fractionString)"
}
return decimalFormat
}
}
177 changes: 121 additions & 56 deletions week4/Calculator/Calculator/Model/Calculator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,14 @@ import Foundation

struct Calculator {

// MARK: Alias(es)

typealias BinaryOperator = CalculatorManager.BinaryOperator
typealias Digit = CalculatorManager.Digit

// MARK: Propery(ies)

private(set) var displayValue = "0"
private(set) var isAllClear = true
private var calculationResult: Decimal? = 0
private var newValue: Decimal? = nil
private var operation: BinaryOperator? = .add
private var `operator`: BinaryOperator? = .add
private var isPreOperatorEqual = false
private var isCalculationResultIsNil: Bool {
calculationResult == nil
}
Expand All @@ -33,44 +29,47 @@ struct Calculator {
self.newValue = Decimal(string: displayValue)
isAllClear = false
} else {
if String(describing: self.newValue ?? 0).count >= 9 {
let maxLengthOfInputDigit = displayValue.contains(".") ? 10 : 9
if displayValue.count >= maxLengthOfInputDigit {
return
}
displayValue = displayValue.appending(String(describing: newValue.rawValue))
self.newValue = Decimal(string: displayValue)
}
}

mutating func setOperation(_ newOperation: BinaryOperator) {
guard let operation = operation, let newValue = newValue else {
self.operation = newOperation
return
mutating func setOperator(_ newOperator: BinaryOperator) {
if isPreOperatorEqual {
`operator` = nil
newValue = nil
isPreOperatorEqual = false
}
calculationResult = calculate(operation, newValue)
guard let calculationResult = calculationResult else {
displayValue = "오류"
return
}
displayValue = String(describing: calculationResult)
proveAndCalculate(newOperator: newOperator)
self.newValue = nil
self.operation = newOperation
self.`operator` = newOperator
}

mutating func equal() {
guard let operation = operation, let newValue = newValue else {
proveAndCalculate(newOperator: nil)
}

private mutating func proveAndCalculate(newOperator: BinaryOperator?) {
let isEqual = newOperator == nil
guard let `operator` = `operator`, let newValue = newValue else {
return
}
calculationResult = calculate(operation, newValue)
if isEqual {
isPreOperatorEqual = true
}
calculationResult = calculate(`operator`, newValue)
guard let calculationResult = calculationResult else {
displayValue = "오류"
self.newValue = nil
return
}
displayValue = String(describing: calculationResult)
self.newValue = nil
self.operation = nil
}

mutating func dot() {
if displayValue.contains(".") || isCalculationResultIsNil {
return
Expand All @@ -81,36 +80,32 @@ struct Calculator {
}

mutating func percent() {
guard let calculationResult = calculationResult else {
return
}
if let newValue = newValue {
displayValue = String(describing: newValue * 0.01)
self.newValue = Decimal(string: displayValue)
} else {
displayValue = String(describing: calculationResult * 0.01)
self.calculationResult = Decimal(string: displayValue)
}
percentOrToggleSignOfDisplayNumber(isToggle: false)
}

mutating func toggleSignOfDisplayNumber() {
percentOrToggleSignOfDisplayNumber(isToggle: true)
}

mutating func toggle() {
private mutating func percentOrToggleSignOfDisplayNumber(isToggle: Bool) {
guard let calculationResult = calculationResult else {
return
}
if let newValue = newValue {
displayValue = String(describing: -newValue)
let operand = isToggle ? -1 : 0.01
if let newValue = newValue, !isPreOperatorEqual {
displayValue = String(describing: newValue * Decimal(operand))
self.newValue = Decimal(string: displayValue)
} else {
displayValue = String(describing: -calculationResult)
displayValue = String(describing: calculationResult * Decimal(operand))
self.calculationResult = Decimal(string: displayValue)
}
}

mutating func allClear() {
displayValue = "0"
newValue = nil
clear()
isPreOperatorEqual = false
calculationResult = 0
operation = .add
`operator` = .add
}

mutating func clear() {
Expand All @@ -120,22 +115,21 @@ struct Calculator {
}

mutating func undoWhenDragged() {
if newValue == nil {
if displayValue.count > 1 {
displayValue.removeLast()
calculationResult = Decimal(string: displayValue)
} else if displayValue.count == 1 {
displayValue = "0"
calculationResult = Decimal(string: displayValue)
}
let isNewValueNil = newValue == nil
if displayValue.count == 1 {
displayValue = "0"
assignValueWhenUndo(isNewValueNil)
} else {
if displayValue.count > 1 {
displayValue.removeLast()
newValue = Decimal(string: displayValue)
} else if displayValue.count == 1 {
displayValue = "0"
newValue = Decimal(string: displayValue)
}
displayValue.removeLast()
assignValueWhenUndo(isNewValueNil)
}
}

private mutating func assignValueWhenUndo(_ newValueIsNil: Bool) {
if newValueIsNil {
calculationResult = Decimal(string: displayValue)
} else {
newValue = Decimal(string: displayValue)
}
}

Expand All @@ -150,11 +144,82 @@ struct Calculator {
return calculationResult - newValue
case .divide:
if newValue == 0 {
return nil
return nil
}
return calculationResult / newValue
case .multiply:
return calculationResult * newValue
}
}
}

extension Calculator {
enum Button: Hashable {
case digit(_ digit: Digit)
case binaryOperator(_ binaryOperator: BinaryOperator)
case equal
case dot
case percent
case toggle
case allClear
case clear

var appearance: String {
switch self {
case .digit(let digit):
return digit.appearance
case .binaryOperator(let binaryOperator):
return binaryOperator.appearance
case .equal:
return "="
case .dot:
return "."
case .percent:
return "%"
case .toggle:
return "+/-"
case .allClear:
return "AC"
case .clear:
return "C"
}
}
}

enum BinaryOperator {
case add
case substarct
case divide
case multiply

var appearance: String {
switch self {
case .add:
return "+"
case .substarct:
return "-"
case .divide:
return "/"
case .multiply:
return "*"
}
}
}

enum Digit: Int {
case zero
case one
case two
case three
case four
case five
case six
case seven
case eight
case nine

var appearance: String {
return String(describing: self.rawValue)
}
}
}
44 changes: 16 additions & 28 deletions week4/Calculator/Calculator/Style/ButtonStyle.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,36 +7,24 @@
import SwiftUI

struct CalculateButtonStyle: ButtonStyle {
let buttonColor: (Color, Color)
let buttonColor: (background: Color, foreground: Color)
let isZero: Bool

func makeBody(configuration: Self.Configuration) -> some View {
if isZero {
configuration.label
.frame(maxWidth:UIScreen.main.bounds.size.width / 2, maxHeight: UIScreen.main.bounds.size.height / 12, alignment: .leading)
.font(.title)
.padding()
.background(buttonColor.0)
.foregroundColor(buttonColor.1)
.overlay {
if configuration.isPressed {
Color(white: 1.0, opacity: 0.3)
}
}
.clipShape(Capsule())
} else {
configuration.label
.frame(maxWidth:UIScreen.main.bounds.size.width / 6.5, maxHeight: UIScreen.main.bounds.size.height / 12, alignment: .center)
.font(.title)
.padding()
.background(buttonColor.0)
.foregroundColor(buttonColor.1)
.overlay {
if configuration.isPressed {
Color(white: 1.0, opacity: 0.3)
}
configuration.label
.frame(
maxWidth:UIScreen.main.bounds.size.width / (isZero ? 2.0 : 6.5),
maxHeight: UIScreen.main.bounds.size.height / 12,
alignment: isZero ? .leading : .center)
.font(.title)
.padding()
.background(buttonColor.background)
.foregroundColor(buttonColor.foreground)
.overlay {
if configuration.isPressed {
Color(white: 1.0, opacity: 0.3)
}
.clipShape(Circle())
}
}
.clipShape(Capsule())
}
}
Loading