[swift2] Xcode7 beta5 Swift 언어 변경사항

Swift 2015. 8. 14. 02:14


Linker

  • bitcode를 활성화하면 이제 weak frameworks와 weak libraries가 지원됩니다. linker는 더이상 -weak_framework, -weak-l 또는 -weak_librarys가 -bitcode_bundle 과 함께 사용될수 없다고 경고하지 않습니다.


Swift Language Changes

1. 구조체, 클래스도 이제 ErrorType 프로토콜을 구현할수 있습니다.


2. 실패가능한 initializer에 위임하거나 체이닝할 때 !를 사용하여 force-unwrap 할 수 있습니다.

  • self.init(...) 또는 super.init(...)가 실패가능한 경우 아래코드와 같이 force-unwrap 할 수 있습니다.
extension UIImage {
    enum AssetIdentifier: String {
        case Isabella
        case William
        case Olivia
    }
    convenience init(assetIdentifier: AssetIdentifier) {
        self.init(named: assetIdentifier.rawValue)!
    }
} 
  • 위와같이 실패가능한 initializer에 체이닝한 non-optional initializer 정의가 가능해집니다.


3. 성능향샹을 위한 -Onone 빌드 옵션

  • -Onone 옵션 (debug) 빌드를 사용하면 표준라이브러리 제네릭 타입에 특화된 인스턴스를 사용하여 빌드성능을 향상시킬 수 있습니다.
  • 많은 경우에 컴파일 타임에 영향없이 debug 빌드에서 상당히 빠른 실행파일을 생성합니다.


4. Objective-C 클래스의 제네릭 서브클래스와 이것을 상속하는 non-제네릭 클래스들은 runtime metadata 인스턴스화가 요구됩니다.

  • Objective-C 코드에서 직접적으로 네이밍을 지정할수 없습니다.
  • Beta4에 Objective-C 클래스들의 제네릭 서브클래스 정의가 가능해졌지만, 생성된 Objective-C 브리징 헤더에는 그러한 클래스들을 에러항목으로 리스팅합니다. 이로인해 잘못된 런타임 행동과 컴파일 타임에러를 발생시키는 오류를 수정하였습니다.
  • 클래스에 대한 @objc 속성의 행동이 좀더 명확해졌습니다.
  • 브리징헤더에 나타날 수 없는 클래스에 @objc를 적용하면 이제 에러입니다.
  • 클래스의 어떤 수퍼클래스라도 @objc 클래스라면, 그 클래스의 멤버들은 암묵적으로@objc 이며, 모든 @objc 클래스들은 NSObject 를 상속해야함. 따라서 유효한 코드에 대한 어떤 변경을 발생시키지는 않습니다.


5. MacTypes.h 에 정의된 Boolean은 Swift와 Objective-C 타입 브리징 상황에서 Bool로 임포트됩니다.


6. NSManaged 속성을 CoreData가 자동생성한 키밸류코딩 호환 to-many 접근자에 접근하기 위한 메서드와 프로퍼티에 사용할 수 있습니다.

@NSManaged var employees: NSSet

@NSManaged func addEmployeesObject(employee: Employee)
@NSManaged func removeEmployeesObject(employee: Employee)
@NSManaged func addEmployees(employees: NSSet)
@NSManaged func removeEmployees(employees: NSSet)
  • 이것들은 NSManagedObject 서브클래스에 선언되어야 합니다.


7. 타입 이름들과 enum cases들은 이제 디폴트로 자격없이(프로토콜 구현없이) print하고 String으로 변환할수 있습니다. debugPrint와 String(refelcting:)은 fully-qualified 이름을 얻기 위해 사용할 수 있습니다.

enum Fruit { case Apple, Banana, Strawberry }
print(Fruit.Apple)           // "Apple"
debugPrint(Fruit.Apple)      // "Fruit.Apple"


8. print()와 Mirrors의한 reflection은 current case와 멀티 payload 타입을 갖는 모든 enums payload를 report 할수 있습니다.

  • 유일하게 reflection이 지원되지 않고 남아있는 enum 타입들은 @objc enums와 C에서 임포트된 enums 입니다.


Swift Standard Library Enhancements and Changes

1. SequenceType 프로토콜 구현체에 .forEach 구문을 사용할 수 있습니다.

(0..<10).forEach {
    print($0)
}    

위 구문은 아래구문과 유사합니다.


for x in 0..<10 {
    print(x)
}

하지만 다음과 같은 차이점이 있습니다.

  • for-in 루프문과 다르게 break, continute를 사용하여 현재 클로져 몸체 호출을 종료하거나 일련의 호출을 건너뛸수
    없습니다.

  • 클로져 몸체에 return문을 사용하면 외부 스콥이 아닌 현재 호출만 종료할수 있으며, 이어지는 일련의 호출을 건너뛸수 없습니다.

  • 이러한 제약때문에 forEach 멤버는 함수형 알고리즘에 일련의 체이닝을 적용하고, 몸체가 적을때만 사용하도록 권장합니다.

foo.map {...}.filter {...}.forEach {...}
  • 다른 경우에는 for..in 문 사용을 권장합니다.


3. SIMD: simd 모듈의 정수형 벡터타입은 &+, &-, & 연산자를 사용하여 감싸진 unchecked 산술식만 지원합니다. +,-, 연산자들은 정수형 벡터에는 사용 불가능하고 Xcode가 자동으로 wrapping 연산자로 교체하라고 제안할 것입니다.


4. SIMD: smid 모듈의 정수형 벡터타입 코드생성은 벡터하드웨어를 더 잘 사용할 수 있도록 개선되어 대부분의 경우에 극적으로 성능이 향상되었습니다.


5. Dictionary의 removeAtIndex(_:) 메서드는 key,value 쌍을 제거하여 두 엘리먼트를 튜플로 반환합니다.

  • 유사하게 Set의 removeAtIndex(_:)은 삭제된 엘리멘트를 반환합니다.


6. Word와 UWord 타입은 표준라이브러리에서 삭제되었습니다. 대신 UInt를 사용하세요.




[swift1.2] Swift 프로토콜 지향 프로그래밍

Swift 2015. 8. 6. 00:57



WWDC 2015 세션중 "Protocol-Oriented Programming in Swift" 라는 흥미로운 세션이 있습니다. 애플에서 Standard Library 그룹의 리더를 맡고 있는 Dave Abrahams 라는 분이 발표한 세션입니다. 세션에서 제공하는 슬라이드와 InfoQ에서 이 세션을 정리한 아티클을 바탕으로 내용을 요약했습니다.


클래스는 멋집니다!


다음과 같은 멋진 특징들을 제공하지요.

  • 캡슐화 (Encapsulation)
  • 접근제어 (Access Cotrol)
  • 추상화 (Abstraction)
  • 네임스페이스 (Namespace)
  • 풍부한 문법 (Epressive Syntax)
  • 확장성 (Extensibility)

그런데...


구조체로도 다 할수 있습니다.

클래스는 훌륭합니다. 타입은 훌륭합니다!

사실 위 특징들은 모든 타입들의 특징이며 클래스는 그것을 구현하는 하나의 방법에 불과합니다. 그렇다면 클래스 사용으로 인한 단점은 무엇이 있을까요?


1. 암묵적인 참조(Reference) 공유

  • 두 객체가 동시에 어떤 객체를 참조하는 경우, 서로 그 사실을 모른채 그 객체를 변경할 수 있습니다.
  • 참조 공유를 방지하기 위해 참조하는 객체를 복사할 수 있지만, 그렇게 하면 효율성이 나빠집니다.
  • 참조를 공유하는 객체에 Race Conditions 이 발생할 수도 있습니다.
  • Lock을 사용하여 레이스 컨디션을 방지할수 있지만 효율성은 더 나빠집니다.
  • Lock을 잘못 사용하면 Deadlock 상태에 빠질 수 있습니다.
  • 잦은 Lock 사용은 코드를 복잡하게 합니다.
  • 복잡성은 더 많은 버그를 유발합니다.

Values Don't Share. (That's a good thing)


2. 상속 (비지니스에 관한 모든 것을 가지고 있습니다.)

  • 슈퍼 클래스를 하나 밖에 가질수 없기 때문에, 초기에 잘 선택해야합니다.
  • 슈퍼 클래스를 나중에 변경하는 것은 매우 어렵습니다.
  • 슈퍼클래스가 갖는 모든 저장속성은 서브클래스에도 (강제적으로) 상속됩니다.
  • 초기화 처리가 복잡해집니다.
  • 수퍼클래스의 불변성을 깨뜨리지 않을수 없게됩니다.
  • 언제 무엇을, 어떻게 재정의해야 하는지 (수퍼 클래스에 대해서)알아야 합니다.

More and more, we promote delegation.


3. 타입관계를 잃어버립니다.(Lost Type Relationships.)

  • 추상 수퍼클래스와 서브클래스의 구현코드가 함께 존재하게 됩니다.
  • 서브클래스 메소드에 접근하기 위해 수퍼클래스를  서브클래스로 다운캐스팅하면서 타입관계를 잃게됩니다.

  • 이진탐색 클래스 모델 Ordered 정의

class Ordered {
    func precedes(other: Ordered) -> Bool { fatalError("메소드를 구현해주세요.") }
}

class Number:Ordered {
    var value:Double = 0
    override func precedes(other: Ordered) -> Bool {
        return value < (other as! Number).value // 
    }
}  

func binarySearch(sortedKeys: [Ordered], forkey k: Ordered) -> Int {
    var lo = 0
    var hi = sortedKeys.count
    while hi > lo {
        let mid = lo + (hi - lo) / 2
        if sortedKeys[mid].precedes(k) { lo = mid + 1 }
        else { hi = mid }
    }
    return lo
}

as! ASubclass 는 타입 관계를 잃어버렸다는 신호
대부분 추상화를 위해 클래스를 사용하기 때문이다.


4. 좋은 추상화 메커니즘이란?

  • Value type을 지원합니다.(클래스 외에도)
  • 정적 타입관계를 지원합니다. (동적 디스패치 외에도)
  • 큰 덩어리로 뭉치지 않아야합니다.
  • Retroactive 모델링을 지원합니다.
  • 모델에 인스턴스 데이터를 강요하지 않아야 합니다.
  • 모델에 초기화의 부담이 없어야 합니다.
  • 무엇을 구현해야 하는지 명확해야 합니다.

Swift는 프로토콜 지향 프로그래밍 언어!


5. 프로토콜 지향 프로그래밍

  • Swift에서 새롭게 추상화를 생각할 때 첫 번째 포인트는 프로토콜!

이진탐색 프로토콜 모델 Ordered 변경해보겠습니다.
protocol Ordered {
    func precedes(other:Self) -> Bool
}    

struct Number : Ordered {
    var value:Double = 0
    func precedes(other:Number) -> Bool {
        return self.value < other.value 
    }
}

이진탐색 함수를 정의합니다.
func binarySearch<T:Ordered>(sortedKeys:[T], forKey k: T) -> Int {
    var lo = 0
    var hi = sortedKeys.count
    while hi > lo {
        let mid = lo + (hi-lo)/2 
        if sortedKeys[mid].precedes(k) { lo = mid + 1 }
        else { hi = mid }
    }
    return lo
}

Int 배열에 이진탐색 함수를 적용해 보겠습니다.
  • 먼저 Int가 프로토콜 Ordered를 구현해야합니다.
// Int형 Ordered 프로토콜 구현하기 

extension Int:Ordered {
    func precedes(other: Int) -> Bool {
        return self < other
    }
}
  • Int 배열에 이진탐색을 적용합니다.
// 1. 키 정렬 
var keys = [10, 30, 1, 4, 5, 6, 7, 8, 55, 20]
var sortedKeys = keys.sorted {  $0 < $1 }
// sortedKeys: [1, 4, 5, 6, 7, 8, 10, 20, 30, 55]

// 2. 찾을 키
var searchKey = 30
// 키 30의 index는 8.

// 3. 이진탐색 
var searchIndex = binarySearch(sortedKeys, forkey: searchKey)
// searchIndex: 8
Number 배열에도 이진탐색을 적용해보겠습니다.
// 1. 정렬된 Number 배열 생성  
var numbers = sortedKeys.map { return Number(value: Double($0)) }
// numbers: [1.0, 4.0, 5.0, 6.0, 7.0, 8.0, 10.0, 20.0, 30.0, 55.0]

// 2. 찾을 키
var keyToSearch = 5.0

// 3. 이진탐색
var index = binarySearch(numbers, forkey: Number(value: keyToSearch))
// index: 2

프로토콜을 사용하면, 커스텀 Number 구조체 뿐만 아니라 기존 타입에도 이진탐색을 쉽게 적용할 수 있음을 알 수 있습니다.




[swift] 문자열 Indexing과 Slicing

Swift 2015. 6. 23. 23:00



Indexing and Slicing Strings

Swift string의 Indexing과 Slicing 대해서 알아보겠습니다.
string은 화면에 보여지는 문자들의 순서집합이라고 생각하는 것이 일반적입니다.
하지만 하나의 문자로 보일지라도 메모리 상에서는 다중 혹은 가변길이의 유니코드값으로 표현되는 경우도 있습니다.

유니코드 문자열

예를 들어 hat emoji (🎩)는 문자 a와 같은 문자보다 인코딩에 더 많은 비트가 필요로합니다.
Swift의 String 타입은 이러한 세부사항들을 처리해줍니다. string을 이루는 각 문자는 (메모리에서 차지하는 길이와는 상관없이)
사용자가 인식하는 유니코드 문자를 표현합니다. 이런 추상화 때문에 정수를 사용해서 string의 인덱스를 표현하는 것이 적합하지
않을수 있습니다.

대신 표준라이브러리는 string에서의 위치를 표현하기에 적합한 String.Index를 제공합니다.

문자열 카운팅

다음 문자열은 가변길이의 유니코드 문자들로 구성되어 있습니다.

var str = "Héllo, 🇺🇸laygr😮und!"
// str의 유니코드 문자의 개수: 18
str.characters.count  // swift2.0
count(str)            // swift1.2
// str의 UTF-16코드 포인트의 개수: 22
str.utf16.count      // swift2.0
count(str.utf16)     // swift1.2

깃발 (🇺🇸) 문자는 사실 2개의 유니코드 스칼라값이 결합되어 구성되지만 Swift는 1개의 문자로 카운팅합니다.
이런 특성이 폼 유효성 검사, 커서 포지셔닝, 텍스트 wrapping 구현을 더 쉽게합니다.
문자열 카운팅, 인덱싱, 슬라이싱은 모두 메모리가 아닌 사용자가 인식하는 문자 인덱스를 기반으로 하고있습니다.

문자열 slicing

string을 index하고 slice하는데 사용하는 Range 값을 생성해보겠습니다.

let badRange = 4..<12   // Range<Int>를 생성합니다.

str[badRange]   // error: 'subscript' is unavailable: cannot subscript String with range of Int

위 코드는 정수형을 string의 인덱스로 사용할수 없다는 컴파일 에러를 발생시킵니다.

대신 다음과 같이 String.Index 객체를 사용할 수 있습니다.

let range = advance(str.startIndex, 4)..<advance(str.startIndex, 12)

string은 startIndexendIndex 속성을 갖습니다.
string의 successor(), predecessor() 함수(swift2.0에서 지원)는 인덱스를 증가 또는 감소시킵니다.

advance() 함수를 사용하여 파라미터의 값만큼 offset를 이동할수 있으며, advance()함수는 인자로 전달받은 offset 만큼 successor(),predecessor()를 호출합니다.

String.Index 타입은 유니코드를 인식할수 있어서 advance()함수가 항상 string index를 적절하게 이동시킬 수 있습니다.

advance() 함수는 인자로 받은 index 타입과 동일한 타입의 값을 반환하기 때문에 ..< range 연산자는 그 타입에 해당하는 range를
생성할수 있습니다.

advance() 함수를 사용하여 string의 특정 index의 문자를 조회해보겠습니다.

str[advance(str.startIndex, 7)] // 🇺🇸를 반환한다.
str[range.startIndex]            // o를 반환한다.
str[range.endIndex]              // 😮를 반환한다.
str[range]                       // o, 🇺🇸laygr를 반환한다.

advance() 함수

또 다른 버전의 advance()함수를 사용해서 메시지를 10자로 제한하는 기능을 구현해보겠습니다.

let messageCharacterLimit = 10
let range = advance(str.startIndex, messageCharacterLimit , str.endIndex)..<advance(str.endIndex, 0)
let result = str.substringWithRange(range)
if result.isEmpty {
    print("empty result")
}
// "ygr😮und!"를 출력합니다.

advance()함수는 startIndex, offset 외에 세번째 파라미터로 endIndex를 전달하면 offset이 endIndex를 초과하는 경우
end.Index를 반환해줍니다. 세번째 인자는 일종의 상한값으로 동작합니다.




[swift] Map, Filter, Reduce

Swift 2015. 6. 22. 23:09



함수를 인자로 취하는 함수를 고차원 함수(higher-order function)라고 합니다.
Swift 표준라이브러리에서 array의 메서드로 제공하는 고차원 함수인 map, filter, reduce에 대해서 알아보겠습니다.

1. Map

    func map<U>(transform: (T) -> U) -> Array<U>

Map은 배열 각 요소 x에 변환함수 transform을 적용하고 그 결과값으로 구성된 배열을 반환하는 함수입니다.
배열요소들을 다른 값으로 맵핑하는 함수이지요.

2. Filter

func filter(includeElement: (T) -> Bool) -> Array<T>

Filter는 조건식을 인자로 받아, 조건식이 true를 만족하는 요소들로만 구성된 배열을 반환하는 함수입니다.
쉽게 말하면, 배열요소들을 필터링하는 함수입니다.

3. Reduce

func reduce<U>(initial: U, combine: @noescape (U, T) -> U) -> U

Reduce는 U를 초기값으로 하여,각 배열요소들과 순차적으로 결합연산을 하여 누적된 단일값을 반환하는 함수입니다.


4. 사용예

이제 사용법에 대해서 알아볼까요? 다음과 같은 정수형 배열이 있습니다.

var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
  1. 1. 정수형 배열의 각 요소에 1을 더한 배열을 얻고 싶다.
  2. 2. 정수형 배열의 각 요소에 2를 곱한 배열을 얻고 싶다.
  3. 3. 정수형 배열에서 짝수로만 구성된 배열을 얻고 싶다.
  4. 4. 정수형 배열 값들의 총합을 얻고 싶다.

map 함수를 사용하여 1,2번 문제의 답을 쉽게 얻을 수 있습니다.

// 1. 정수형 배열의 각 요소에 2를 곱한 배열을 얻고 싶다.  
arr.map { (x) -> Int in
    return x+1
}

// 2. 정수형 배열의 각 요소에 2를 곱한 배열을 얻고 싶다.
arr.map { (x) -> Int in
    return x*2
}

filter를 사용하여 3번을 해결해보겠습니다.

// 3. 정수형 배열에서 짝수로만 구성된 배열을 얻고 싶다. 
arr.filter { (x) -> Bool in
    return x%2 == 0
}  

당연히 4번은 reduce의 몫입니다.

// 4. 정수형 배열 값들의 총합을 얻고 싶다.
arr.reduce(0, combine: { (result, x) -> Int in
   return result + x
})

Trailing Closure 를 사용하여 다소 낯선 형태지만 코드가 너무 짧아 놀라셨죠?   

(Trailing Closure는 함수의 마지막 인자가 클로져(함수)일 경우, 클로져를 함수 호출부의 꼬리(trailing)에 표기하는 방식입니다. )

이러한 고차원 함수들을 복합적으로 사용하여 프로그래밍하는 방식을 함수형 프로그래밍이라고 합니다. 

함수형 프로그래밍은 짧고 명료한 코드를 작성할 수 있게하고, 버그의 가능성 또한 훨씬 줄인다고 합니다.

낯선 함수형 프로그래밍 방식에 익숙해지려면 다소 시간이 걸리겠지요? ^^


5. Map 함수 구현하기

학습한 내용을 좀더 잘 이해하기 위해 직접 map 함수를 만들어 보겠습니다.

일반적인 방법으로 1,2번 문제를 구현하는 코드를 작성했습니다.

var arr = [1, 2, 3, 4, 5]

func pluseOne(arr:[Int]) -> [Int] {
    var result:[Int] = []
    for x in arr {
        result.append(x + 1)
    }
    return result
}

func multiplyTwo(arr:[Int]) -> [Int] {
    var result:[Int] = []
    for x in arr {
        result.append(x * 2)
    }
    return result
}  

두 함수는 연산하는 행위만 제외하고 거의 비슷합니다. 연산하는 행위를 함수로 묶어내면 일반화가 가능해보이네요.

func map(arr:[Int], transform:(Int->Int)) -> [Int] {
    var result:[Int] = []
    for x in arr {
        result.append(transform(x))
    }
    return result
}  

이제 제네릭을 사용하여 범용타입으로 대치하면

func map<T, U>(arr:[T], transform:(T->U)) -> [U] {
    var result:[U] = []
    for x in arr {
        result.append(transform(x))
    }
    return result
}

map 함수가 완성되었습니다. 우리는 글로벌 함수로 구현했지만 표준라이브러리에서는 array의 메소드로 제공한다는 점이 유일한 차이입니다.


5. Filter 함수 구현하기

Map 함수를 구현해보아서 Filter 함수 구현은 좀더 간단합니다.

// 일반적인 방법으로 구현하고
func filter(arr:[Int]) -> [Int] {
    var result:[Int] = []
    for x in arr {
        if x%2 == 0 {
            result.append(x)
        }
    }
    return result
}

// 함수로 공통 행위를 묶어낸 다음
func filter(arr:[Int], includeElement:(Int->Bool)) -> [Int] {
    var result:[Int] = []
    for x in arr {
        if includeElement(x) {
            result.append(x)
        }
    }
    return result
}


// 제네릭 적용
func filter<T>(arr:[T], includeElement:(T->Bool)) -> [T] {
    var result:[T] = []
    for x in arr {
        if includeElement(x) {
            result.append(x)
        }
    }
    return result
}


6. Reduce 함수 구현하기

단계적으로 구현해보니 고차원 함수 구현이 어렵지 않죠? 이제 reduce를 구현해 볼까요?

// 일반적으로 구현하고  
func reduce(arr:[Int]) -> Int {
    var result:Int = 0
    for x in arr {
        result = result + x
    }
    return result
}

// 초기값 할당과 누적하는 행위를 파라미터로 분리하고 
func reduce(arr:[Int], initial:Int, combine:(Int,Int)->Int) -> Int {
    var result:Int = initial
    for x in arr {
        result = combine(result, x)
    }
    return result
}

// 제네릭 적용 
func reduce<T, U>(arr:[T], initial:U, combine:(U, T)->U) -> U {
    var result:U = initial
    for x in arr {
        result = combine(result, x)
    }
    return result
}  

지금까지 Swift 표준라이브러리의 Map, Filter, Reduce에 대해 알아보았습니다.




'Swift' 카테고리의 다른 글

[swift2] Xcode7 beta2 Swift 언어 변경사항  (0) 2015.06.24
[swift] 문자열 Indexing과 Slicing  (0) 2015.06.23
[swift] Map, Filter, Reduce  (0) 2015.06.22
[swift2] New in Swift2.0  (0) 2015.06.19
[swift] Apple Swift Blog  (0) 2015.06.10
[swift] Swift 기초 - 4  (0) 2014.10.29

[swift] Apple Swift Blog

Swift 2015. 6. 10. 01:00


애플 WWDC 2015 에서 Swift2 공개와 올해 말 오픈소스화 발표가 있었습니다.

애플 swift 블로그를 방문하니 역시나 새롭게 단장되어있네요.   Swift2 의 변화를 훑어보기 위해 대문 페이지를 번역해보았습니다. 

[출처]: Apple Swift blog




Swift.  안전하고, 빠르며, 인터렉티브한 

최신의 프로그래밍 언어


Swift는 iOS, OS X, watchOS를 위한 강력하고 직관적인 프로그래밍 언어입니다. 

Swift 코드를 작성하는 것은 인터렉티브하고, 재미있습니다. 문법은 간결하지만 표현력이 풍부하며,  

앱은 번개처럼 빠르게 실행됩니다.  Swift는 당신의 다음 프로젝트 - 또는 현재 앱에도 사용할수 있도록 

준비되어있습니다. - 왜냐하면  Swift는 Objective-C 와 함께 동작하기 때문이지요.




Swift 2 소개

Swift 는 밑바닥부터 개선되었습니다. 릴리즈, 디버그 빌드를 막론하고 더 빠른  코드를 생성합니다.

Swift 컴파일러는 var 대신 let를 사용하라는 새로운 Fix-it 제안을 제공해주는데도 더 빠릅니다.

주석에 마크다운를 사용하여 rich text와 내장 이미지를 추가할 수 있습니다.

새로운 assistant는 header-like 뷰에서 Swift API를 보여줍니다.  그리고 Cocoa 프레임워크와 Objective-C 

코드를 더 풍부하고 훨씬 안정성있게 해주는 새로운 문법들이 개선되었습니다. 




에러처리 모델(Error Handling Model)

진보된 에러처리 모델은 에러를 캐치하고 던지는 명확하고, 풍부한 문법을 제공합니다. 

쉽게 커스텀 에러타입을 정의하고 명확하고 의미있는 이름으로 에러 케이스를 기술할  수 있습니다. 

새로운 에러모델은  NSError 클래스와 Cocoa 프레임워크와 잘 조화되도록 설계되었습니다.


에러 처리 코드의 예입니다.


개선된 문법(Syntax improvements)

새로운 문법 특징들은 언어를 일관성 있게 개선하면서도 더 풍부한 코드를 

작성할 수 있게 합니다. SDK는 Objective-C에, Swift를 더 명확하고 안전하게 하는 

 generics와 nullability 어노테이션을 도입했습니다. 

Swift 2.0에 개선된 몇가지 예입니다. 

- do, guard, defer, repeat를 사용한 강력한 제어흐름 

- 함수와 메서드  키워드 네이밍 규칙 통합

- 프로토콜 extension 과 디폴트 구현 

- if문과 for 루프에서의 확장된 패턴매칭 

Xcode7는 애플리케이션과 playground 코드를 최신 Swift2.0 의 개선된 문법으로 

변환해주는 강력한 마이그레이터를 포함합니다.


가용성(Availability)

최신의 특징, 문서, API 변경사항을 접근하기 위해서 최신의 SDK 사용해야 했지만

때때로 앱이 이전 버전의 OS 에서 실행되야할 때가 있습니다.

Swift2.0 가용성 체킹 기능을 가지고 있습니다. 기능은 target OS version  

가장 적합한 앱을 쉽게 빌드할 있게 해줍니다. 컴파일러는  최소 OS 타겟에서는 지원하지 않는

새로운 api 사용하려 할때 에러를 발생시킵니다

그리고 특정 버전의 OS에서만 실행되도록 버전분기를 해주는 코드블럭를 

랩핑하는 키워드들 제공합니다.


오픈소스(Open Source)

올해 Swift 오픈소스로 릴리즈 됩니다

우아하고, 강력하고 안전한 Swift 결정체가 산업 전반에 소개될 수 있는

기회를 제공합니다. 우리가 함께 개발하는 것을 상상하니 흥미진진합니다. 


모던(Modern)

Swift 수십년의 애플 플랫폼 개발 경험과 가장 최신의 프로그래밍 언어 연구결과의 집합체입니다.

Objective-C에서 차용한 named 파라미터는 명확한 문법으로 표현하되, 가독성과 유지보수를 쉽게합니다.

타입추론은 모듈이 헤더를 제거하고 네임스페이스를 제공하면서, 코드를 더 깔끔하게 하고, 그리고 실수를 덜 

유발하게 합니다. 메모리는 자동으로 관리되며, 세미콜론 조차 타이핑 할 필요 없습니다.

모든 이런 현대적인 아이디어들이 언어를 쉽고, 사용하기 재미있게 만들어줍니다. 



Swift는 코드를 더 풍부하게 하는 다른 많은 특징들을 가지고 있습니다. 

- 클로저는 함수 포인터와 통합되었습니다.

- 튜플과 다중 리턴값 

- 제네릭

- 빠르고 간결한 range와 collection iteration

- 메서드, extension, 프로토콜을 지원하는 구조체

- map, filter와 같은 함수형 프로그래밍 패턴

- try/catch/throw 를 사용하는 네이티브 에러처리 



 

   인터렉티브 플레이그라운드 (Interactive Playgrounds)

Playgrounds 는 Swift 코드 작성을 믿을수 없을 정도로 단순하고 재미있게 합니다. 

한 줄의 코드 타이핑 결과가 즉시 나타납니다. 코드 오른편에서 빠르게 결과를 훑어보거나, 

그 결과를 바로 아래에 고정할수 있습니다. 결과뷰는 그래픽, 결과리스트, 시간의 흐름에 따른 그래프로 

볼수 있습니다. Time Assistant를 열어 관련된 뷰들이 변화하고 애니메이션 되는것을 볼수 있습니다. 

새로운 UI코드를 실험하고, 코딩하면서 애니메이션 되는 SpriteKit Scene을 실행해보기 좋습니다. 

Playground에서 코드작성을 완료했을 때, 단순히 프로젝트로 코드를 옮기세요. 

Xcode7의 새로운 기능중 하나로  Playgrounds는 이탤릭 볼드, 불릿 리스트, 내장이미지와 링크 등을 가진 

rich text를 사용하여 주석을 달수 있습니다.  심지어 리소스도 내장할수 있어서 코드는 단순하게 하면서도 

Swift 소스 코드를 믿을수 없을 정도로 강력하고 매력적이게 할수 있습니다.


아름다운 텍스트와 인터렉티브한 코드를 사용하여 프로그래밍 커리큘럼을 공유할 수 있습니다.

새로운 알고리즘을 설계하고, 단계마다 그 결과를 볼수 있습니다.

테스트 슈트를 만들기 전에 새로운 테스트를 작성하고 동작하는지 검증할 수 있습니다.

Swift 코딩 기술을 연마하기 위해 새로운 API를 실험해볼 수 있습니다.

실험결과를 Playgrounds 안에서 동작하는 코드예제를 갖는 문서로 만들 수 있습니다.


Read-Eval-Print-Loop(REPL)

Xcode의 LLDB 디버깅 컨솔은 Swift 언어의 인터렉티브한 버전을 포함하고 있습니다.

스위프트 문법을, 실행되고 있는 앱과 상호작용하고 evaluate하는데 사용해보세요.

또 스크립트 같은 환경에서는 어떻게 동작하는지 새로운 코드를 작성해보세요.

Xcode 컨솔과 터미널에서 사용가능합니다.


안정성을 위한 설계(Designed for Safety)

Swift는  불안전한 코드들을 제거했습니다. 변수는 사용하기 전에 초기화 되어야 하고, 

배열과 정수타입은 오버플로그 검사를 하며 메모리는 자동으로 관리됩니다. 

문법은 의도를 잘 드러내도록 튜닝되었습니다.

예를 들어 단순하게 3문자 키워드를 사용하여 변수(var) , 상수(let)를 선언합니다. 

또 다른 사례로, 디폴트로 Swift 객체는 nil이 될 수 없습니다. 

Swift 컴파일러는  컴파일 타임 에러로 객체가 nil이 되는 것을 예방합니다. 

이것이 코드작성을 훨씬 명확하게 하고, 안전하게 합니다. 그리고 당신 앱의 수많은 종류의 

런타임 크래시들을 예방해줍니다. 그러나 nil이 유효하고 적절한 값일 경우가 있습니다. 

이런 상황에서는 optional이라고 알려진 혁신적인 특징을 사용합니다.

optional은 nil을 포함할 수 있으며, Swift 문법은 당신이 이해할 수 있고, 안전하게 처리할수 있도록

 ?구문을 사용하도록 강제합니다. 


빠르고 강력하다(Fast and Powerful)

초기 컨셉부터 Swift는 속도를 염두해두고 개발되었습니다. 고성능 LLVM 컴파일러를 사용하여, Swift 코드는 

대부분의 최신 하드웨어에 최적화된 네이티브 코드로 변환됩니다. 문법과 표준라이브러리는 코드가 가장 잘 실행되도록

튜닝되었습니다.

Swift는 C와 Objective-C 언어들을 계승합니다.  로우레벨 기본형 타입들과, 제어흐름, 연산자들을 포함하고 있습니다.

클래스, 프로토콜, 제네릭과 같은 객체지향 특징들은 Cocoa, Cocoa Touch 개발자들이 필요로 하는 성능과 힘을 제공합니다.


Objective-C 상호운영성 (Interoperability) 

Swift를 사용하여 전체 애플리케이션을 작성할 수 있습니다.

현재 앱의 새로운 기능 구현을 위해서 Swift코드를 사용할 수도 있습니다.

Swift 코드는 동일 프로젝트에 있는 Objective-C 파일들과  함께 존재하며, 전체 Objective-C API 에 접근하며 쉽게 적용할

수 있습니다.







'Swift' 카테고리의 다른 글

[swift] Map, Filter, Reduce  (0) 2015.06.22
[swift2] New in Swift2.0  (0) 2015.06.19
[swift] Apple Swift Blog  (0) 2015.06.10
[swift] Swift 기초 - 4  (0) 2014.10.29
[swift] Swift 기초 - 3  (1) 2014.10.29
[swift] Swift 기초 - 2  (0) 2014.10.29

[swift] Swift 기초 - 2

Swift 2014. 10. 29. 13:30



Swift 두 번째 스터디입니다. 

지난 시간에 학습한 내용을 정리해볼까요?





1. 변수 선언은 var 키워드를, 상수 선언은 let 키워드를 사용합니다.

2. Swift 컴파일러는 변수에 할당되는 값을 통해 타입을 추론합니다.

3. 유니코드에서 지원하는 다양한 문자를 변수 이름에 사용할 수 있습니다.

4. 문자열 타입 String, 문자 타입 Character를 지원합니다.

5. Array, Dictionary 컬렉션의 요소들은 동일한 타입이어야 합니다.

4. foreach 구문을 사용할 수 있고,  for-range 루프 문을 지원합니다.

5.  Switch-Case 문에 정수형 이외의 타입도 사용 가능합니다.

6. Swift의 모든 변수는 디폴트로 nil이 할당 될 수 없습니다.

7.  nil 이 될수 있는 변수는 ? 연산자를 붙혀 optional 타입으로 선언합니다.

8. optional 변수는 사용하기 전에 !연산자를 사용하여 unwrapping 해야 합니다.



이번 시간에는 함수,  클로져,  그리고 enum 타입에 대해 알아보겠습니다.




optional 에 대해 다시한번 정리하고 갈까요?

optional 타입은 런타임에 발생할 수 있는 nil 에러를  

컴파일 타임에 발견할 수 있도록 해줍니다.

보다 안전한 프로그램을 개발할 수 있도록  Swift 언어에서 제공하는 키워드이지요.






회사이름을 인자로 받아 주식코드를 반환하는 Objective-C 코드 예제입니다.

Facebook 에 대한 주식코드는 정의되지 않았기 때문에 마지막 라인의 코드에서

 text 문자열에 nil을 추가하려고 하여 런타임 에러가 발생하는 코드입니다.


문법적으로는 유효한 구문이기 때문에

이 에러는 실제 프로그램이 실행되기 전까지 문제를 알 수 없습니다. 헉!  



Swift에서는 optional 타입을 도입하여 이 문제를 멋지게 해결합니다.

nil이 될수 있는 변수는 optional 타입으로 선언하도록 강제한 것이지요. 

"optional 타입"은  " nil이 될수 있으니 주의깊게 다루세요" 라고 말하는 것과 같습니다.


위 Swift 코드에서는 컴파일러가 컴파일 타임에 에러를 알려 줍니다. 굿!




optional 타입을 사용하기 전에는 반드시 옵셔널 타입을 상쇄해야 하는데, unwrapping 한다고 표현합니다.

unwrapping 하는 방법은 if 문을 사용하여 nil 이 경우에, ! 연산자를 사용하여 optional을 상쇄합니다.

if 문을 사용하는 이유는,  nil 인 경우에 !연산자를 사용하면 런타임 에러가 발생하기 때문입니다.

nil이 아니라는 것을 보장하는 경우에 unwrapping해서 사용하라는 의미이지요. 


이 구문은 swift에서 관용구 처럼 사용되는데, optional binding이라하는 좀더 세련된 방법을 제공합니다.



정확히 이전 구문예제와 동일한 역할을 하는 optional binding 구문입니다.

! 연산자 대신에 let 상수 키워드를 사용하여 unwrapping하는 것이 유일한 차이입니다.

자주 사용하게 될 구문이니 꼭 기억하세요. 



함수 자체를 if 평가문에 사용하여 unwrapping 할수도 있습니다.



Swift에서는 func 키워드를 사용하여 함수를 정의합니다. 

함수의 파라미터에 디폴트 값을 지정 할 수 있습니다.  

buildGreeting()과 같이 인자없이 호출할 경우 name 파라미터에 "World" 문자열이 할당되어 사용됩니다.


튜플 타입을 지원합니다. 튜플은 쉽게 말하면 값의 묶음이라 할수 있습니다.

튜플은 선언과 동시에 상수가 되며, 값을 변경하려고 할 경우 컴파일 에러가 발생합니다.

튜플을 사용하면 한 번에 여러값을 전달하고, 반환할 수 있어서 편리합니다.




반환된 튜플을 어떻게 사용해야 할까요? 튜플 변수에 값을 할당하여 사용할 수 있습니다.




반환되는 튜플의 원소에 이름을 부여하여 사용할 수도 있습니다.



클로져는 쉽게 말해 실행가능한 코드블럭이라 할수 있습니다.  

함수도 코드 블럭이기 때문에 클로져로 사용할 수 있습니다.

이 클로져를 변수에 할당해 두고 필요한 때에 호출해서 사용할 수 있습니다.



클로져는 파라미터와 반환하는 값, 그리고 코드 블럭으로 구성됩니다.

greetingPrinter는 파라미터와 반환값 없이,  "Hello World!" 를 출력하는 클로져 입니다.



클로져의 재미있는 점은 함수의 인자 혹은 반환값으로 사용할 수 있다는 점입니다.

파라미터,반환값으로 정적인 데이터 뿐만이 아니라 동적인 행동(코드블럭)을 

전달하여, 다양한 조합으로 사용할 수 있습니다.


위 코드는 코드블럭을 특정 횟수만큼 반복하는 클로져의 예입니다.



클로져가 마지막 파라미터 인 경우 

위와 같이 함수의 꼬리에 클로져가 따라오는 형태로 사용할 수 있는데,

이런 형태를 Trailing 클로져라고 합니다. 



Swift의 enum은 연관된 값을 전달하여 사용할 수 있습니다. 

switch-case 문과 조합하여 유용하게 사용할 수 있는데, 자세한 설명은 나중으로 미루겠습니다.




Int 타입으로 정의한 Planet enum 변수를 println() 함수로 출력하면 

엉뚱하게도 Enum Value 라는 값이 출력됩니다. enum이 갖는 값이 아닌 enum 자체가 출력되는 것입니다.

enum 의 원소값을 출력하고 싶을 때는,  enum.toRaw() 멤버함수를 사용합니다.




enum 타입을 정수가 아닌 문자형으로 정의하여 원소값을 출력하는 예입니다.



나중에 클래스와 구조체에 대해 알아보겠지만

enum 도 초기화함수(생성자)와 멤버함수를 갖을 수 있습니다.



enum 을 생성하고 멤버함수를 호출하는 예입니다.






'Swift' 카테고리의 다른 글

[swift2] New in Swift2.0  (0) 2015.06.19
[swift] Apple Swift Blog  (0) 2015.06.10
[swift] Swift 기초 - 4  (0) 2014.10.29
[swift] Swift 기초 - 3  (1) 2014.10.29
[swift] Swift 기초 - 2  (0) 2014.10.29
[swift] Swift 기초 - 1  (1) 2014.10.29

[swift] Swift 기초 - 1

Swift 2014. 10. 29. 13:26





"Swift는 어떤 언어인가? 애플은 왜 Swift 언어를 만들었을까? "


"Objective-C 언어를 대체할 새로운 언어인가?  Objective-C 언어는 사라지는건가?"


"그렇게 되기까지 어느 정도의 시간이 걸릴 것인가?"



위 질문들에 답을 찾기 위해 시작한 스터디(총 4강)의 결과물을 공유합니다.



Swift는 iOS, OSX 개발을 위해 애플에서 발표한 

멀티 패러타임, 컴파일 프로그래밍 언어입니다.

2014 WWDC에서 처음 소개되었고, 코코아/코코아 터치,

Objective-C 코드와 호환되게 설계되었습니다.




2014 WWDC에서 크레이그 페더릭은 "Objective-C가 없는 C언어"라고 소개하였습니다.

C언어처럼  빠르면서 Objective-C 언어의 생산성과 강력함을 가진 언어!

애플 개발자 Swift 공식 사이트에서는 코드작성이 인터렉티브하고, 

재미있고, 혁명적인 새로운 프로그래밍 언어라고 소개합니다.



Swift 단어의 뜻을 아시나요? 

제비를 닮은 심볼은  해안과 산지의 바위절벽에 서식하며 

여름에 우리나라에 찾아온다는 "칼새"를 의미합니다.

"신속한","빠른" 이라는 뜻도 동시에 가지고 있지요

Swift의 심볼이 정말 칼새와 똑같이 생겼네요.






Swift는 현대 프로그래밍 언어의 장점을 두루 채용한 언어입니다.

주요 스펙은 기존의 서버사이드 병렬 스크립트 swift 언어에서 가져와, 

다른 특징들을 결합했다고 합니다.

Swift를 3단어로 표현하면 - SAFE! MORDERN! POWER!



 


2010년 애플 개발툴 부서 총책임자 "크리스 레트너"에 의해 

Swift 프로젝트가 시작되었습니다. 이후 많은 개발자들의 참여로 발전하게 되었고,  

오늘에 이르게 되었습니다. Swift의 아버지 = 크리스 레트너?






새롭게 소개된 Xcode6에는 Swift 코드를 인터랙티브하게 실험해볼 수 있는 

Playground 라는 템플릿을 포함하고 있습니다.

컨솔출력뿐만 아니라 UI 요소들 또한 바로 확인할 수 있으며

루프문의 값을 기억해 그래프로 그려주기까지 합니다. 

코드를 맘껏 가지고 놀 수 있는 놀이터 그 자체입니다.




이제부터 Swift의 문법에 대해서 알아보겠습니다. 



가장 기초가 되는 변수와 상수는 어떻게 선언할까요?

변수는 var, 상수는 let  키워드를 사용합니다. 

정수,실수,문자열,배열,사전,클래스 등 모든 타입들에 적용되는

일관되면서 심플한 규칙을 따릅니다.

(편리성을 위해 3문자 키워드로 맞추는 섬세함까지!)






Swift의 두드러진 특징 중의 하나로 타입추론을 꼽을 수 있습니다.

타입추론이란 할당되는 값(Value)을 통해 변수의 타입을 예측하는 것을 의미합니다.

똑똑한 컴파일러는 변수에 타입을 명시하지 않아도 할당되는 값을 보고 

이 변수가 "Int 혹은 String" 타입으로 예측하고 이후부터 해당타입으로 변수를 취급합니다.







Swift는 유니코드문자를 변수이름으로 사용할 수 있습니다. 

이모티콘으로도 변수이름을 지을 수 있으니 재미있을 따름입니다.




"" 쌍타옴표로 감싼 문자열을 String 타입으로 인식합니다. 

Objective-C와는 다르게 문자열을 표기하는데 @를 사용하지 않지요.







for-each 구문을 사용해서 문자열(String)을 

이루는 문자(Character)를 간편하게 순회할수 있습니다.





스터디를 진행했던 Xcode6 Beta 베타 버전에서는  

문자+문자, 문자열+문자 의 접합연산이 가능했는데,  

Swift1.0 정식버전에서는 불가능해졌습니다.

배열과 배열, 문자열과 문자열의 접합연산만이 가능다는 점! 주의하세요





포맷팅 문자열은 어떻게 만들까요? 

문자열 내부에 \(변수) 구문을 사용해서 원하는 값으로 치환이 가능합니다.






앞서 언급했던 Swift의 간결함 중 한 가지! 기억하나요?

var 키워드를 사용하면 수정 가능한 문자열.

let 키워드를 사용하면 수정 불가능한 문장열을 정의할 수 있습니다.






Array와 Dictionary에 대해서 알아볼까요?

Objective-C의 NSArray, NSDictionary와 대응하는 클래스로,  대괄호[]를 사용하여 선언합니다.

Array는 값의 순서리스트를, 

 Dictionary는 키:값 쌍으로 초기화 할 수 있습니다.







Objective-C에서는 NSObject를 상속하는 어떤클래스도 포함할 수 있었습니다.

반면 Swift에서는 Array는 동일한 타입의 값들만 포함할 수 있고, 

Dictionary는 문자열 키에 동일한 타입의 값들만 포함해야한다는 제약이 추가되었습니다.






 일반적인 while과 for 루프문을 사용할 수 있습니다.

루프 조건문에서는 ()를 사용할 수 있지만 일반적으로 사용하지 않는게 관례입니다.




Objective-C에서는 볼수 없었던 Range 루프문입니다. 

1...5는 1부터 5를 포함하여 5번의 루프를,

0..<5는 0부터 5를 포함하지 않고 5번의 루프를 반복합니다.

(마치 for 조건문에 i < 5와 i <= 5 를 사용하는 것처럼)






for-each 구문으로 Array를 순회할 수 있습니다.

Dictionary도 아직 배우지 않았지만 튜플을 사용하여 (키,값)쌍으로 순회할 수 있습니다.




Swift의 변수는 디폴트로 nil이 될수 없습니다. 

즉 선언과 동시에 반드시 초기화가 이루어져야 하지요.

null 과 같이 아직 값을 갖지 않는 변수가 필요할 때는 어떻할까요? 

그래서 필요한 것이 Optional 타입입니다. 변수의 타입 뒤에 ?를 붙여 옵셔널 타입으로 

선언하면, 변수는 nil (null)값을 가질 수 있습니다.  

"optional 타입" 의 자세한 내용은 다음 강의에서 설명하겠습니다.





Optional로 선언된 변수는 그냥 사용할 수 없습니다. 

컴파일 에러에서 벗어나기 위해 optional 타입을 벗겨야(unwrapping) 하는데요

위와 같은 구문을 사용해서 optional 타입을 unwrapping 할 수 있습니다.

"possibleLegCount가 nil 아니면 그 값을 상수 letCount에 할당하고 if 문으로.." 

처럼 해석할 수 있습니다. 역시 자세한 설명은 다음 강의에서.




switch 구문입니다. Objective-C와 다른 점을 눈치 채셨나요?

그렇습니다. case 조건안에 ,를 구분으로 여러 값을 명시할 수 있습니다. 

또 switch 문에 정수형 외에 다른 타입들도 사용이 가능합니다.


1강 끝~~ 이라고 하기엔 아직 이릅니다. 아래를 보세요.




2014 WWDC 가 진행되면서 앱스토어에 

WWDC 세션을 소개하고 안내하는 Swift 최초의 공식앱이 올라왔습니다. 



iOS8과 요세미티를 deployment target으로 한 앱은 미래에도 정상작동을 보장합니다.

사실 메버릭스와 iOS7을 타겟으로 해도 동작하는데 그 이유는 

앱 번들 안에 경량의 swift 런타임을 포함하기 때문이라고 합니다.

Swift 스펙이 안정화될 즈음에 런타임이 제거될거라 합니다.


바이너리 호환성은 보장되지 않는다고 하니, 앱의 모든 컴포넌트들은 

동일한 버전의 Xcode와  Swift 컴파일러를 사용해서 빌드되야 합니다.


Swift의 스펙은 아직도 핫하게 변경되고 있어서 소스코드 수준의 호환성을 

보장하지 않습니다. Xcode에서 마이그레이션 할 수 있는 수단을 제공할 계획이라고 합니다.



호환성 문제가 있긴 하지만, Swift가 기존 플랫폼에서도 실행가능한 이유는 

Objective-C와 동일한 런타임을 사용하기 때문이라고 하네요

단일 프로그램에서 함께 복합해서 사용할 수도 있구요

브리징 헤더를 제공하면 Objective-C로 작성된 코드를 Swift에서도 손쉽게 사용할 수 있습니다. 





Optional 타입은 왜 필요한가? 에 대한 의문이 생깁니다. 

컴파일 타입에 확정된 값을 갖지 않는 변수에 사용한다면, 

대다수의 변수들이 optional로 선언되어야 할텐데, 왜 굳이 옵셔널 타입이 필요한 걸까요??

자세한 내용은 다음 강의에서!




 위 구문은 어떤 결과를 갖을까요?

첫번째 구문은 nil 값을 갖는 상수입니다.

상수이기 떼문에 당연히 값을 변경하고자 하면 에러가 발생하겠지요


아래 구문은 옵셔널 타입이 아니기 때문에 nil을 할당할 수 없습니다.









'Swift' 카테고리의 다른 글

[swift2] New in Swift2.0  (0) 2015.06.19
[swift] Apple Swift Blog  (0) 2015.06.10
[swift] Swift 기초 - 4  (0) 2014.10.29
[swift] Swift 기초 - 3  (1) 2014.10.29
[swift] Swift 기초 - 2  (0) 2014.10.29
[swift] Swift 기초 - 1  (1) 2014.10.29