여는글
Swift는 타입 체크를 모두하는 강타입(Strong Type) 언어이다. 이와 동시에 MVC로 구분해서 프로그램을 작성할 수 있다. 이에 대해서 간단히 설명을 하고 기존에 만든 계산기 프로그램의 MVC를 대략적으로 나눠보겠다.
이후에 변수에 get, set 함수를 정의하여 getter와 setter를 생성해보겠다.
다음으로 Enum과 Structure를 비교하겠다.
마지막으로, Dictionary를 사용하는 방법에 대해서 자세히 알아보도록 하자.
MVC in Swift
Swift는 MVC를 명확히 나눌 수 있는 언어중에 하나라고 본다. MVC 개념에 대해서 자세하게 다루지는 않을 것이다.
[https://itunes.apple.com/us/course/developing-ios-8-apps-swift/id961180099 - 3번째 강의에서 참조]
위 그림을 보면서 하나하나 설명을 해보자.
기본적으로 어떤것이 각각의 MVC에 대응되는지 파악해보자.
1. Model
- 모델에 대응하는 것은 딱히 이거다! 하는 것이 없다.
- 어플리케이션을 작성하면서 어떤 것이 데이터에 해당하고, 데이터를 어떻게 가공해서 보여줄지를 잘 파악하여 모델로 묶으면 된다.
- 이따가 계산기프로그램에서 어떤 것을 모델로 가지고 갈 건지 나누는 것을 보면서 추가적으로 설명을 더해보겠다.
2. View
- 뷰는 명확하다. Story 보드에 존재하는 UI이다.
- 간혹 컨트롤러에 UI를 생성하는 코드를 작성할 때도 있지만, 되도록 Story 보드에서 모두 생성한다음에 보였다 안보였다를 조절 하는
것이 맞는 방법일 것이다.
3. Controller
- 컨트롤러 또한 명확하다. Controller라고 파일 이름이 지정되어있으니!
- 하지만, Model과 Controller의 구분을 명확히 하지 않으면 복잡한 형태가 될 수 있다.
다음으로 MVC간의 통신에 대해서 보자. MVC간의 통신은 위 그림에 잘 나타있다.
Controller는 직접적으로 View와 Model에 접근을 하여 View를 변환하거나, Model값을 가져 올 수 있다. View와는 Outlet이라는 개념을 통해서 통신을 한다.
View는 Controller에 직접적인 접근이 불가능하다. 그리고 View에서 Model로 바로 접근하는 것은 불가능하다. View에서 Controller로 접근하는 방법은 Listener 즉, Action을 이용해서 접근하는 것이다. 또 Delegate와 Data source등을 이용해서 Controller에 접근이 가능하다. Controller에 접근한다고 Controller의 행동이 바뀌거나 하는 것은 아니다. Controller에 신호를 보내서 Model값을 다시 가져오거나 다른 행동을 취하게 하는 것이다.
Model 또한 Controller에 직접적인 접근이 불가능하다. Model의 값이 변환되었을때 신호를 보내 Controller를 하여금 다시 값을 가져오게 시켜야 한다.
무엇을 모델로 두고 무엇을 컨트롤러에 두어야 하는가?
이것에 대한 명확한 답은 없을 수 있다. 그리고 수많은 사람들이 혼돈하는 것중에 하나이다. 필자도 가끔씩 혼돈하여 두개를 구분없이 사용할 때도 있다. 모델을 구분할때 생각해야 하는 것은 2단계의 스탭이 있다고 본다.
1) 이 프로그램을 관리 하는데 저장해야 할 데이터는 무엇인가?
2) 저장된 데이터를 불러올 때 해줘야 할 일이 있는가?
2번째 단계에 대해서는 많은 의문이 있다. 모델에서 처리하고 가져오는 것이 편할때가 있고, 컨트롤러에서 처리하는 것이 좋을 때가 있다. 기본적으로는 모델단계에서 저장된 데이터를 처리해서 가져오는 것은 SQL을 실행할때 원하는 데이터 형태를 다 계산해서 가져와서 효율을 높이는 형태와 같다고 볼 수 있다. 컨트롤러는 단지 가져온 값에 따라서의 행동을 처리하면 된다.
하지만 필자는 2번째 단계에 대해서 유연하게 대처한다. 이로인해서 완벽한 MVC가 되지 않을 수도 있지만...
계산기 프로그램을 보자. (이전 글의 맨아래 소스 코드를 다운받아 보시면 됩니다.)
여기서 보면, 입력받은 숫자와 선택된 계산법을 데이터 셋으로 생각하여 저장한다음에 결과값을 구하여 반환하는 것까지 하나의 모델로 묶을 수 있을 것이다.
아래의 파일은 MVC 개념을 도입해서 만든 계산기의 완성 코드이다.
Getter, Setter
필자가 Swift를 보면서 깜작놀랐던 것인 Getter와 Setter이다. 변수 선언과 동시에 Getter와 Setter를 지정할 수 있다.
예제
var displayValue: Double {
get {
return NSNumberFormatter().numberFromString(display.text!)!.doubleValue
}
set {
display.text = "\(newValue)"
userIsInTheMiddleOfTypingANumber = false
}
}
예제는 계산기에 있는 displayValue를 선언한 부분이다.
displayValue 값은 Label에 있는 값을 자신의 값처럼 사용한다. 따라서 Get함수는 Label값을 가져와 Double로 변환하여 반환한다. set 함수에는 newValue라는 것이 기본적으로 반환된다. 이는 displayValue = [VALUE]로 호출하면 VALUE가 newValue로 전달한다.
Enum VS Structure
Enum과 Structure 모두 Swift에서 제공하는 데이터 단위이다. Enum은 갖을 수 있는 값을 지정한 것이고, Structure는 Structure만의 변수를 갖을 수 있다. 이 두가지에 대한 명확한 차이는 아래를 보면서 살펴보자.
참조 : http://blog.teamtreehouse.com/enums-structs-swift
1. Enum
Enum은 그 변수가 갖을 수 있는 값을 지정할 수 있다. 즉, Enum으로 생성된 변수는 Enum안에 있는 값들중 하나를 선택해야 한다.
예를들어보자.
enum Relationship{
case Family
case Friend
case Coworker
case Etc
init(){
self = .Coworker
}
}
var relation0: Relationship = Relationship.Family
var relation1: Relationship = Relationship()
relation0은 Family, Friend, Coworker, Etc중에 하나의 값만을 갖을 수 있으며 초기화 값은 .Family이다.
enum에도 생성자를 붙일 수 있다. 생성자가 있을 경우 해당 enum을 생성해주면 init이 실행되어 초기화를 한다. relation1의 초기값은 생성자에 의해서 .Coworker가 된다. relation1도 Family, Friend, Coworker, Etc중에 하나의 값을 갖을 수 있다.
2. Structure
Structure는 해당 변수가 또 다른 데이터를 갖을 수 있는 형식을 취한다. 즉, Structure 안에 있는 변수는 해당 Structure의 변수가 된다. 마치 클래스처럼 사용이 가능해진다.
예를들어보자.
struct People{
var firstName: String
var lastName: String
var age: Int
}
var person = Array< People >()
person.append(People(firstName: "Cloud", lastName: "Travel", age: 21))
한명 한명의 사람(People)은 성, 명, 나이를 갖는다. 그리고 이에 대한 변수를 선언할때에는 Optional Value를 제외한 모든 값에 대해서 값을 전달해줘야 한다.
※ 추가적으로 클래스와도 비교해보자
- 구조체와 클래스는 비슷한 구조를 가지고 있다.
- 하지만, 클래스는 상속이 가능하다.
- 클래스는 Call by reference 방식이다. 하지만 Structure나 Enum은 Call by value 방식이다.
Dictionary
기초단계에서 설명할대 Dictionary를 해쉬와 유사하다고 설명하고, 엄청 간단하게 설명하였다. Dictionary는 Hash와 유사하게 Key-Value가 하나의 쌍을 이룬다. Dictionary를 선언하는 방법은 다음과 같다.
var [NAME] = Dictionary<[Key-Type], [Value-Type]>()
ex)
var AlphaToNum = Dictionary<String, Int>()
// 지속적으로 Dictionary에 값을 추가하거나 Dictionary에서 값을 가져올 수 있다.
AlphaToNum["A"] = 76
AlphaToNum["a"] = 91 // ASCII code인데 맞는지는 생각이 나지 않는다... 반대인가..?
let result: Int = AlphaToNum["A"]! // 이곳을 주목!!
println("\(result)")
이곳을 주목을 주목하라. Dictionary에 존재하지 않는 값을 우리가 호출하려고 할 수 도 있다. 따라서 기본적으로 Dictionary에 대한 반환은 Optional 값이다. 이에 따라서 값을 정확히 보기 위해서는 Type을 지정해주고, 있다는 것을 확신 시켜줘야 한다. if let을 이용해서 체크를 하는 것이 이상적이다. 위에서는 귀찮아서 확실히 있는 값이므로 "!"로 처리 하였다.
마치는글
Swift를 공부하면서 듣거나 느낀 여러가지 것들이 있다.
1. 함수를 정의할때는 반환값에 Optional이 필요한지 안한지를 정확히 파악할것!
- 오류가 있어서 반환값에 빈값이 올 수 있는 경우 함수 선언에서 반환값을 Optional로 설정한다.
- 함수 호출부에서는 if let을 이용하여 값이 nil인지 아닌지를 파악한 후에 후처리를 하는 것이 이상적이다.
2. '_' I don't care what it is!! "_" under-bar는 나는 이곳에 무엇이 들어갈지 신경쓰지 않겠다. 무엇이 와도 된다. 이런 의미를 나타낸다.
3. !와 ?의 차이를 명확히하자
- 두개다 Optional을 나타내는 값이다.
- 두개의 차이는 Compile 시점에 있다. 선언에서 ?로 한다면 사용시 !표를 계속 붙여야 하는 불편함이 발생할 수도 있다.
공부하면서 느끼는 것은 이렇게 글 마지막마다 작성할 예정이다. 힘내자.. 1주일안에 스위프트를 마스터해보자...