티스토리 뷰

Swift

Swift 4.2 변경사항

Zedd0202 2018. 6. 17. 17:17
반응형

안녕하세요 :) Zedd입니다. 

투표...다들 하셨겠죠.....꼭 하시길

요새 이래저래 글을 못썼는데 이제부터 부지런히 공부하면서 글을 쓰려고 합니다.

저는 정리하면서 공부하면 아주 잘...기억하는거 같음. 

그러니 제발 Apple은 WWDC 스크립트를 주시길 바랍니다ㅠ


"What's New in Swift 4.2”는 제 생에...첫..라이브로 본 WWDC였었는데 보고 나서 든 생각은 영어공부를 열심히 해야겠다....

반은 이해가는데 반은 이해 안가는 상황

기억나는건 그 PPT리모콘이 이상했다는것....

지금보니까 리모콘 이상해서 막 당황하고 리모콘 교체하는거 편집된 것 같네요.

Apple의 인간미.......ㅎ


오늘은 일단 변경사항만 알아봅시다.

앞부분은 스크립트가 나와야 완벽히 이해할 수 있을 것 같음



아 또 여담이지만....문서를 뒤적거리다가




Documentation Archive..? 왠지..뭔가 처음 보는 로고? 카피..?그래서 들어가봤더니


더이상 업데이트 되지 않는다.........라고 하는것 같네요.

아 물론 없어진거 아니고 아카이브니까 다 남아있습니다.

로딩이..왜이렇게 길지


2018-06-04에 포풍 업데이트하심




ㅠㅠ여기도 바뀜...Guide And Sample뭐 이런거 있지 않았나요..

하긴 근데 API reference랑 내용이 다른게 너무 많았음 ㅡㅡ

물론 API reference가 더 최신.


암튼 이제




여기만 이용하라는 말...ㅇㅋ

또 Swift문서 사이트가 조금 바뀌었네요.

제가 너무 늦게 본 걸수도;;;



가 디자인이 바뀐것 같습니다. 이렇게 생기진 않았었는데..원래 swift.org안에 있었나...? Swift 문서 공부하던 옛날글들 링크 눌러보면 이제 다 이쪽으로 오네요. 



됐고 이제 레알루다가 4.2에서 뭐 바뀌었는지 알아봐야함



초록색 체크들은 “커뮤니티”에서 제안한거고, Swift 4.2에서 구현이 완료된 기능?들입니다.



Derived collections of enum cases

Warning and error diagnostic directives

Dynamic member look up

Enhanced conditional conformances

Random number generation and shuffling

Simpler, more secure hashing

Checking sequence elements match a condition

In-place collection element removal

Boolean toggling



하나씩 살펴봅시다.


● Derived collections of enum cases [SE-0194]

갸ㅑㅑㅑㅑㅑㅑㅑㅑㅑㅑㅑㅑㅑㅑㅑㅑㅑㅑㅑㅑㅑㅑㅑㅑㅑ


associated values 가 없는 enum(열거형)은 유한하고 고정된 수의 case를 가지지만, 프로그램 방식으로 작업하는 것은 어렵습니다.

모든 case를 열거하고, 계산하고, 가장 높은(highest) rawValue를 결정하거나, 해당 값의 colleciton을 생성하는 것은 당연합니다. 

그러나 Swift컴파일러와 Swift런타임 모두 이 정보를 알고있음에도 불구하고, 사용자가 정보를 검색할 수 있는 안전하고 승인된 방법은 없습니다. 

사용자는 간단한 enum의 모든 case를 반복하기 위해, 다양한 해결방법을 사용해야합니다.

이 주제는 swift-evolution이 존재하기 시작한 2개월 만에 3번에 걸쳐 제기되었습니다.zzzzzz


우리는 타입이 유한하고, 열거 가능한 값 집합을 가지고 있음을 나타내기 위해, CaseIterable이라는 프로토콜을 제안합니다.


SE-0194를 가시면 이 CaseIterable과 같은 효과를 내기 위해..정말 ㅁ노력한 코드들을 볼 수 있습니다. 

왜 이제 내준건데.....


Solution.


enum Beverage: CaseIterable {

    case coffee, tea, juice

}


Beverage.allCases // returns some Collection whose Iterator.Element is Beverage

Beverage.allCases.count   // returns 3

Array(Beverage.allCases// returns [coffee, tea, juice]


네, 그렇습니다. CaseIterable프로토콜은 자동으로 열거형의 모든 case에 대한 collection을 만들어줍니다.

enum이 CaseIterable를 준수하기만 한다면요.

컴파일타임에 Swift는 자동으로 사용자가 정의한 순서대로 모든 case의 배열인 “allCases”프로퍼티를 생성합니다. 


  1. enum Beverage: CaseIterable {
  2. case coffee, tea, juice
  3. }

  4. for beverage in Beverage.allCases {
  5. print(beverage)
  6. }
  7. // coffee
  8. // tea
  9. // juice


이제 이게 손쉽게 가능해지는 것이죠.


무조건 저 allCases라는 프로퍼티가 생기는건 아니고. associated values가 없는 경우에만 생깁니다.




이렇게 case 중에 하나라도 associated values가 있게되면, CaseIterable를 준수하지 않는다는 에러를 뱉게 됩니다.

....


그럼 associated values있으면 CaseIterable못쓰냐 ㅡㅡ 

아닙니다.

CaseIterable를 채택하지 않는 방법도 있겠지만, 우리가 "직접" 추가해주는 방법이 있습니다. 


enum Beverage: CaseIterable {

    case coffee, tea, juice

    case pizza(with: String)

    

    static var allCases: [Beverage] {

        return [.coffee, .tea, .juice, .pizza(with: "cheese")]

    }

}


바로 이렇게 말이죠. 

(Xcode 10은 조금 뭔가 뭔가....굵네요. 글씨크기가. 복사해와도 자동으로 bold처리가 되네) 



물론 저 "직접 넣는" allCases를 이용해 내가 원하는 case들만 넣어줄 수 도 있겠죠? 


enum Beverage: CaseIterable {

    case coffee, tea, juice

    case coke

    

    static var allCases: [Beverage] {

        return [.coffee, .tea, .juice]

    }

}


이렇게요. coke case가 allCases에서 빠지게 되겠죠/

또한 case에 unavailable를 mark하면, 

enum Beverage: CaseIterable {

    case coffee, tea, juice


    @available(*, unavailable)

    case coke

} //error!


위 코드는 에러를 내게 되는데요, CaseIterable을 준수하지 않기 때문입니다.



그래서 직접 allCases만들어줘야함..



enum Beverage: CaseIterable {

    case coffee, tea, juice


    @available(*, unavailable)

    case coke


    static var allCases: [Beverage] {

        return [.coffee, .tea, .juice]

    }

}


이렇게요!


주의 : enum의 original 정의부에 CaseIterable를 추가해야합니다. extension에서는 x

훌륭하다 Apple.



● Warning and error diagnostic directives [SE-0196]

이 제안은  #warning 및 #error 지시문을 도입하여 Swift컴파일러가 컴파일 중 사용자 정의 경고 또는 오류를 방출하도록 합니다.


자, 새로운 지시문은 위에서 말했다시피, 2가지 입니다.


#warning : 코드를 작성할 때, Xcode에서 경고를 표시하도록 합니다. 

#error : 컴파일 오류를 발생시켜 빌드되지 않도록 합니다. 


이 두가지 모두 다른 이유로 유용하다고 하는데요,


#warning은 주로 자신이나 다른사람들에게 어떤 작업이 불완전하다는 것을 상기시키는데 유용합니다.


func configPath() -> String {

    #warning("this should be made more safe")

    return Bundle.main().path(forResource: "Config", ofType: "plist")!

}


이렇게 하면 아 코드는 강제 언래핑이 있어서 위험하니까 좀 더 안전하게 만들 필요가 있다..!라고 자신이나 다른 개발자가 알 수 있게 되죠.



굉장히 거슬려서 빨리 고쳐버리고싶음




#error는 바로 예제부터 볼까요.


struct Configuration {

    var apiKey: String {

        #error("Please enter your API key below then delete this line.")

        return "Enter your key here"

    }

}


위와같은 코드 많이 보셨을지도 모릅니다.

!!!!!!!!!!!!!!!!!!!! 만약에 뭐 제가 어떤 예제 프로젝트를 받았다고 칩시다. 하지만 API키는 각자꺼를 넣어야해요.

하지만 모르고 돌리면..암튼 일단 프로젝트가 빌드가 되긴 할겁니다. 아무것도 받아오진 않겠지만..ㅎㅎ

아무튼 이럴때!!!!!! #error를 저렇게 놓게되면, 빌드가 안되고 저부분에 오류가생긴다는 것이죠.





두 지시문은 #warning ( "Some message") 및 #error ( "Some message")와 같은 방식으로 작동합니다.

또한,  #warning 및 #error는 기존 #if지시문과 함께 사용 할 수 있습니다. 평가되는 조건이 true인 경우만 트리거 됩니다. 


아래 #if 지시문이 true이기 때문에, 아래 #warning과 #error가 실행되게 됩니다. 


이 제안은 Objc를 사용 해본 개발자라면 익숙하다고 하네요..! 





● Dynamic member look up [SE-0195]


이 제안은 새로운 @dynamicMemberLookup 특성을 도입합니다. 


Swift를 Python과 같은 스크립트 언어에 더 가깝게 만들 수 있는 방법인데요, 이 특성은 Swift가 프로퍼티에 접근할 때, subscript메소드를 호출하도록 지시합니다. 때문에 subscript메소드인 subscript (dynamicMember :)가 필요합니다.

요청한 프로퍼티의 문자열 이름이 전달되고, 원하는 값을 반환받을 수 있습니다.


이거는 말로 하면..잘 이해가 안가고 예제를 봐야합니다. 

Swift4.2전까지, custom subscript를 사용하고 싶으면, 


class DJ {

    subscript(key: String) -> String {

        switch key {

        case "Zedd":

            return "stay"

        case "Avicii":

            return "levels"

        default:

            return ""

        }

    }

}

let zedd = DJ()

zedd["Zedd"] //stay



이렇게 정말로 subscript를 사용하여 해당 값을 불러와야 했었죠.

하지만, Swift4.2에서는, 


@dynamicMemberLookup

class DJ {

    subscript(dynamicMember key: String) -> String {

        switch key {

        case "Zedd":

            return "stay"

        case "Avicii"

            return "levels"

        default:

            return ""

        }

    }

}

let zedd = DJ()

zedd.Zedd //stay



자, DJ앞에 @dynamicMemberLookup특성을 표시하고, subscript메소드인 subscript (dynamicMember :)가 필요하다고 그랬으니, 만들어줍니다.

그러면...!!!!!! 우리가 만든 subscript를 우리에게 굉장히 익숙한 .(dot) syntax로 호출할 수 있게 됩니다. 


컴파일러가 subscript를 평가할 때,  subscript가 "런타임"에 동적으로 호출되기 떄문에 Python이나 Ruby같은 스크립팅 언어에서와 마찬가지로 타입에 안전한 코드를 작성 할 수 있다고 합니다.


Dynamic member lookup을 명시했다고 해서, 타입의 프로퍼티에 영향을 주는 것은 아닙니다. 


@dynamicMemberLookup

class DJ {

    var name: String

    var song: String

    

    init(name: String, song: String) {

        self.name = name

        self.song = song

    }

    

    subscript(dynamicMember key: String) -> String {

        return "\(name) - \(song)"

    }

}

let zedd = DJ(name: "Zedd", song: "stay")

zedd.안녕하세요 //"Zedd - stay"

zedd.name //"Zedd"

zedd.song //"stay"


신기한점은 저렇게 타입의 저장프로퍼티가 아닌 것들을 .(dot) syntax로 호출하게 되면, 알아서 subscript가 불립니다. zedd.안녕하세요 를 부르니까 "Zedd - stay"가 출력된거 보이시죠!?!?


상속에서도 당연히 동작을 하게 됩니다. 


@dynamicMemberLookup

class DJ {

    var name: String

    var song: String

    

    init(name: String, song: String) {

        self.name = name

        self.song = song

    }

    

    subscript(dynamicMember key: String) -> String? {

        return "\(name) - \(song)"

    }

}


class Avicii: DJ {}

let avicii = Avicii(name: "Avicii", song: "levels")

avicii.안녕 //"Avicii - levels"

avicii.zedd //"Avicii - levels"

avicii.name //"Avicii"

avicii.song //"levels"




클로져도 리턴할 수 있습니다!


@dynamicMemberLookup

class DJ {

    subscript(dynamicMember key: String) -> (_ str: String) -> Void {

        return {

          print("안녕하세요 :) \($0)입니다.")

        }

    }

}


let zedd = DJ()

zedd.printSomething("Zedd") //안녕하세요 :) Zedd입니다.


@dynamicMemberLookup은 Swift의 타입 시스템에서 전체적인 역할을 합니다. 

즉, 프로토콜, 구조체, 열거형 및 클래스(@objc로 표시된 클래스 포함)에 명시 할 수 있습니다.


위 말은!!!!!!!! 두가지를 의미하게 되는데요.


첫번째는 위 예제에서 보았듯이, @dynamicMemberLookup을 사용하여 클래스를 만들 수 있으며, 클래스를 상속한 클래스도 자동으로 @dynamicMemberLookup입니다. 


두번째로, @dynamicMemberLookup을 프로토콜에서 정의하고, 프로토콜 extension을 사용하여 @dynamicMemberLookup이 요구하는  subscript(dynamicMember:)를 추가한 다음, 원하는 대로 프로토콜을 준수하도록 만들 수 있습니다.

예제를 볼까요?


@dynamicMemberLookup

protocol Subscripting { }


extension Subscripting {

    subscript(dynamicMember member: String) -> String {

        return "This is coming from the subscript"

    }

}


extension String: Subscripting { }

let str = "Hello, Swift"

print(str.username) //"This is coming from the subscript\n"


자, Subscripting이라는 프로토콜을 정의하고, 해당 프로토콜의 extension에서 subscript(dynamicMember:)을 구현해주었습니다. 그리고 Swift기본타입인 String이 Subscripting을 채택하도록 했습니다. 

그리고, 아무 String에서 현재 String에 없는 프로퍼티 "이름"을 써주면, 위에서 미리 구현해두었던 

subscript(dynamicMember:)가 런타입에 동적으로 호출이 되어, "This is coming from the subscript\n"이라는 것을 출력하게 됩니다. 



SE-0195에 가시면 Apple이 적어놓은 예제가 하나 있는데요, 

ㅇ엌ㅋㅋㅋ그러고보니


이 문서는 크리스 래트너가 썼나봄 갸ㅑㅑ

암튼 ㄱ 크리스 래트너가 @dynamicMemberLookup을 사용하여 JSON탐색을 보다 자연스러운 구문으로 만들기 위해 예제를 하나 들었네요, 


@dynamicMemberLookup

enum JSON {

    case IntValue(Int)

    case StringValue(String)

    case ArrayValue(Array<JSON>)

    case DictionaryValue(Dictionary<String, JSON>)

}


extension JSON {

    var stringValue : String? {

        if case .StringValue(let str) = self {

            return str

        }

        return nil

    }

    subscript(index: Int) -> JSON? {

        if case .ArrayValue(let arr) = self {

            return index < arr.count ? arr[index] : nil

        }

        return nil

    }

    subscript(dynamicMember member: String) -> JSON? {

        if case .DictionaryValue(let dict) = self {

            return dict[member]

        }

        return nil

    }

}

(왜 enum의 각 케이스가 대문자로 시작하는지는 모르겠음.)

암튼 이렇게 하면. 


원래 

let json = JSON.StringValue("Example")

json[0]?["name"]?["first"]?.stringValue


이런식으로 써야하는 것을


json[0]?.name?.first?.stringValue


뭐 이런식으로 .(dot) syntax를 통해 JSON값에 접근 할 수 있게 됩니다.


ㅇㅋ

끝임




Enhanced conditional conformances [SE-0143].

Swift 4.1 변경사항글에서도 본 것 같죠? "conditional conformances”.

하지만......conditional conformances가 짱짱인것 같지만 짱짱이 아니어따


Swift 4.1 변경사항글에 예제로 든것이 Purchaseable프로토콜입니다.


protocol Purchaseable {

    func buy()

}

struct Book: Purchaseable {

    func buy() {

        print("You bought a book")

    }

}


배열안에 element가 모두 Purchasable인 경우, 배열이 Purchasable을 준수하도록 할 수 있었습니다. 


extension Array: Purchaseable where Element: Purchaseable {

    func buy() {

        for item in self {

            item.buy()

        }

    }

}


이것은 컴파일 타임에 훌륭하게 작동했지만, 문제가 있었다고 합니다.

런타임에 conditional conformance을 쿼리해야한다면, Swift 4.1에서는 지원되지 않았기 때문에 crash가 발생하게 됩니다.


그래서..!!!

Swift 4.2에서는 이것이 고쳐졌습니다.

바로 "dynamic queries"


let items: Any = [Book(), Book(), Book()]


if let books = items as? Purchaseable {

    books.buy()

}

//You bought a book

//You bought a book

//You bought a book



일치하는 프로토콜로 변환 할 수 있는지 확인하려는 경우, 위와같이 훌륭하게 작동합니다.

이게 왜...? 싶지만, Swift 4.1에서는..



let items: Any = [Book(), Book(), Book()]


if let books = items as? Purchaseable {

    books.buy()

}


//아무것도 출력되지 않음.



왜냐? 



extension Array: Purchaseable where Element: Purchaseable {

    func buy() {

        for item in self {

            item.buy()

        }

    }

}


위 코드가 없으니까.....하지만 Swift 4.2에서는 위에 처럼 저렇게 명시를 안해줘도, 알아서 다 해준다능ㅎ

갸ㅑㅑㅑ



그리고 Hashable도 완전히 강화?..엄청 좋아졌는데요,


모든 프로퍼티가 각각 Hashable을 준수해야만 자동으로 hashValue라는 것을 합성해주었는데요,


Swift 4.1에서는 안됐었던 array가 Swift4.2에서는 됩니다!


struct User: Hashable {

    var name: String = ""

    var pets: [String] = []

}


let user = User()

user.hashValue


array이외에도, optional, dictionary 심지어 range까지 지원하게 됩니다.


다음으로 ㄱ





Random number generation and shuffling [SE-0202]

제 글 중에서 random number뽑는 방법글도 있는데...이젠 ㅂㅂ...

한번 봅시다.


현재 Swift가 제공하는 random 기능은, C API를 통해 이루어진다고 합니다. 물론 코드를 실행하는 시스템에 따라 다르긴 하지만요.

예를들어, arc4random_uniform(_:)를 볼까요


let digit = Int(arc4random_uniform(10))


위 코드는 0~9사이의 임의의 숫자를 반환했습니다. 이는 Foundation import가 필요했고, Linux에서는 작동하지 않습니다.

반면에, 모든 Linux기반 접근 방식은 modulo bias를 도입했는데, 이는 특정 숫자가 다른 것보다 더 자주 생성되었음을 의미했습니다.


즉, 시스템마다 다른 random 구현이 제공됩니다.

그래서, 이 제안의 주요한 초점은 random API의 통합 및, 모든 플랫폼에 대한 안전안 random API를 만드는 것입니다.

Swift4.2에서는 random API를 표준 라이브러리에 추가하여 이러한 문제를 해결합니다.


let randomInt = Int.random(in: 1..<5)


바로 위와같이 말이죠.

위 코드는 Int지만, Float 및 Double에도 적용 할 수 있습니다. 


let randomFloat = Float.random(in: 1..<10)

let randomDouble = Double.random(in: 1...100)


심지어는...


let randomBool = Bool.random()


Bool타입 마저도 random한 값을 뽑을 수 있게 되었습니다. 대신 파라미터가 없는건 당연하겠죠?

위코드는 사실 


if Int.random(in: 0...1) == 1 {

    //code

}


위와 같이 접근해도 되지만,  let randomBool = Bool.random()사용자의 의도를 보다 명확하게 표현합니다. 

random한 값을 뽑는 API이외에도,  Array내의 shuffle()과 shuffled()메소드를 사용하여 배열을 뒤섞는 기능도 지원합니다.

shuffle()과 shuffled()의 차이는 sort()와 sorted()의 차이와 같습니다. shuffle()이 in-place죠.

var albums = ["Red", "1989", "Reputation"]


// shuffle in place

albums.shuffle()


// get a shuffled array back

let shuffled = albums.shuffled()


이것이 끝이 아닙니다.

Array에 새로운 메소드가 또!! 추가되었는데요, 바로 randomElement()라는 메소드입니다. 이름만 봐도...뭔지 알 것 같죠?

randomElement()는 비어있지 않은 Array의 임의의 요소를 반환하고, 그렇지 않으면 nil을 반환합니다.


if let random = albums.randomElement() {

    print("The random album is \(random).")

}


albums = []

albums.randomElement() //nil


randomElement()가 나오기 전까지......배열안에서 임의의 요소를 뽑기위해 얼마나 아름답지 않은 코드를 짰었는지.........ㅎㅎ...

Apple ㄱㅅ



Simpler, more secure hashing [SE-0206]

해싱이 조금더 간단해지고 안전해졌다는 말 같네요.

봅시다.

아시다시피, Swfit의 Collection중, Set과 Dictionary는 Hashable한 값들만 들어올 수 있었죠.

좋은 Hash함수를 사용하면, 간단한 조회, 삽입 및 삭제가 평균적으로 일정한 시간이 걸릴 수 있습니다.

그러나 데이터에 맞게 Hash함수를 신중하게 선택하지 않으면 이러한 연산의 예상 시간이 테이블에 저장된 요소 수에 비례하게 될 수 있습니다. 

테이블이 충분히 큰 경우, 이러한 상황은 쉽게 용인 할 수 없는 성능으로 이어질 수 있습니다. Hash충돌에 압도(overwhelmed)당하면, 앱과 네트워크 서비스가 새로운 이벤트를 장기간 처리하는 것을 멈출 수 있습니다. 또한, 앱을 응답이 없게 만들거나 서비스를 중단하기에 충분 할 수 있습니다.


이 제안은 표준 라이브러리의 범용 Hash함수를 나타내는 새로운 "Hasher"타입을 소개하며, hash(into:) 메소드 요구사항으로 Hashable프로토콜을 "확장"합니다. hash(into:)의 요구사항은 더이상 사용되지 않는 이전 hashValue프로퍼티를 대체하기 위한것입니다.


Hasher는 복원력있는 구조체이기 때문에, 표준 라이브러리의 향후 버전에서 Hashable을 구현하는 기존 코드를 변경하거나 다시 컴파일 할 필요가 없이, Hash기능을 향상시킬 수 있습니다. 


자..요약하자면, Swift 4.1변경사항에서, 타입이 Hashable을 채택하고, 모든 프로퍼티가 각각 Hashable을 준수한다면 컴파일러가 자동으로 hashValue라는 것을 합성해주었죠.

하지만, 자신만의 커스텀 hashValue를 만들고 싶다!!!고 하면 직접 만들 수 있었습니다. 

하지만. 


var hashValue: Int {

    return x.hashValue ^ y.hashValue &* 16777619

}


16777619은 왜있는거야? &는 왜? 그 옆에 *는 왜붙은거지? &*가 뭐지?????

라는 상황이 발생하게 되죠. 


이 제안은 이러한 과정을 쉽게 만듭니다.


struct iPad: Hashable {

    var serialNumber: String

    var capacity: Int


    func hash(into hasher: inout Hasher) {

        hasher.combine(serialNumber)

    }

}


바로 위처럼요. 

combine의 파라미터로서, 프로퍼티였던 serialNumber를 넣었네요.

단순히 이렇게만 해주면, 구현하기 쉽고 모든 이전버전에 비해 성능이 향상된다고 합니다.


combine()을 반복적으로 호출하여 Hash에 더 많은 프로퍼티를 추가할 수 있으며, 프로퍼티를 추가하는 순서는 완성된 hashValue에 영향을 줍니다.

Hasher를 독립적인 hash 생성기로 사용 할 수도 있습니다. hash할 값을 재공한다음, finalize()를 호출하여 최종값을 생성하면 됩니다. 


var hasher = Hasher()

hasher.combine(first)

hasher.combine(second)

let hash = hasher.finalize()


이렇게요!

Hasher는 객체를 Hash할 때 마다 임의의 Seed를 사용하므로, 앱 실행중에는 모든 객체의 hash값이 다르다는 것을 효과적으로 보장합니다.

즉, Set또는 Dictionary에 추가하는 요소는 앱을 실행할때마다 순서가 달라질 가능성이 높습니다. 

ㅇㅎ




Checking sequence elements match a condition [SE-0207]

시퀀스의 모든 요소가 어떠한 값과 같거나, 특정 기준과 일치하는지 확인하고자 하는 것은 일반적입니다.


// every element is 9

!nums.contains { $0 != 9 }

// every element is odd

!nums.contains { !isOdd($0) }


이렇게 말이죠.

하지만, 이번제안에서 이러한 메소드를 추가합니다.



let scores = [85, 88, 95, 92]


let passed = scores.allSatisfy { $0 >= 85 }


print(passed) //true


allSatisfy의 원형은


func allSatisfy(_ predicate: (Element) throws -> Bool) rethrows -> Bool


이렇게 생겼는데요, 

시퀀스의 모든 요소가 지정된 predicate를 충족하는지 여부를 나타내는 Bool값을 반환합니다.

유용하게 쓸 수 있겠죠?



In-place collection element removal [SE-0197]


collection에서 특정 요소의 모든 occurrences를 제거하려는 것은 일반적입니다.

이 제안은 removeAll알고리즘을 표준 라이브러리에 추가하여 주어진 predicate와 일치하는 collection의 모든 요소를 제거합니다. 


자, 일부 기준과 일치하는 모든 요소를 제거하는 것은 자주 있는 일이죠?

그러나 정확하고 효율적으로 구현하는 것은 까다로울 수 있습니다.

Swift3에서 이 효과를 얻는 가장 쉬운 방법은, filter를 사용했습니다.


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

// remove odd elements

nums = nums.filter { !isOdd($0) }


이렇게요.

nums에는 홀수가 아닌 요소만 뽑은 [2,4]가 들어가게 되겠죠.


위와같은 방법은, 가독성 문제 이외에도, 새로운 메모리 할당 및 제거 할 필요가 없는 경우에도, 모든 요소의 복사본이 생기는 두가지 성능문제가 있었습니다.


이 제안은 이러한 문제를 개선한것인데요,


var greetings = ["Hello", "Hi", "Goodbye", "Bye"]


greetings.removeAll { $0.count > 3 }


이제 이렇게 removeAll안에 조건을 넣어서..!! 할 수 있습니다.

갸ㅑㅑ



Boolean toggling [SE-0199]

꽤 오래전 부터 본....제안이네요.


view.isHidden = !view.isHidden


이런식의 코드들..........정말...많았습니다...


myVar.prop1.prop2.enabled = !myVar.prop1.prop2.enabled


길어지면 정말 아름답지 않음ㅡㅡ

그래서!!!!!!!! 이번 Swift 4.2에서는 toggle()이라는 메소드가 도입됩니다.

이름에 걸맞게 bool값을 토글해주는 것이죠.


extension Bool {

    /// Equivalent to `someBool = !someBool`

    ///

    /// Useful when operating on long chains:

    ///

    ///    myVar.prop1.prop2.enabled.toggle()

    mutating func toggle() {

        self = !self

    }

}


간-단


toggle 이름의 후보들로는 



  • invert
  • negate
  • flip


이런것들이 있었다고 해요zzz확실히..toggle이 완벽히 승




 Removing Implicitly Unwrapped Optionals[SE-0054]

Swift 4.1에서는 


let favoriteNumbers: [Int!] = [10, nil, 7, nil]

let favoriteSongs: [String: [String]!] = ["Cosmin": ["Nothing Else Matters", "Stairway to Heaven"],

                                          "Oana": nil]

let credentials: (usermame: String!, password: String!) = ("Cosmin", nil)


저렇게 타입에 !를 붙히면 warning이


Using '!' in this location is deprecated and will be removed in a future release; consider changing this to '?' instead


이렇게 떴었습니다.


let favoriteNumbers: [Int!] = [10, nil, 7, nil]


let favoriteSongs: [String: [String]!] = ["Cosmin": ["Nothing Else Matters", "Stairway to Heaven"], "Oana": nil]

let credentials: (usermame: String!, password: String!) = ("Cosmin", nil)


Swift 4.2에서 이렇게 하게 되면..


Using '!' is not allowed here; treating this as '?' instead


!가 허용이 안된다며, 대신 ?로 바꾸라고 하죠. 오류는 아니고..warning인건 같습니다. 



자, 이렇게 Swift 4.2변경사항을....공부해봤씁니당

뭔가 굉장히 많이 발전하는 듯한...그런 느낌이에요 :)

Xcode 10도 엄청 좋아지고!!!!!! 자동완성도 뭔가 빠른느낌 ㅎ

quick help도 보기 더 좋아지고..




quick help안에서 



여기로 갈 수 있었던..버튼은 없어졌지만




요거..저 document가서 볼 내용을 quick help에 다 담은듯 합니당.

얼른 정식으로 Xcode 10을 올리고 싶네요 ~.~

도움이 되었길 바래요 :)


출처 : 

https://www.raywenderlich.com/194066/whats-new-in-swift-4-2

https://www.hackingwithswift.com/articles/77/whats-new-in-swift-4-2




반응형

'Swift' 카테고리의 다른 글

Swift ) (1) Understanding Swift Performance (Swift성능 이해하기)  (24) 2018.09.21
Swift ) Method Swizzling  (1) 2018.07.07
Swift ) Class only Protocol. class? AnyObject?  (4) 2018.04.18
Swift ) FloatingPoint  (0) 2018.04.14
Swift 4.1 Released! -2  (0) 2018.04.14