logo

English

이곳의 프로그래밍관련 정보와 소스는 마음대로 활용하셔도 좋습니다. 다만 쓰시기 전에 통보 정도는 해주시는 것이 예의 일것 같습니다. 질문이나 오류 수정은 siseong@gmail.com 으로 주세요. 감사합니다.

[swift 4] 변경 사항 정리

by 엉뚱도마뱀 posted Jul 23, 2018
?

Shortcut

PrevPrev Article

NextNext Article

Larger Font Smaller Font Up Down Go comment Print Attachment
?

Shortcut

PrevPrev Article

NextNext Article

Larger Font Smaller Font Up Down Go comment Print Attachment

 

 

스위프트가 4번째 버전이 나왔습니다. 하지만 문법적으로 변경되는 부분이 크게 많지 않아서 서 3 버전과 크게 달라진 문법은 많지 않습니다.

내부적으로 수정되거나 추가된 문법이 많고, 삭제된 부분은 거의 없으니까요.

 

달라진 문법을 살펴보겠습니다.

 

 

 

방향산자

위연산자에서 경쓸 요가 습니다.

 

 

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

// Swift 3

numbers[2..<numbers.endIndex] // [3, 4, 5]

numbers[0...2] // [1, 2, 3]

numbers[0..<2] // [1, 2]

// Swift 4

numbers[2...] // [3, 4, 5]

numbers[...2] // [1, 2, 3]

numbers[..<2] // [1, 2]

numbers = []

// Swift 3

//numbers[0...numbers.endIndex] // out of range - error

// Swift 4

numbers[0...] // []

let number: Int = 100

// Swift 3

switch number {

case Int.min..<0:

    print("negative")

case 0:

    print("zero")

case 1...Int.max:

    print("positive")

default:

    print("unknwon")

}

// Swift 4

switch number {

case ..<0:

    print("negative")

case 0:

    print("zero")

case 1...:

    print("positive")

default:

    print("unknwon")

}

 

 

 

String의

Swift 4 String은 화가 나입니다. 그 중 만한 용을 주로 리했습니다. 더 많은 사항은 [String Processing For Swift 4] 문서를 참고해보시기 바랍니다.

 

 

String 구조체가 다시 Collection 프로토콜을 따릅니다. [SE-0163]

 

var greeting: String = "Hello, Swift!"

// Swift 3

greeting.characters.forEach { print($0) }

print(greeting.characters.count) // 13

// Swift 4

greeting.forEach { print($0) }

print(greeting.count) // 13

 

 

Unicode 9적용되었습니다. [String Processing For Swift 4 - Unicode 9 Conformance]

이전에 문자열 길이 결과가 제각각이었던 유니코드 문자들이 사람이 인지할 수 있는 단위로 세어집니다.

 

스크린샷 2018-07-23 오후 5.26.04.png

 

여러 줄 리터럴 문법이 생겼습니다. [SE-0168]

큰따옴표 세 개를 연결하여 표현하면 여러 줄 문자열을 표현하는 리터럴 문법입니다.

반드시 """ 다음 줄부터 문자열을 입력해야하며, 문자열 마지막 줄 다음줄에 """로 닫아줘야 합니다.

 

// Swift 3

greeting = "Hello\nHow are you?\nI'm fine thanks, and you?"

// Swift 4

greeting = """

Hello

How are you?

I'm fine thanks, and you?

"""

 

 

Substring 타입과 StringProtocol 프로토콜이 생겼습니다.

기존에 String 타입에 구현되어있던 주요 기능을 StringProtocol에 기본구현 하였습니다.

 

 

let subIndex = greeting.index(greeting.startIndex, offsetBy: 4)

// Swift 3

let subGreeting = greeting[greeting.startIndex...subIndex]

print(type(of: subGreeting)) // String

// Swift 4

let subGreeting = greeting[...subIndex]

print(type(of: subGreeting)) // Substring

let stringFromSubstring: String = String(subGreeting)

 

 

Character입에 unicodeScalars 로퍼티가 추가되었습니다. [SE-0178]

Swift 3서는 Character 인스턴스의 유니코드 스칼라 값을 알아내려면 String 타입으로 변환하여야 했지만, 이제는 바로 Character 인스턴스의 unicodeScalars 프로퍼티를 이용해 알아낼 수 있습니다.

 

 

let character: Character = ""

// Swift 3

print(String(character).unicodeScalars)

// Swift 4

print(character.unicodeScalars)

 

 

Dictionary와 Set

용하는 렉션 입인 Dictionary와 Set의 능이 층 강화되었습니다.

 

[SE-0154], [SE-0165]

 

 

 

키와 값의 시퀀스를 통해 새로운 딕셔너리를 생성할 수 있습니다. 또, 키와 값을 기존의 딕셔너리에 병합할 수 있습니다.

 

let zipSequence = zip("abcdefghijklmnopqrstuvwxyz", 97...)

let asciiTable = Dictionary(uniqueKeysWithValues: zipSequence)

// ["w": 119, "n": 110, "u": 117, "v": 118, "x": 120, "q": 113, ...]

let vegetables = ["tomato", "carrot", "onion", "onion", "carrot", "onion"]

let vegetableZipSequence = zip(vegetables, repeatElement(1, count: Int.max))

var vegetableCounts = Dictionary(vegetableZipSequence, uniquingKeysWith: +)

vegetableCounts.merge([("tomato", 1)], uniquingKeysWith: +)

// ["tomato": 2, "carrot": 2, "onion": 3]

 

 

Dictionary와 Set의 filter 과가 Array대신 각의 입으로 환됩니다., 딕셔너리는 mapValues(_:) 메서드를 통해 값이 변형된 새로운 딕셔너리를 만들 수 있습니다.

 

let vowels: Set<Character> = ["a", "e", "i", "o", "u"]

let asciiVowels = asciiTable.filter({ vowels.contains($0.key) })

// Swift 3

print(type(of: asciiVowels)) // Array<(key : Character, value : Int)>

// Swift 4

print(type(of: asciiVowels)) // Dictionary<Character, Int>

asciiVowels["a"]  // 97

asciiVowels["b"]  // nil

let filteredSet: Set<Character> = vowels.filter{ $0 < "h" }

// Swift 3

print(type(of: filteredSet)) // Array<Character>

// Swift 4

print(type(of: filteredSet)) // Set<Character>

// Swift 3

let strangeMap = asciiTable.map { [$0: "0x" + String($1, radix: 16)] }

print(type(of: strangeMap)) // Array<Dictionary<Character, String>>

// [["u": "0x75"], ["v": "0x76"], ["w": "0x77"], ["x": "0x78"], ["q": "0x71"], ["n": "0x6e"], ...]

// Swift 4

let asciiHexTable = asciiTable.mapValues({ "0x" + String($0, radix: 16) })

// ["w": "0x77", "n": "0x6e", "u": "0x75", "v": "0x76", "x": "0x78", ...]

 

 

셔너리브스크립트 법이 가되었습니다. 원하는 당하는 으면 nil 본값을 돌려줍니다.

본값이 다는 은 값이 재한다는 미이므로, 해당 서브스크립트의 반환값은 옵셔널이 아닌 값이라는 뜻입니다. 딕셔너리 옵셔널 전쟁에서 해방될 수도!

 

 

let favoriteSubject: [String: String] = ["yagom": "swift", "hana": "communication", "jisu": "swift"]

// Swift 3

type(of: favoriteSubject["minji"]) // Optional<String>

// Swift 4

type(of: favoriteSubject["minji"]) // Optional<String>

type(of: favoriteSubject["minji", default: "unknown"]) // String

var favoriteCount = [String: Int]()

favoriteSubject.forEach { favoriteCount[$0.value, default: 0] += 1 }

print(favoriteCount) // ["swift": 2, "communication": 1]

 

 

init(grouping:by:)니셜라이저를 건에 Array 퀀스를 셔너리 태로 룹지을 습니다. 그룹 준값은 셔너리의 가 됩니다.

 

struct Person: CustomStringConvertible {

    enum Gender {

        case male, female, unknwon

    }

    

    let name: String

    var gender: Gender

    

    var description: String { return name }

}

let yagom = Person(name: "yagom", gender: .male)

let hana = Person(name: "hana", gender: .female)

let jisu = Person(name: "jisu", gender: .unknwon)

let eric = Person(name: "eric", gender: .male)

let mike = Person(name: "mike", gender: .male)

let friends = [yagom, hana, jisu, eric, mike]

let friendsByGender = Dictionary(grouping: friends, by: { $0.gender })

print(type(of: friendsByGender))    // Dictionary<Gender, Array<Person>>

print(friendsByGender)

// [Person.Gender.unknwon: [jisu], Person.Gender.male: [yagom, eric, mike], Person.Gender.female: [hana]]

 

 

reserveCapacity(_:)서드를 Array 약된 간을 있습니다.

 

var emptyDictionary = [String: String]()

print(emptyDictionary.capacity) // 0

emptyDictionary.reserveCapacity(100)

print(emptyDictionary.capacity) // 192

// 최소 100개의 요소가 들어갈 수 있도록 공간을 확보하기 때문에 꼭 100이지 않을 수 있습니다

emptyDictionary.reserveCapacity(10)

print(emptyDictionary.capacity) // 192

emptyDictionary.reserveCapacity(1000)

print(emptyDictionary.capacity) // 1536

 

 

Key path

Cocoa에서 순한 자열로 현하던 key path를 위프트에서는 확한 입(KeyPath 는 제네릭 클래스) 식으로 현합니다. 조금 전한 로그래밍을 을까 기대됩니다. [SE-0161]

 

key path를 통하여 프로퍼티에 접근할 수 있도록 모든 타입에 자동으로 [keyPath:] 서브스크립트 메서드가 추가됩니다.

key path는 백슬래시(\)를 통해 표현합니다.

 

struct Person {

    var name: String

}

struct Stuff {

    var name: String

    var owner: Person

}

var yagom = Person(name: "yagom")

let macbook = Stuff(name: "macbook pro", owner: yagom)

print(type(of: \Person.name)) // WritableKeyPath<Person, String>

var result: Any = macbook[keyPath: \Stuff.name]

print(result) // macbook pro

let keyPath = \Stuff.owner

let nameKeyPath = keyPath.appending(path: \.name)

result = macbook[keyPath: nameKeyPath]

print(result) // yagom

result = macbook[keyPath: \Stuff.owner.name]

print(result) // yagom

 

 

로토콜

Objective-C 래스와 로토콜을 시에 르고 입이라는 미로 용되었던 현이 있습니다.

 

 

SomeClass<SomeProtocol, AnotherProtocol> *name

// SomeProtocol과 AnotherProtocol을 준수하는 SomeClass 타입의 변수 name

이 표현이 이제 스위프트에서도 가능해졌습니다. [SE-0156]

 

 

class ClassA { }

class ClassB: ClassA { }

protocol ProtocolA { }

extension ClassB: ProtocolA { }

var someVariable: ClassA & ProtocolA

// someVariable = ClassA()

// 오류발생 : ProtocolA를 충족하지 않음

someVariable = ClassB() // 모든 조건 충족

 

 

where 확장

프로토콜과 그 연관 타입에 where 절을 사용하여 타입 제약을 줄 수 있습니다. [SE-0142]

 

 

protocol StringRepresentable: RawRepresentable

where RawValue == String { }

protocol RawStringWrapper {

    associatedtype Wrapped: RawRepresentable

    where Wrapper.RawValue == String

}

 

 

 

 

네릭브스크립트

브스크립트가 제 제네릭 개변수와 입을 용할 게 되었습니다. [SE-0148]

 

 

struct CustomModel<Key: Hashable, Value> {

    var dictionary: [Key: Value]

    

    subscript<T>(key: Key) -> T? {

        return dictionary[key] as? T

    }

}

let information = CustomModel(dictionary: ["name": "yagom", "age": 100, "height": 183.0])

let name: String? = information["name"] // yagom

 

 

Private근수준의

존의 private 근수준은 같은 파일인 여부와 상관없이 private 요소를 해당 범위를 벗어나면 사용할 수 없었습니다. 대체제로 fileprivate를 사용하였는데, 이는 문제를 야기할 수 있는 가능성을 가지고 있습니다. 같은 파일이라도 접근을 원치 않는 요소가 있는데, extension 으로 입을 확장하여 요소를 사용려면 fileprivate로 지정해 주어야 하는 문제가 있었기 때문이죠. 아래 Swift 3 예를 먼저 보겠습니다.

 

 

// Swift 3

struct Person {

    var name: String

    // private로 지정하면 extension에서 접근할 수 없기 때문에 fileprivate로 선언

    fileprivate var age: Int = 0

    init(name: String) {

        self.name = name

    }

}

extension Person {

    mutating func passedYear() {

        self.age += 1

    }

}

var yagom = Person(name: "yagom")

yagom.passedYear()

yagom.age // 접근가능! 원하던 시나리오가 아님!

 

 

이라는감한 분은 기고 었기 문에 private로, 어디서든 접근을 막고 싶었지만, 같은 파일의 익스텐션에서 조차 접근할 수 없기 때문에 fileprivate로 접근수준을 지정했습니다. 그 결과, 엉뚱하게 같은 파일의 다른 소스에서도 접근할 수 있게 되었습니다.

 

 

// Swift 4

struct Person {

    var name: String

    private var age: Int = 0

    init(name: String) {

        self.name = name

    }

}

extension Person {

    mutating func passedYear() {

        // private라도 같은 파일의 extension에서 접근 가능

        self.age += 1

    }

}

var yagom = Person(name: "yagom")

yagom.passedYear()

// yagom.age // 접근불가

Swift 4서는 제를 선하여 일의 스텐션에서는 근할 도록 변경되었습니다.

 

 

 

카이브와리얼라이제이션 / JSON 코딩

NSCoding과 NSObject를 쉽게 용할 래스 입을 외하고, 구조체나 열거타입에서는 아카이빙이 참으로 난해했습니다. 물론 NSObject를 상속받지 않는 스위프트 고유 클래스도 마찬가지였습니다. 그러나 이제 타입이 스스로 어떻게 아카이브하고 시리얼라이즈 할지 정의할 수 있게 되었습니다. 그저 타입과 그 타입의 하위 타입이 모두 Codable 프로토콜을 준수하면 아카이브하고 그것을 풀어낼 수 있도록 할 수 있습니다. 기존에 사용하던 NSKeyedArchiver 클래스도 Codable 프로토콜을 완벽히 지원합니다. Codable과 함께 JSONEncoder, JSONDecoder로 인해 JSON 인코딩과 디코딩이 엄청나게 편해졌습니다!! 으아아아아아아아~!! [SE-0166],  [SE-0167]

 

 

struct Person: Codable {

    enum Gender: String, Codable {

        case male, female, unknown

    }

    

    var name: String

    var age: Int

    var gender: Gender

    var friends: [Person]

}

let yagom = Person(name: "yagom", age: 20, gender: .male, friends: [])

let hana = Person(name: "hana", age: 22, gender: .female, friends: [yagom])

let eric = Person(name: "eric", age: 25, gender: .male, friends: [yagom, hana])

var encoder = JSONEncoder()

let jsonData = try encoder.encode(eric)

let jsonString = String(data: jsonData, encoding: .utf8)

print(jsonString)

// "{\"age\":25,\"gender\":\"male\",\"friends\":[{\"age\":20,\"gender\":\"male\",\"friends\":[],\"name\":\"yagom\"},{\"age\":22,\"gender\":\"female\",\"friends\":[{\"age\":20,\"gender\":\"male\",\"friends\":[],\"name\":\"yagom\"}],\"name\":\"hana\"}],\"name\":\"eric\"}"

let decoder = JSONDecoder()

let decoded: Person = try decoder.decode(Person.self, from: jsonData)

print(decoded.name) // eric

 

 

NSNumber릿징

상치 과를 는 NSNumber 브릿징 과가 수정되었습니다.

 

 

// Swift 3

let numberOne = NSNumber(value: Int64.max)

if numberOne is Int16 {

    print("numberOne == Int16")

} else if numberOne is Int64 {

    print("numberOne == Int64")

} // numberOne == Int16

let numberTwo = NSNumber(value: UInt32(777))

if let value = numberTwo as? Int8 {

    print(value)

} // 9

// Swift 4

let numberOne = NSNumber(value: Int64.max)

if numberOne is Int16 {

    print("numberOne == Int16")

} else if numberOne is Int64 {

    print("numberOne == Int64")

} // numberOne == Int64

let numberTwo = NSNumber(value: UInt32(777))

if let value = numberTwo as? Int8 {

    print(value)

} // 아무 출력 없음

 

 

그외 기타 변경 사항

 

    * Core Foundation 입들은 Hashable과 Equatable 로토콜을 CFHash와 CFEqual 수구현을 수합니다. Swift 3 드(Swift 3.2 버전)서도 용되는 사항입니다. [SR-2388]

 

* 암시적인 @objc 선언을 이제 더욱 명확히 표현해 주어야 합니다. [SE-0160]

 

* raw buffer를 슬라이스 한 결과는 더이상 같은 타입으로 반환되지 않습니다. [SE-0138]

 

* 재정의(override)가 더 완벽하게 지원됩니다. [SR-1529]

 

* 제네릭 매개변수를 갖는 서브스크립트를 정의할 수 있습니다. [SE-0148]

 

* 스위프트 타입 시스템이 이제는 하나의 튜플 전달인자를 가지는 함수와 여러 매개변수를 가지는 함수를 구분합니다. [SE-0110]

 

* 여러 연산자를 수반한 정수형 상수를 정의하는 C 언어의 매크로의 형태를 더 다양하게 임포트 할 수 있습니다.

 

* inout 매개변수를 사용하는 reduce 함수가 추가되었습니다. [SE-0171]

 

* 컬렉션 타입의 두 요소를 서로 바꿔주는 swapAt(_:_:) 메서드가 추가됐습니다. [SE-0173], [SE-0176]

 

 

 

TAG •

List of Articles
No. Subject Author Date Views
55 macOS Daemon 관련 시스템 폴더 목록 lizard2019 2024.03.08 3
54 Firebase 'GoogleUtilities/GULURLSessionDataResponse.h' file not found Error Fix lizard2019 2023.07.04 175
53 [macOS] Xcode 디버깅 시 Could not attach pid 오류 해결 file lizard2019 2023.06.05 473
52 [macOS, iOS] 개발자 정보 확인하는 명령어 digipine 2023.03.23 147
51 [macOS] 현재 사용 중인(열려있는) 포트 확인하고 Close 하기 digipine 2022.10.24 254
50 [iOS] Audio Session Setting digipine 2021.11.26 546
49 [iOS] 개발자를 위한 iOS 15의 새로운 기능 file digipine 2021.11.04 492
48 [iOS/macOS] 사설 인증서를 사용한 SSL HTTPS 통신 시 우회처리 digipine 2021.07.06 2943
47 [MacOS] Terminal 에서 zsh compinit: insecure directories 경고 제거하기 lizard2019 2021.04.30 564
46 Concurrent vs Serial DispatchQueue: Concurrency in Swift explained lizard2019 2021.04.16 414
45 WatermelonDB 'jsi/jsi.h' file not found 문제 해결 file digipine 2021.04.06 730
44 [iOS/Objective-C] __weak, __block 사용법 digipine 2021.02.16 5493
43 macOS ARP Spoofing Attack file digipine 2020.09.17 684
42 The distance estimate iBeacon signal strength lizard2019 2019.10.25 693
41 [MacOS, Swift] 스크롤뷰, NSScrollView 사용법 엉뚱도마뱀 2018.11.01 1264
40 [swfit 4] 스위프트 Swift 동시성 동기화 정리 엉뚱도마뱀 2018.09.06 1313
» [swift 4] 변경 사항 정리 file 엉뚱도마뱀 2018.07.23 1019
38 [Objective-C] NSOperation과 NSOperationQueue를 사용하는 방법 - 설명 및 예제 엉뚱도마뱀 2018.03.14 4185
37 MacOS mysql 비밀번호 분실 시 재설정하기 digipine 2017.11.14 1028
36 OSX - Screen Serial Terminal - OSX에서 시리얼 터미널 사용하기 digipine 2017.11.03 6836
Board Pagination Prev 1 2 3 Next
/ 3