애플의 새로운 언어, 스위프트
1-1. 스위프트의 특징
- 개발 생산성과 앱 성능 모두에서 만족할 만한 결과를 가져오는 언어로 포지셔닝되어 있습니다.
- C, C++, Objective-C, JAVA처럼 정적 바인딩을 채용하고 있습니다.
- 데이터 타입 추론 기능에 의해 컴파일러가 알아서 변수와 상수의 타입을 결정하기 때문에 동적 바인딩 언어인 것처럼 착각되기도 합니다.
- 데이터 타입에 대한 구분이 엄격합니다
- 선언된 변수와 상수는 컴파일 단계에서 데이터 타입이 미리 정의되어 있어야 하고, 일단 변수의 데이터 타입이 정의되면 다른 타입으로 변경할 수 없습니다.
- 엄격성을 바탕으로 컴파일러는 타입에 맞지 않는 데이터가 변수에 대입되는 것을 사전에 차단하여 안정성을 높일 수 있습니다.
- 네임스페이스를 사용하여 필요한 객체들을 참조하는데, 일반적으로는 프로젝트 전체가 네임스페이스의 범위로 지정됩니다.
- 같은 프로젝트 내에 작성된 객체들은 반입 과정 없이 참조할 수 있습니다.
- 스위프트에서 import 구문은 UIKit, Foundation 등의 프레임워크나 라이브러리 정도에만 사용하게 되어 개발 생산성을 향상할 수 있습니다.
1-2. 스위프트의 주요 기능
현대에 와서 발표되는 언어 중 전적으로 새로운 언어는 거의 존재하지 않습니다.
기존에 발표된 언어에서 아이디어를 차용하여 자신의 것으로 발전시키고, 시간이 지나면 또 다른 언어가 이를 차용하는 과정이 반복되기 때문입니다.
애플이 스위프트를 만들면서 주변 언어로부터 차용한 10가지 개념 및 특징
1. 딕셔너리(해시 테이블) - 자바스크립트, 파이썬
자바스크립트 개발자들은 대괄호 구문을 이용하여 값을 배열로 만들거나 문자열을 입력받는데, 이것이 해시 테이블 역할을 합니다.
이것을 딕셔너리(Dictionaries)라고 부르며, 초기화할 수 있는 구문을 제공합니다.
var airports = [String : String?] ()
airports["ICN"] = "Inchon International Airport"
// If close "Inchon Interational Airport", then delete it"
airports["ICN" = nil
// ICN has now benn removed from the dictionary
2. 데이터 타입 추론 - 함수형 프로그래밍 언어
최근의 우수한 컴파일러들은 데이터로부터 스스로 형식을 추론할 수 있으므로 컴파일러가 알아서 변수에 데이터 형식을 지정할 수 있게 되었습니다.
이러한 움직임은 ML과 같은 함수형 언어부터 시작 됐으며 이후 다양한 언어에도 등장했고 마이크로소프트까지도 이같은 추론 기능을 닷넷 프레임워크에 추가한 만큼 이제는 주류 기능이라고 할 만합니다.
데이터 타입은 강제하지만, 데이터 타입을 생략할 수 있는 스위프트 컴파일러의 발전 덕분에 iOS 개발자들도 이제 코드 입력에 드는 수고를 조금은 덜 수 있게 되었습니다.
let meaningOfLife = 42
// meaningOfLife is inferred to be of type Int
3. 데이터 구조체 타입 선언 - C#, JAVA
제네릭 타입을 통해 HashMap, Array, Collection에 넣을 데이터 형식을 컴파일러에게 미리 알 수 있도록 지원합니다.
자바 5 버전, C#은 제네릭 타입 기호인 '<', '>'를 사용하여 데이터 구조체에 저장될 형식을 지정하곤 합니다.
스위프트에도 적용이 되어 데이터 구조체에 저장될 타입을 컴파일러에게 미리 알려줄 수 있게 되었습니다.
var namesOfIntegers = Dictiionary<Int, String>()
// namesOfIntegers is an empty Dictionary<Int, String>
4. 문자열 템플릿 - 콜드 퓨전, JSP, Python 등
-
최초의 컴퓨터는 단순히 숫자만을 처리했지만, 요즘은 프로그래머가 하는 일 대부분은 문자열을 이어 붙이는 작업입니다.
-
편의를 위해 많은 프로그래밍 도구들이 변수값을 문자열 템플릿에 삽입하는 기능을 제공합니다.
-
콜드 퓨전(Cold Fusion), 자바 서버 페이지(JSP, JAVA Server Page), 파이썬 서버 페이지(PSP, Python Server Page)와 같은 웹 도구들은 오래전부터 데이터와 HTML을 템플릿에서 혼합하는 간편한 방법을 제공해왔습니다.
-
스위프트는 역슬래시와 함께 소괄호를 작성하고, 그 안에 평가할 식이나 변수를 넣어 출력해주는 깔끕한 템플릿 시스템을 제공합니다.
-
세 번의 부가적인 키 입력으로 문자열 템플릿을 제공하는 이 방식은 같은 기능을 수행하기 위한 키 입력 중에서는 가장 적은 수일 것입니다.
let apples = 3
let oranges = 5
let appleSummary = "I have \(apples) apples"
let fruitSummary = "I have \(apples + oranges) piece of fruit"
5. 선택 사항인 세미콜론 - Javascript, Python
- 세미콜론(;)은 한 행의 구문이 끝났음을 알려주는 간편한 방법이지만, 어떤 이유에선지 세미콜론을 입력하기 싫어하는 개발자의 수가 증가하고 있습니다.
- 스위프트에서 세미콜론은 라인 끝에 붙일 수 있는 선택 사항입니다. 여러 구문을 한 라인으로 묶어야 할 때에는 세미콜론이 필요하지만, 각 구문을 개별 라인으로 작성할 때는 세미콜론 기호를 입력할 필요가 없습니다.
6. 프로토콜(인터페이스) - Java, C#
- Java, C#에서 정교한 객체지향 클래스 구조체를 만드는 프로그래머는 먼저, 기본 인터페이스부터 설계를 시작하는 경우가 많습니다.
- 인터페이스는 클래스가 정의에 부합하기 위해 제공해야 하는 모든 함수에 대한 구조를 정의하는 기본 클래스입니다.
- 스위프트는 클래스 모음의 인터페이스에 대해 '프로토콜'이라는 용어를 사용합니다.
protocol ExampleProtocol {
var simpleDescription : String { get }
mutating func adjust()
}
7. 튜플(Tuple) - Lisp, Python
- 리스프와 같은 초기 언어는 모든 요소를 튜플 목록으로 간주했는데, 파이썬 같은 근래의 언어는 메소드에서 반환되는 N개의 값과 여기에 바인딩되는 N개의 변수를 맞추기 위한 명시적인 구문을 제공합니다.
- 스위프트도 이 방식을 따라 튜플을 지원합니다.
func getGasPrices() -> (Double, Double, Double) {
return (3.59, 3.69, 3.79)
}
getGasPrices()
8. 자동참조(가비지 콜렉터 비슷) - Java, C#, Objective-C
-
가비지 콜렉터 : 메모리를 탐색하면서 더는 사용되지 않는 메모리 영역을 회수하는 자동 루틴, 앞 글자를 따서 GC라고 불리기도 합니다.
-
스위프트 자동 참조 카운트 (ARC - Auto Referencing Counter)를 사용하는데, 이는 Objective-C 사용자들 사이에서 널리 사용된 것과 비슷한 솔루션입니다.
9. 부호 있는 정수와 부호 없는 정수 - C#, Objective-C
- 좋은 시스템 프로그램이란 바이트 레벨에서 작동하는 프로그램을 의미하는 경우가 많습니다.
- Java와 같은 일부 추상적 언어는 부호 없는 정수의 복잡성을 회피했지만, C# 언어는 이를 수용했습니다.
- 스위프트 역시 1, 2, 4, 8바이트의 부호 없는 정수와 부호 있는 정수를 제공합니다.
let pink : UInt32 = 0xCC6699
let redComponent = (pink & 0xFF0000) >> 16
// redComponent is 0xCC, or 204
let greenComponent = (pink & 0x00FF00) >> 8
//greenComponent is 0x66, or 102
let blueComponent = pink & 0x0000FF
// blueComponent is 0x99, or 153
10. 클로저(Closure) - Lisp, Scheme, Javascript
- 자바스크립트 프로그래머는 소량의 코드를 묶어서 함수처럼 전달하는 클러저를 사용할 수 있습니다.
- 이러한 클러저는 람다 함수 아이디어를 개발한 리스프, 스킴과 같은 언어에서 가져온 것입니다.
- 스위프트는 클러저를 제공할 뿐만 아니라 함수를 1급 객체로 간주, 인자값으로 함수 자체를 전달하는 기능을 제공합니다.
let numbers = [Int]()
numbers.map({
(number:Int) -> Int in
let result = 3 * number
return result
})
11. 멀티 라인 쿼우팅 (Multi-Line Quoting)
- 파이썬 프로그래머들은 세 개의 따옴표를 겹친 """ ~ """를 이용하여 여러 줄의 문자열을 간편하게 입력해 왔습니다.
- 줄바꿈이나 범위에 상관없이 """로 시작하고 """로 닫기만 하면 그 안에 표현된 모든 문자열(공백까지 포함한)이 그대로 처리된다는 장점 덕분에, 긴 문자열을 입력할 때 요긴하게 사용되어 왔습니다.
- 스위프트에서도 파이썬의 멀티 라인 쿼우팅 문법을 도입했습니다.
- 여러 줄의 문자열을 입력하기 위해 더이상 문자열 내부에 인위적인 줄바꿈 문자('\n')를 넣어주지 않아도 된다는 뜻입니다.
let quert = """
SELECT member_id, member_name, member_level, nick_name
FROM member
WHERE login_id = ? AND password = ?
"""
1-3. 구조적 특징
-
빠름
- 벤치마크에서 볼 수 있듯이 복합정렬 연산에서 오브젝티브-C보다 빠른 성능을 나타냅니다.
- 고성능 앱을 만들기 위해 GCC 대신 LLVM 컴파일러를 사용해오고 있는데, 이 컴파일러에서 제공하는 코드 최적화기를 사용하여 소스 컴파일과 최적화를 수행함으로써 스위프트의 성능을 극대화할 수 있습니다.
-
설계에 의한 안전성
- 변수나 상수는 반드시 선언한 후에 사용하도록 강제하였으며, 타입 추론 기능에 의해 변수의 초기값을 기준으로 타입을 정의함으로써 데이터 입력에 대한 안전성을 높이고자 하였습니다.
- 배열과 정수는 오버플로우에 대비하여 확인하며, 특히 개발자가 정의하지 않은 배열 값에 승인하지 않은 값들이 주입될 수 없도록 Array bounds check 기능을 추가하였습니다.
- 포인터에 직접 접근하는 시도를 차단하고, 클래스를 통해 간접적으로만 레퍼런스를 참조할 수 있도록 제한했습니다.
- ARC (Auto Referencing Counter)를 이용하여 자동으로 메모리를 관리하므로 메모리 누수 현상에 대한 안전성도 높일 수가 있습니다.
-
현대적
- 파이썬 언어에 기반을 둔 읽고 쓰기 쉬운 문법을 채택하였습니다. 그 결과, 코드 작성이나 디버깅, 유지보수 과정에서 기존의 오브젝티브-C보다 훨씬 적은 양의 코드가 사용됩니다.
- 손쉬운 유지보수를 위해 헤더 파일 사용 대신 메인 파일에 통합하여 코드를 작성할 수 있습니다.
- 옵셔널(Optional), 제네릭(Generics), 클로저(Closure), 튜플(Tuple)뿐만 아니라 현태 프로그래밍 언어의 특성까지도 상당수 포함하고 있습니다.
-
상호반응
- Xcode 6 버전부터 애플은 스위프트 코드의 프로토타이핑을 위하여 플레이그라운드(Playground) 편집기를 제공합니다. 스위프트 코드를 작성하고, 그 결과와 메모리 스택 등의 정보 확인을 즉시 할 수 있어, 상호반응적으로 코드를 작성할 수 있으며 디버깅도 매우 쉽습니다.
-
완전한 플랫폼
- 단순히 보조적인 수준으로만 스위프트를 사용할 수 있는 것이 아니라,
코코아 프레임워크나 코코아 터치 프레임워크의 모든 API를 스위프트로 호출할 수 있습니다. **
- 오브젝티브-C로 작성되어 있던 핵심 프레임워크의 모든 라인이 스위프트 언어를 이용하여 거의 모두 재작성되었고, 이를 이용하면 오브젝티브-C 코드에 의존하지 않고도 프로그램을 작성할 수 있다는 것은 애플의 발표에 의해 널리 알려진 사실입니다.
-> 스위프트만으로 하나의 완전한 앱을 만들 수 있다.
- 통합
- 스위프트는 객체지향 언어의 특성을 모두 제공하는 동시에 자료형과 흐름 제어, 연산자 같은 저수준 언어의 기본 요소들도 모두 포함합니다.
- 하나의 앱 프로젝트에서 오브젝티브-C와 함께 사용할 수 있도록 통합성도 지니고 있습니다.
- 오브젝티브-C 객체를 스위프트에서 참조할 수 있으며, 각각의 화면별로 오브젝티브-C 또는 스위프트로 나누어 작성하는 것도 가능합니다.
1-4. 오브젝티브-C vs 스위프트
파일 통합
- 오브젝티브-C
- C를 기초로 하여 만들어진 언어이므로 파일 구조도 C처럼 헤더 파일과 소스 파일로 구분됩니다.
- .h 확장자 : 변수나 상수에 대한 선언, 인터페이스에 대한 정의가 작성됩니다.
- .m 확장사 : 헤더 파일에서 정의한 인터페이스를 구현하는 내용이 작성됩니다.
-> 선언과 구현이 분리되는 형태.
- 스위프트
- 헤더 파일과 소스 파일이 모두 .swift 확장자를 갖는 파일 하나로 통합되었습니다.
- 변수나 상수, 각종 객체의 형식에 대한 선언과 실질적인 내용 구현이 모두 하나의 파일에서 이루어집니다.
클래스의 정의와 구현
- 오브젝티브-C
- 헤더 파일에 클래스의 인터페이스를 정의하고, 소스 파일에서는 정의된 인터페이스를 구현합니다.
- 반드시 클래스 선언 시 상위 클래스를 상속받아야 하며, 아무것도 상속받을 필요가 없을 때라도 최상위 클래스인 NSObject를 상속받아야 합니다.
- 스위프트
- 클래스의 인터페이스 정의 없이 바로 클래스를 구현하면 됩니다.
- 상속받아야 할 클래스가 없으면 정말 아무것도 상속받지 않아도 됩니다.
// 오브젝티브-C : 클래스 선언 - 헤더파일
@interface Player : NSObject
@End
// 오브젝티브-C : 클래스 구현 - 소스파일
@implementation Player
@end
// 스위프트 파일 : 클래스 구현
class Player {
}
상속
- 오브젝티브-C
- 다중 상속을 지원하지 않지마느 자바의 인터페이스(Interface) 에 해당하는 개념인 프로토콜(Protocol)을 정의하여 클래스 객체가 준수해야 할 형식을 제공할 수 있습니다.
- 카테고리(Category) 개념을 통해 상속 대신 기존 객체 자체를 직접 확장할 수 있습니다.
- 스위프트
- 다중 상속을 지원하지 않으며 프로토콜을 정의할 수 있습니다.
- 기존 객체를 직접 확장할 수 있도록 Extension이 제공되는데, 이는 오브젝티브-C의 카테고리에 대응하는 개념입니다.
- 단, 오브젝티브-C에서 클래스 객체만 확장할 수 있었던 카테고리에 비해 스위프트의 Extension은 클래스, 구조체, 프로토콜 등 대부분 객체에 적용할 수 있습니다.
범용 타입
- 오브젝티브-C
- 개발의 편의와 효율성을 높이기 위해 모든 데이터 타입을 저장할 수 있는 범용 타입 객체가 필요할 때가 있는데, 오브젝티브-C에서는 이와 같은 범용 타입으로 id 타입을 제공합니다.
- id 타입은 모든 타입의 데이터를 저장할 수 있을 뿐만 아니라, 호환성만 보장된다면 저장된 데이터를 어떠한 타입으로든 변환할 수 있는 특성을 가지고 있습니다.
- 코코아 프레임워크나 코코아 터치 프레임워크에서는 범용 타입을 이용한 API들이 많이 사용되고 있습니다.
- 스위프트
- 동일한 코코아 프레임워크나 코코아 터치 프레임워크를 사용하기 때문에, 오브젝티브-C의 id 타입에 대응하는 범용 타입의 객체가 필요합니다.
- 이 때문에 제공되는 것이 Any 타입과 AnyObject 클래스입니다.
- Any : 구조체, 클래스, 열거형, 함수 등 스위프트에서 제공하는 모든 타입의 값을 저장할 수 있는 타입
- AnyObject : 클래스에 한해 범용으로 사용 가능한 데이터 타입입니다.
메소드 호출
- 오브젝티브-C
- 스몰토크의 문법을 차용한 결과, 메소드 호출을 메시지 전송 방식으로 처리합니다.
- 즉, 객체의 메소드를 호출하는 대신 객체에 메시지를 보내서 필요한 기능을 처리합니다.
- 객체와 메시지는 공백을 통해 연결되며 대괄호를 사용하여 메시지 전송 단위를 감싸서 구분합니다.
- 스위프트
- 일반적인 객체지향에서의 메소드 호출 방식을 따릅니다.
- 객체와 메소드 사이는 점(.)을 통해 연결되고, 메소드 호출 단위를 감싸는 구분자는 사용하지 않습니다.
오브젝티브-C와 스위프트에서의 메소드 호출 방식 예제.
// 오브젝티브-C
[인스턴스명 incrementBy:3]
// 스위프트
인스턴스명.incrementBy(3)
nil의 의미
- 오브젝티브-C
- 존재하지 않는 객체에 대한 참조를 위해 nil이라는 상수를 사용합니다.
- nil과 NULL의 차이
- 상수 간에 차이는 있지만, 오브젝티브-C 문법에서 두 상수는 기술적으로 혼용할 수 있습니다.
- 일반적으로는 nil은 클래스 객체를 참조하는 데에 사용되고, NULL은 그 밖에 다른 포인터 자료형에 사용됩니다.
// 객체의 빈 참조에 사용되는 nil
UIViewController *uvc = nil;
// 포인터 자료형의 빈 참조에 사용되는 NULL
int *sPtr = NULL;
- 스위프트
- 스위프트에서 nil은 옵셔널 타입의 기본값으로 사용되며 ' 값이 존재하지 않음 '을 의미합니다.
- 스위프트에서 NULL 상수가 정의되어 있지 않습니다.
// 옵셔널 타입의 기본값으로 nil이 대입
var name : String? = nil
포인터 사용
- 오브젝티브-C
- 객체에 대한 인스턴스 변수를 정의할 때에는 항상 포인터를 사용하는 레퍼런스 참조를 기본으로 사용했습니다.
- 모든 변수 앞에 포인터를 거의 의무적으로 붙여주다 보니, 오브젝티브-C에서 포인터를 사용한다고는 해도 C 코드를 직접 작성하는 부분을 제외하면 크게 신경 쓸 부분이 없기는 했지만, 그럼에도 포인터를 사용해야 한다는 것은 초보자들에게는 적지 않은 부담으로 작용했습니다.
- 스위프트
- 포인터 개념을 제거하여 개발자가 직접 레퍼런스를 참조하지 않도록 하는 대신, 객체의 종류에 따라 컴파일러가 직접 레퍼런스를 참조할 것인지 아니면 객체를 복사할 것인지를 결정합니다.
- 클래스는 포인터를 사용하지 않아도 자동으로 레퍼런스를 참조하고, 구조체는 객체를 복사하여 사용하는 방식으로 처리됩니다.
객체지향 타입
- 오브젝티브-C
- 객체지향을 위한 타입으로 클래스를 제공합니다.
@Interface 어노테이션을 이용하여 형식을 선언하고,
@Implementation 어노테이션을 이용하여 실질적인 내용을 구현합니다.
이렇게 작성된 클래스를 사용할 때에는 인스턴스를 생성하여 사용합니다.
- 스위프트
- 객체지향용 타입으로 클래스뿐만 아니라 구조체, 열거형까지 제공합니다.
이들 객체 타입은 모두 인스턴스를 만들 수 있으며 인스턴스와 관련된 변수, 상수를 속성(property)으로 선언하여 사용할 수 있습니다.
그뿐만 아니라 이들 객체 타입에 인스턴스 메소드와 타입 메소드를 작성하여 사용할 수도 있습니다.
// 스위프트의 객체지향 타입들 예시
// 클래스 (class)
class SampleClass {
}
// 구조체 (Structure)
struct SampleStruct {
}
// 열거형(Enumeration)
enum SampleEnum {
}
익명 함수
- 현대 프로그래밍 개념에서 익명 함수의 사용은 람다 함수를 사용할 수 있게 해주는 리스프, 스킴같은 함수형 프로그래밍 언어로부터 도입되었다고 할 수 있습니다.
- 람다 함수는 함수 기반으로 정의되는 코드 내에서 한 번만 사용하면 되는 코드마저 함수로 선언해서 사용해야 하는 번거로움을 피할 수 있게 해 줌으로써 코드를 더욱 간결하게 만들어 줍니다.
- 람다 함수는 최근 자바 8에서도 도입되는 등 프로그래밍 언어의 강력한 기능으로 고려되고 있습니다.
- 오브젝티브-C에서는 블록(Block)이라는 개념으로 익명 함수를 표현할 수 있었는데, 이 기능이 스위프트에서는 클로저를 이용한 익명 함수 정의 문법으로 제공됩니다.
오류 처리
- 일반적으로 객체 지향 언어에서 제공하는 오류 처리 기능은 오류 발생이 예상되는 지점에 미리 오류를 검출하는 코드를 작성해두고, 실제로 오류가 발생할 때 정해진 코드 블록 바깥으로 오류정보를 던져 처리할 수 있도록 지원하는 방식입니다.
- 오브젝티브-C
- 오류를 검출하기 위한 기능은 제공되었지만, 이는 읽고 쓸 수 있는 매개변수를 사용하여 오류를 검출해내는 방법이었을 뿐 오류 처리를 위한 구문이 별도로 제공된 것은 아니었습니다.
- 스위프트
- 2.0버전부터 오류를 검출해내고 각 오류에 효과적으로 대응할 수 있도록 전용 구문을 제공하고 있습니다.
- 많은 프로그래밍 언어에서 널리 사용하는 Try ~ Catch 구문을 채택한 스위프트는 코드를 실행하는 과정에서 오류가 발생하더라도 프로그램이 중단되는 것을 막아주고, 미리 준비된 대응 구문을 효율적으로 오류에 대응할 수 있게 합니다.