Skip to content

Commit 03acfd4

Browse files
committed
add post
1 parent e8c43e7 commit 03acfd4

File tree

1 file changed

+120
-0
lines changed

1 file changed

+120
-0
lines changed
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
---
2+
layout: post
3+
title: "[Swift] Private Extension과 Helper 타입"
4+
tags: [Swift, Extension, Helper]
5+
---
6+
{% include JB/setup %}
7+
8+
우리는 코드를 작성할 때, 전달받은 Parameter를 이용하거나 변수의 값을 조합하는 등을 통해 새로운 값을 만들어 전달합니다.
9+
10+
<div class="mermaid" style="display:flex;justify-content:center;">
11+
graph LR;
12+
A-->Business_Logic-->B;
13+
</div>
14+
15+
다음과 같이 문자열이 들어왔을 때, 소수점 둘째자리까지 표시하는 문자열을 반환한다고 가정해봅시다.
16+
17+
```swift
18+
struct Service {
19+
// 소수점 둘째자리까지 표시
20+
func displayAmount(_ amount: String) -> String? {
21+
let formatter = NumberFormatter()
22+
formatter.numberStyle = .decimal
23+
formatter.maximumFractionDigits = 2
24+
formatter.roundingMode = .down
25+
formatter.groupingSeparator = ","
26+
return formatter
27+
.number(from: amount)
28+
.flatMap { formatter.string(from: $0) }
29+
}
30+
}
31+
32+
service.displayAmount("123.456") // "123.45"
33+
```
34+
35+
위와 같은 코드는 Interactor, Service, Model 등과 같은 코드에서 많이 사용하며, 이를 Extension으로 코드를 분리할 수 있습니다.
36+
37+
```swift
38+
struct Service {
39+
func displayAmount(_ amount: String) -> String? {
40+
amount.roundDownTwoDecimalPlaces
41+
}
42+
}
43+
44+
private extension String {
45+
var roundDownTwoDecimalPlaces: String? {
46+
let formatter = NumberFormatter()
47+
formatter.numberStyle = .decimal
48+
formatter.maximumFractionDigits = 2
49+
formatter.roundingMode = .down
50+
formatter.groupingSeparator = ","
51+
return formatter
52+
.number(from: self)
53+
.flatMap { formatter.string(from: $0) }
54+
}
55+
}
56+
```
57+
58+
Extension 코드에 접근제어자를 `Private`를 사용한 것은 해당 파일에서만 사용하고, 다른 곳에서는 사용하질 않도록 하기 위함입니다. 또한, 일정 수준 이상 코드를 작성하게 되면 Extension에 작성된 코드를 볼 일이 거의 없습니다.
59+
60+
그러나 Extension으로 코드 분리하였지만 그건 위치만 변경되었을 뿐, 기존 코드와는 큰 차이가 없습니다. 또한, 해당 파일의 대부분은 Extension 코드가 많이 차지할 수 있습니다. Swift는 특정 폴더 내에서만 사용 가능한 접근제어자 같은 기능을 제공하지 않습니다. Extension의 접근제어자를 Private 말고는 다른 것을 사용하기도 애매합니다.
61+
62+
그러면 어떻게 하는 것이 좋을까요?
63+
64+
## Helper 타입
65+
66+
Swift는 타입 내에서 타입을 정의할 수 있는 기능을 제공합니다.
67+
68+
```swift
69+
struct A {
70+
struct B {}
71+
}
72+
73+
// or
74+
75+
extension A {
76+
struct B {}
77+
}
78+
```
79+
80+
B 타입은 A 타입 내에 정의되었기 때문에, 외부에서 `A.B`로 직접 접근하지 않는 이상, B 타입을 접근할 일이 거의 없다고 볼 수 있습니다. 그러면 이를 조금 응용하면 Helper 타입을 만들고, 별도의 파일로 분리한다면, 어떨까요?
81+
82+
```swift
83+
/// FileName : Service.swift
84+
struct Service {
85+
private let helper = Helper()
86+
87+
func displayAmount(_ amount: String) -> String? {
88+
helper.roundDownTwoDecimalPlaces(from: amount)
89+
}
90+
}
91+
92+
/// FileName : Service+Helper.swift
93+
extension Service {
94+
struct Helper {}
95+
}
96+
97+
extension Service.Helper {
98+
func roundDownTwoDecimalPlaces(from value: String) -> String? {
99+
let formatter = NumberFormatter().roundDownTwoDecimalPlaces
100+
return formatter
101+
.number(from: value)
102+
.flatMap { formatter.string(from: $0) }
103+
}
104+
}
105+
106+
private extension NumberFormatter {
107+
var roundDownTwoDecimalPlaces: NumberFormatter {
108+
locale = .init(languageCode: .korean)
109+
numberStyle = .decimal
110+
maximumFractionDigits = 2
111+
roundingMode = .down
112+
groupingSeparator = ","
113+
return self
114+
}
115+
}
116+
```
117+
118+
Service는 Helper에 선언된 roundDownTwoDecimalPlaces 함수를 호출하여 결과를 얻을 수 있습니다. 또한, Service 파일은 Extension 코드가 없기 때문에 코드량이 적어집니다. 이는 유지보수할 때, 파일 단위로 코드를 파악하기 쉬워집니다.
119+
120+
다른 언어에서 Helper 타입과 유사한 것을 정의하고 사용하고 있어, 새로운 개념은 아니지만, Swift와 Objc에서는 Extension을 통해 코드를 사용하는 관습이 많이 있어 생각을 조금만 전환해보면 코드를 분리하여 사용할 수 있습니다.

0 commit comments

Comments
 (0)