[최종 수정일 : 2018.04.03]

원문 : https://www.raywenderlich.com/187826/whats-new-in-swift-4-1

What’s New in Swift 4.1?


Xcode 9.3과 Swift 4.1은 드디어 베타를 벗어났습니다! 이번 릴리즈에는 표준 라이브러리와 언어 자체에 대해 오랫동안 기다렸던 개선 사항이 포함되어 있습니다. Swift 진화 과정(Swift Evolution Process)을 열심히 따라오지 않았다면, 계속 읽으세요.

이 튜토리얼에서, 여러분은 Swift 4.1에서 소개된 가장 중요한 변화에 대해서 배우게 될 것입니다.

이 글은 Xcode 9.3이 필요하며, 시작하기 전에 설치하고 준비가 되었는지 확인합니다.

시작하기(Getting Started)

Swift 4.1은 Swift 4와 소스 호환되며, 이미 Xcode에서 Swift Migrator를 사용해서 프로젝트를 Swift 4로 마이그레이션 한 경우에, 여러분의 코드는 새로운 기능에 영향받지 않습니다.

아래 섹션에서, [SE-0001]처럼 연결된 태그가 표시될 것입니다. 각 제안에 대한 링크를 포함시켰으므로 각각의 특정 변화에 대해 전체 세부사항을 파헤칠수 있습니다. playground에서 기능을 시험해 보는 것을 권장하며 작업하면서 변경되는 것을 더 잘 이해할 수 있습니다.

시작하려면, Xcode 9.3을 열고 File > New > Playground를 선택합니다. 플랫폼(platform)을 iOS로 고르고 템플릿(template)은 Blank를 선택합니다. 이름을 원하는 데로 지정하고 저장합니다. 이 튜토리얼을 최대한으로 활용하려면, 작업하면서 새로운 playground에서 각 기능을 시험해 보세요.

주의
Swift 4 의 주요내용을 봐야하나요? 문제 없습니다! 이 튜토리얼의 이전 버젼을 확인하세요

Swift 4: Swift 4에서 무엇이 새로워 줬나(What’s New in Swift 4)

언어 개선(Language Improvements)

이번 릴리즈에는 조건부 적합성(conditional conformance), 프로토콜에서 관련 타입에 대한 제귀적 제약 등, 여러가지 언어적 개선을 포함하였습니다.

조건부 적합성(conditional conformance)

SE-0143 타입 인자가 특정 조건을 만족하는 곳에서, 조건부 적합성(conditional conformance)으로 제네릭 타입에 대해 프로토콜 적합성(protocol conformance)이 가능합니다. 이는 코드의 유연성을 높여주는 강력한 기능입니다.

표준 라이브러리에서의 조건부 적합성(conditional conformance)

Swift 4에서는, 그 요소들이 Equatable이면 배열과 딕셔너리, 옵셔널을 비교할수 있습니다. 몇가지 예제를 통해 동작하는 방법을 확인할 수 있습니다.

// Arrays of Int
let firstArray = [1, 2, 3]
let secondArray = [1, 2, 3]
let sameArray = firstArray == secondArray

// Dictionaries with Int values
let firstDictionary = ["Cosmin": 10, "George": 9]
let secondDictionary = ["Cosmin": 10, "George": 9]
let sameDictionary = firstDictionary == secondDictionary

// Comparing Int?
let firstOptional = firstDictionary["Cosmin"]
let secondOptional = secondDictionary["Cosmin"]
let sameOptional = firstOptional == secondOptional

Swift 4에서 Int가 Equatable이므로 이 예제에서 동등성(equality)을 테스트 하기 위해 == 연산자를 사용합니다. 
그러나, Swift 4에서 옵셔널은 Equatable을 준수하지 않기에, 콜렉션 옵셔널(collections of optionals)을 비교하는 일반적인 상황이었습니다. Swift 4.1은 조건 적합성을 사용하여 이 문제를 해결하며, 비교할 Equatable타입을 가지는 옵셔널 타입을 허용합니다.

// Array of Int?
let firstArray = [1, nil, 2, nil, 3, nil]
let secondArray = [1, nil, 2, nil, 3, nil]
let sameArray = firstArray == secondArray

// Dictionary with Int? values
let firstDictionary = ["Cosmin": 10, "George": nil]
let secondDictionary = ["Cosmin": 10, "George": nil]
let sameDictionary = firstDictionary == secondDictionary

// Comparing Int?? (Optional of Optional)
let firstOptional = firstDictionary["Cosmin"]
let secondOptional = secondDictionary["Cosmin"]
let sameOptional = firstOptional == secondOptional

Swift 4.1에서 Int?는 Equatable이며, ==연산자는 [Int?][String: Int?]과 Int??에 대해 동작합니다.

배열의 배열([[Int]])을 비교할때 비슷한 문제 해결되었습니다. Swift 4에서, 세트가 Equatable을 준수하므로, 집합의 배열([Set<Int>])만 비교할수 있습니다. Swift 4.1 이것을 해결하며, 배열(과 딕셔너리)는 값이 있는한 Equtable입니다.

let firstArrayOfSets = [Set([1, 2, 3]), Set([1, 2, 3])]
let secondArrayOfSets = [Set([1, 2, 3]), Set([1, 2, 3])]

// Will work in Swift 4 and Swift 4.1
// since Set<Int> is Equatable
firstArrayOfSets == secondArrayOfSets

let firstArrayOfArrays = [[1, 2, 3], [3, 4, 5]]
let secondArrayOfArrays = [[1, 2, 3], [3, 4, 5]]

// Caused an error in Swift 4, but works in Swift 4.1
// since Arrays are Equatable in Swift 4.1
firstArrayOfArrays == secondArrayOfArrays

일반적으로, Swift 4.1의 Optional, Array, Dictionary는 기본 값 또는 요소가 이런 프로토콜을 준수할때마다Equatable과 Hashable를 준수합니다.

이것은 표준 라이브러리에서 조건부 적합성이 동작하는 방법입니다. 이제, 여러분의 코드로 그것을 구현할 것입니다.

코드에서 조건부 적합성(Conditional conformance in code)

자신의 뮤지컬 밴드를 만들기 위해 조건부 적합성을 사용할 것입니다. 시작하려면 플레이그라운드 하단에 다음 코드 블록을 추가하세요.

// 1 
class LeadInstrument: Equatable {
  let brand: String
  
  init(brand: String) {
    self.brand = brand
  }
  
  func tune() -> String {
    return "Standard tuning."
  }
  
  static func ==(lhs: LeadInstrument, rhs: LeadInstrument) -> Bool {
    return lhs.brand == rhs.brand
  }
}

// 2
class Keyboard: LeadInstrument {
  override func tune() -> String {
    return "Keyboard standard tuning."
  }
}

// 3
class Guitar: LeadInstrument {
  override func tune() -> String {
    return "Guitar standard tuning."
  }
}

이것은 단계별로 수행됩니다.

  1. LeadInstrument은 Equatable을 준수합니다. 그것은 특정 브랜드(brand)와 악기를 튜닝하는데 사용할 수 있는 tune()메소드 이름을 가지고 있습니다.

  2. 키보드 표준 튜닝을 반환하기 위해 keyboard에서 tune()를 재정의합니다.

  3. Guitar에 대해서도 같은 일을 합니다.

다음으로, 악기의 밴드를 선언합니다.

// 1  
class Band<LeadInstrument> {
  let name: String
  let lead: LeadInstrument
  
  init(name: String, lead: LeadInstrument) {
    self.name = name
    self.lead = lead
  }
}

// 2
extension Band: Equatable where LeadInstrument: Equatable {
  static func ==(lhs: Band<LeadInstrument>, rhs: Band<LeadInstrument>) -> Bool {
    return lhs.name == rhs.name && lhs.lead == rhs.lead
  }
}

이것은 단계별로 수행합니다.

  1. 제네릭 타입으로 Band라는 클래스를 만듭니다 - LeadInstrument. 각 밴드에는 고유한 이름(name)과 리드 악기(lead instrument)를 가지고 있습니다.
  2. LeadInstrument가 수행하는 동안 Band가 Equatable를 준수하기 위해 where를 사용합니다. Band의 제네릭 LeadInstrument이 Equatable를 준수하는 능력이 바로 조건부 적합성이 작용하는 정확한 이유입니다.

다음으로, 여러분이 좋아하는 밴드를 정의하고 비교하세요.

// 1
let rolandKeyboard = Keyboard(brand: "Roland")
let rolandBand = Band(name: "Keys", lead: rolandKeyboard)
let yamahaKeyboard = Keyboard(brand: "Yamaha")
let yamahaBand = Band(name: "Keys", lead: yamahaKeyboard)
let sameBand = rolandBand == yamahaBand

// 2
let fenderGuitar = Guitar(brand: "Fender")
let fenderBand = Band(name: "Strings", lead: fenderGuitar)
let ibanezGuitar = Guitar(brand: "Ibanez")
let ibanezBand = Band(name: "Strings", lead: ibanezGuitar)
let sameBands = fenderBand == ibanezBand

이 코드의 일부에서, 적절한 Bands로 두개의 keyboard와 Guitars를 만듭니다. 그리고 나서 앞에서 정의한 조건부 적합성 덕분에, bands를 직접 비교할 수 있습니다.

JSON 파싱에서 조건부 적합성(Conditional conformance in JSON parsing)

배열(arrays), 딕셔너리(dictionaries), 세트(sets)와 옵셔널은 Swift 4.1 에서 그 요소들이 Codable을 준수하는 경우Codable을 준수합니다. 이를 시도하기 위해 플레이그라운드(playground)에 다음 코드를 추가하세요.

struct Student: Codable, Hashable {
  let firstName: String
  let averageGrade: Int
}

let cosmin = Student(firstName: "Cosmin", averageGrade: 10)
let george = Student(firstName: "George", averageGrade: 9)
let encoder = JSONEncoder()

// Encode an Array of students
let students = [cosmin, george]
do {
  try encoder.encode(students)
} catch {
  print("Failed encoding students array: \(error)")
}

// Encode a Dictionary with student values
let studentsDictionary = ["Cosmin": cosmin, "George": george]
do {
  try encoder.encode(studentsDictionary)
} catch {
  print("Failed encoding students dictionary: \(error)")
}

// Encode a Set of students
let studentsSet: Set = [cosmin, george]
do {
  try encoder.encode(studentsSet)
} catch {
  print("Failed encoding students set: \(error)")
}

// Encode an Optional Student
let optionalStudent: Student? = cosmin
do {
  try encoder.encode(optionalStudent)
} catch {
  print("Failed encoding optional student: \(error)")
}

[Student], [StringL Student], Set<Student>, Student?인코딩하기 위해 코드를 사용합니다. Swift 4.1에서 Student가 Codable이므로, 원할하게 동작하며, 이러한 콜렉션 타입도 준수합니다.

JSON 인코딩하는 동안 Camel Case와 Snake Case 간의 변환(Convert Between Camel Case and Snake Case During JSON Encoding)

Swift 4.1 JSON 인코딩하는 동안 CamelCase 프로퍼티를 snake_case 키로 변환할 수 있습니다.

var jsonData = Data()
encoder.keyEncodingStrategy = .convertToSnakeCase
encoder.outputFormatting = .prettyPrinted

do {
  jsonData = try encoder.encode(students)
} catch {
  print(error)
}

if let jsonString = String(data: jsonData, encoding: .utf8) {
  print(jsonString)
}

인코더를 만들때, keyEncodingStrategy를 .converToSnakeCase로 설정합니다. 콘솔을 보면, 다음과 같이 보입니다.

[
  {
    "first_name" : "Cosmin",
    "average_grade" : 10
  },
  {
    "first_name" : "George",
    "average_grade" : 9
  }
]

JSON 디코딩중에 snake case keys에서 snake case 프로퍼티로 돌아갈 수 있습니다.

var studentsInfo: [Student] = []
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase

do {
  studentsInfo = try decoder.decode([Student].self, from: jsonData)
} catch {
  print(error)
}

for studentInfo in studentsInfo {
  print("\(studentInfo.firstName) \(studentInfo.averageGrade)")
} 

이번에는, keyDecodingStrategy를 .convertFromSnakeCase로 설정합니다.

Equatable과 Hashable 프로토콜 적합성(Equatable and Hashable Protocols Conformance)

Swift 4는 구조체가 Equatable과 Hashable를 준수하도록 상용구 코드를 작성이 요구됩니다.

struct Country: Hashable {
  let name: String
  let capital: String
  
  static func ==(lhs: Country, rhs: Country) -> Bool {
    return lhs.name == rhs.name && lhs.capital == rhs.capital
  }
  
  var hashValue: Int {
    return name.hashValue ^ capital.hashValue &* 16777619
  }
}

이 코드에서, Equatable과 Hashable모두 지원하기 위해 ==(lhs:rhs:)와 hashValue를 구현했습니다. 여러분은 국가들을 비교하고, 세트에 추가하고 딕셔너리 키로 사용할 수 있습니다.

let france = Country(name: "France", capital: "Paris")
let germany = Country(name: "Germany", capital: "Berlin")
let sameCountry = france == germany

let countries: Set = [france, germany]
let greetings = [france: "Bonjour", germany: "Guten Tag"]

Swift 4.1은 모든 프로퍼티들이 Equatable와 Hashable인 경우에, Equatable과 hashable에 대한 구조체에서 기본 구현(default implementations)을 추가합니다. SE-0185

이렇게하면 코드가 매우 단순해지며, 간단히 다음과 같이 작성할 수 있습니다.

struct Country: Hashable {
  let name: String
  let capital: String
}

Swift 4에서 Equatable와 Hashable으로 작업하기 위해 관련된 값(associated values)인 열거형(Enumerations)은 추가코드가 필요합니다.

enum BlogPost: Hashable {
  case tutorial(String, String)
  case article(String, String)
  
  static func ==(lhs: BlogPost, rhs: BlogPost) -> Bool {
    switch (lhs, rhs) {
    case let (.tutorial(lhsTutorialTitle, lhsTutorialAuthor), .tutorial(rhsTutorialTitle, 
               rhsTutorialAuthor)):
      return lhsTutorialTitle == rhsTutorialTitle && lhsTutorialAuthor == rhsTutorialAuthor
    case let (.article(lhsArticleTitle, lhsArticleAuthor), .article(rhsArticleTitle, rhsArticleAuthor)):
      return lhsArticleTitle == rhsArticleTitle && lhsArticleAuthor == rhsArticleAuthor
    default:
      return false
    }
  }
  
  var hashValue: Int {
    switch self {
    case let .tutorial(tutorialTitle, tutorialAuthor):
      return tutorialTitle.hashValue ^ tutorialAuthor.hashValue &* 16777619
    case let .article(articleTitle, articleAuthor):
      return articleTitle.hashValue ^ articleAuthor.hashValue &* 16777619
    }
  }
}

열거형의 케이스가 사용되어 ==(lhs:rhs:)와 hashValue에 대한 구현을 작성했습니다. 이를 통해 블로그 게시물을 비교하고 세트와 딕셔너리에서 사용할 수 있습니다.

let swift3Article = BlogPost.article("What's New in Swift 3.1?", "Cosmin Pupăză")
let swift4Article = BlogPost.article("What's New in Swift 4.1?", "Cosmin Pupăză")
let sameArticle = swift3Article == swift4Article

let swiftArticlesSet: Set = [swift3Article, swift4Article]
let swiftArticlesDictionary = [swift3Article: "Swift 3.1 article", swift4Article: "Swift 4.1 article"]

Hashable의 경우와 마찬가지로, 이 코드 크기는 기본 Equatable과 Hashable구현 덕분에 
Swift 4.1에서 크게 줄어들었습니다.

enum BlogPost: Hashable {
  case tutorial(String, String)
  case article(String, String)
}

20줄의 상용구 코드를 관리하지 않아도 됩니다.


Hashable Index Types

첨자 매개변수의 타입이 Swift 4에서 Hashable인 경우 키 경로에서 첨자를 사용할 수 있습니다. 이를 통해 double의 배열로 작업할 수 있었습니다.

let swiftVersions = [3, 3.1, 4, 4.1]
let path = \[Double].[swiftVersions.count - 1]
let latestVersion = swiftVersions[keyPath: path]

keyPath를 사용하여 swiftVersions로 현재 Swift 버젼 번호를 가져옵니다.

Swift 4.1은 표준 라이브러리의 모든 인덱스 타입에 Hashable 적합성을 추가합니다. SE-0188

let me = "Cosmin"
let newPath = \String.[me.startIndex]
let myInitial = me[keyPath: newPath]

첨자는 문자열의 첫번째 글자를 반환합니다. Swift에서 String 인덱스 타입은 Hashable이기 때문에 동작합니다.

프로토콜에서 연관된 타입에 대한 재귀적 제약(Recursive Constraints on Associated Types in Protocols)

Swift 4는 프로토콜에서 관련된 타입(associatedtype)에 대한 재귀적 제약(recursive constraints) 정의를 지원하지 않습니다.

protocol Phone {
  associatedtype Version
  associatedtype SmartPhone
}

class IPhone: Phone {
  typealias Version = String
  typealias SmartPhone = IPhone
}

예제에서, SmartPhone 관련된 타입(associatedtype)을 정의하였지만, 모든 스파트폰은 전화기이기 때문에, Phone에 제약하는것이 유용할수 있습니다. Swift 4.1 에서는 이제 가능합니다. SE-0157

protocol Phone {
  associatedtype Version
  associatedtype SmartPhone: Phone where SmartPhone.Version == Version, SmartPhone.SmartPhone == SmartPhone
}

Version과 SmartPhone 모두 phone과 같아야하기 위해 where를 사용합니다.

프로토콜에서의 Weak와 Unowned 참조(Weak and Unowned References in Protocols)

Swift 4는 프로토콜 프로퍼티에 대해서 weak와 unowned를 지원합니다.

class Key {}
class Pitch {}

protocol Tune {
  unowned var key: Key { get set }
  weak var pitch: Pitch? { get set }
}

class Instrument: Tune {
  var key: Key
  var pitch: Pitch?
  
  init(key: Key, pitch: Pitch?) {
    self.key = key
    self.pitch = pitch
  }
}

특정 키(key)와 음높이(pitch)로 악기를 튜닝했습니다. 음높이(pitch)가 nil일수도 있으며, 튜닝(Tune) 프로토콜에서 weak로 모델링 할 수 있습니다.

그러나 프로토콜 자체에서 정의되었으면 weak와 unowned모두 실질적으로 의미가 없으며, Swift 4.1은 그것들을 제거하고 프로토콜에서 이러한 키워드를 사용하여 경고 메시지가 나타날 것입니다. SE-0186

protocol Tune {
  var key: Key { get set }
  var pitch: Pitch? { get set }
}

콜렉션에서 인덱스 간격(Index Distances in Collections)

Swift 4는 collection에서 요소들의 숫자를 선언하기 위해 IndexDistance를 사용하였습니다.

func typeOfCollection<C: Collection>(_ collection: C) -> (String, C.IndexDistance) {
  let collectionType: String
  
  switch collection.count {
  case 0...100:
    collectionType = "small"
  case 101...1000:
    collectionType = "medium"
  case 1001...:
    collectionType = "big"
  default:
    collectionType = "unknown"
  }
  
  return (collectionType, collection.count)
}

typeOfCollection(_:)은 콜렉션의 타입과 갯수를 포함하는 튜플을 반환합니다. 배열(array), 딕셔너리(dictionaries), 세트(sets)와 같은 콜렉션 종류를 사용할수 있습니다; 예를 들어:

typeOfCollection(1...800) // ("medium", 800)
typeOfCollection(greetings) // ("small", 2)

where을 사용하여 indexDistance를 Int로 제한하여 함수의 반환 타입을 향상시킬 수 있습니다.

func typeOfCollection<C: Collection>(_ collection: C) -> (String, Int) where C.IndexDistance == Int {
  // same code as the above example
}

Swift 4.1은 표준 라이브러리에서 IndexDistance를 Int로 교체하며, 이 경우에는 where절이 필요하지 않습니다. SE-0191

func typeOfCollection<C: Collection>(_ collection: C) -> (String, Int) {
  // same code as the above example
}

모듈에서 구조체 초기화(Structure Initializers in Modules)

Swift 4에서 public 구조체에 속성을 추가하면 원본이 깨지는(source-breaking) 변경이 발생할 수 있습니다. 이 튜토리얼에서, Xcode에서 View\Navigators\Show Project Navigator으로 가서 프로젝트 네비게이터(Project Navigator)가 보이는지 확인합니다. 그 다음에, Sources에서 우측 클릭하고 메뉴에서 New File을 선택합니다. DiceKit.swift 파일 이름을 변경합니다. 다음 코드 블록으로 내용을 변경합니다.

public struct Dice {
  public let firstDie: Int
  public let secondDie: Int

  public init(_ value: Int) {
    let finalValue: Int

    switch value {
    case ..<1:
      finalValue = 1
    case 6...:
      finalValue = 6
    default:
      finalValue = value
    }

    firstDie = finalValue
    secondDie = 7 - finalValue
  }
}

구조체의 초기화는 두개의 주사위가 1과 6사이의 유효한 값을 가지도록 합니다. playground로 돌아가서 이 코드를 끝부분에 추가하세요.

// 1
let dice = Dice(0)
dice.firstDie
dice.secondDie

// 2
extension Dice {
  init(_ firstValue: Int, _ secondValue: Int) {
    firstDie = firstValue
    secondDie = secondValue
  }
}

// 3
let newDice = Dice(0, 7)
newDice.firstDie
newDice.secondDie

다음은 이 코드로 수행한 것입니다.

  1. 유효한 주사위 한쌍을 만들었습니다.
  2. 속성(properties)에 직접 접근할 수 있는 다른 초기화로 Dice를 확장(expended)하였습니다.
  3. 구조체의 새로운 초기화로 유효하지 않은 주사위 한쌍을 정의 했습니다.

Swift 4.1에서, cross-target initializers는 기본 값을 호출해야 합니다. Dice의 확장(extension)을 다음과 같이 변경합니다.

extension Dice {
  init(_ firstValue: Int, _ secondValue: Int) {
    self.init(abs(firstValue - secondValue))
  }
}

이 변경으로 구조체는 클래스 처럼 동작합니다: Swift 4.1에서 크로스 모듈 초기화(cross-module initializers)는 반드시 편리한 초기화(convenience initializers)이어야 합니다.


플랫폼 설정과 빌드 환경 업데이트(Platform Settings and Build Configuration Updates)

Swift 4.1은 코드 테스트하는데 많은 플랫폼과 빌드 기능을 추가하였습니다.

빌드 포함(Build Imports)

Swift 4에서, 운영 시스템 자체를 확인하여 특정 플랫폼(platform)에서 모듈(module)을 사용할수 있는지 테스트했습니다. 예를 들어:

#if os(iOS) || os(tvOS)
  import UIKit
  print("UIKit is available on this platform.")
#else
  print("UIKit is not available on this platform.")
#endif

UIKit은 iOS와 tvOS에서 사용할수 있으며, 테스트가 성공하면 포함(imported)했습니다. Swift 4.1는 모듈 자체(module itself)에 대해 확인하도록 하여 작업을 더 단순화합니다.

#if canImport(UIKit)
print("UIKit is available if this is printed!")
#endif

Swift 4.1에서, 특정 프레이뭐크를 가져올수 있는지 확인하기 위해 #if canImport(UIKit)을 사용합니다. SE-0075

대상 환경(Target Environments)

Swift 4 코드를 작성할때, 시뮬레이터나 실제 장치에서 실행가능한지 확인하기 위해 가장 잘 알려진 방법은 아키텍쳐와 운영체제를 모두 확인하는 것입니다.

#if (arch(i386) || arch(x86_64)) && (os(iOS) || os(tvOS) || os(watchOS))
  print("Testing in the simulator.")
#else
  print("Testing on the device.")
#endif

아키텍쳐가 인텔 기반이고 운영체제가 iOS, tvOS, watchOS 인경우에, 시뮬레이터에서 테스트 했었습니다. 그렇지 않으면, 장치(device)에서 테스트 했었습니다.

이 테스트는 매우 성가시고 또한 문제를 잘 설명하지 못했습니다. Swift 4.1은 이러한 테스트를 좀 더 간단하게 만듭니다. 단지 targetEnvironment(simulator)을 사용하면 됩니다. SE-0190

#if targetEnvironment(simulator)
  print("Testing in the simulator.")
#endif

그외 다양한 것들(Miscellaneous Bits and Pieces)

Swift 4.1에서 알아 두어야 할 몇가지 업데이트가 있습니다.

순서 압축하기(Compacting Sequences)

불행하게도, flatMap(_:)은 다양한 방법으로 오버로드되고, 특정 시나리오에서, flatMap(_:) 이름은 동작에 대해 잘 설명하지 못했습니다.

이러한 이유들로, Swift 4.1에서는 의미를 더 분명히하고 고유하게 만들기 위해, flatMap(_:)의 이름을 compactMap(_:)으로 변경되었습니다. SE-0187

let petNames = pets.compactMap { $0 }

안전하지 않은 포인터(Unsafe Pointers)

Swift 4는 안전하지 않은 가변 버퍼 포인터(unsafe mutable buffer pointers)를 생성하고 변경하기 위해, 임시로 안전하지 않은 가변 포인터(unsafe mutable pointers)를 사용되었습니다.

let buffer = UnsafeMutableBufferPointer<Int>(start: UnsafeMutablePointer<Int>.allocate(capacity: 10), 
                                             count: 10)
let mutableBuffer = UnsafeMutableBufferPointer(start: UnsafeMutablePointer(mutating: buffer.baseAddress), 
                                               count: buffer.count)

Swift 4.1을 사용하면 안전하지 않은 가변 버퍼 포인터로 직접 작업할 수 있으며, 안전하지 않은 가변 포인터와 같은 접근법을 사용합니다. SE-0184

let buffer = UnsafeMutableBufferPointer<Int>.allocate(capacity: 10)
let mutableBuffer = UnsafeMutableBufferPointer(mutating: UnsafeBufferPointer(buffer))

새로운 Playground 기능(New Playground Features)

Swift 4에서는 Xcode playgrounds에서 타입 설명을 사용자 정의할 수 있었습니다.

class Tutorial {}
extension Tutorial: CustomPlaygroundQuickLookable {
  var customPlaygroundQuickLook: PlaygroundQuickLook {
    return .text("raywenderlich.com tutorial")
  }
}
let tutorial = Tutorial()

튜토리얼(Tutorial)에서 playground 설명을 사용자정의 훑어보기를 반환하기 위해 CustomPlaygroundQuickLookable을 구현했습니다. customPlaygroundQuickLook의 설명 타입은 PlaygroundQuickLook의 경우에 제한되었습니다. Swift 4.1에서 더 이상 사실이 아닙니다:

extension Tutorial: CustomPlaygroundDisplayConvertible {
  var playgroundDescription: Any {
    return "raywenderlich.com tutorial"
  }
}

이번에 CustomPlaygroundDisplayConvertible을 구현합니다. 그 설명의 타입은 Any이며, playgroundDescription에서 아무것도 반환할 수 없습니다. 이렇게 하면 코드가 단순해지고 더 유연해집니다. SE-0198

여기에서 어디로 가야하나요?(Where to Go From Here?)

최종 playground를 Download Materials링크에서 다운로드 받을 수 있습니다.

Swift 4.1은 올해 후반기에 나오는 Swift 5에 추가할 중대한 변경사항에 대배하기 위해 Swift 4 기능을 개선합니다. 여기에는 ABI 안전성, 향상된 제네릭과 문자열, 새로운 메모리 소유, 동시성(concurrency) 모델 등을 포함합니다.

모험을 느끼고 싶은 경우에, Swift 표준 라이브러리 diffs 또는 공식 Swift CHANGELOG에서 이 버젼에서 모든 변경 사항에 대한 자세한 정보를 볼수 있습니다. 또한 이것을 사용해서 Swift 5에 무엇이 오는지에 대해 주의를 하세요.

Swift 5와 그 이후의 변화가 어떻게 되는지 궁금하다면, 또한 Swift 진화 제안(Swift Evolution proposals)에서 확인하는 것을 추천하며, 그곳에서 어떤 새로운 기능, 변경, 추가되었는지 확인할 수 있습니다. 정말 원하는 경우, 검토중인 현재 제안 중 하나에 대한 리뷰를 남기거나 직접 제안을 해주세요.

Posted by 까칠코더