8 Kwietnia 2018

Logo Swift 4.1

Wstęp

Czasu od pierwszej poważnej aktualizacji Swift’a minęło już co prawda trochę (Styczeń 2018), ale jakoś nie było okazji żeby napisać parę słów na temat tychże zmian. To no teraz nastał ten moment, w którym uznałem że… warto 😅.

Osobiście – subiektywnie – nowa wersja języka przyniosła dwie istotnie zmiany dotyczące pracy z protokołami. Protokoły Eqatable i Hashable dostały swoje default’owe implementacje (wreszcie… 💪), zostało też prowadzone coś, co przetłumaczyłem na warunkowanie zgodności, czyli conditional conformances.

Swift 4.1 to pierwsza duża zmiana wprowadzona do języka Swift od czasu wypuszczenia wersji 4 na WWDC 2017.

Ze spraw technicznych – do korzystania z wersji Swift 4.1 potrzebujesz Xcode w wersji 9.3 lub późniejszej.

Tyle w kwestii wstępu… lecimy z tematem 🚀.

Syntezowanie Equatable I Hashable

Od razu zacznę od zmiany, która dla mnie – osobiście – jest najistotniejszą z nowości. Swift od samego początku miał pewne rozwiązania, które możemy nazwać dziś jako… hm 🤔… nie do końca optymalne. Przykład? Parsowanie JSON przed wprowadzeniem protokołu Codable. Dopiero wersja 4.0 spowodowała, ze parsowanie najpopularniejszego obecnie formatu odpowiedzi serwerowych stało się proste i logiczne.

Podobnie było do tej pory właśnie z Equatable, czyli protokołem porównującym obiekty. W języku Swift jest tak, że kiedy porównujemy np. Dwie liczby – 2 == 2 – to tak naprawdę porównujemy dwa obiekty typu Int, którego to deklaracja implementuje protokół Equatable.

Jak każdy szanujący się deweloper, na pewno nie raz zdarzyło Ci się napisać własną „Porównywarkę” obiektów. Służył temu właśnie protokół Equatable, który pozwalał na nadpisanie metody „==” służącej porównywaniu obiektów.

Eksperyment na zwierzątkach 🐼:

struct Animal {
    var species: String
    var name: String
    var age: Int
    var habitat: String
}

Jeśli mamy teraz dwie instancje typu Animal i chcemy je porównać – do tej pory musieliśmy napisać metodę porównującą jej wszystkie parametry. 😓.

struct Animal: Equatable {
    var species: String
    var name: String
    var age: Int
    var habitat: String

    static func ==(lhs: Animal, rhs: Animal) -> Bool {
        return lhs.species == rhs.species && lhs.name == rhs.name && lhs.age == rhs.age && lhs.habitat == rhs.habitat
    }
}

Na szczęście – Swift 4.1 wprowadza automatyczne generowanie tej metody! Jedyne o co musimy się martwić jako deweloperzy to to, żeby zadeklarować protokół Equatable, a Swift robi za nas resztę porównując wszystkie dostępne dla kasy parametry. Oczywiście własna implementacja nadal pozostaje możliwa 😁.

Podobnie rzecz ma się w przypadku protokołu Hashable. Wcześnie aby „Zahashować” jakąś wartość potrzebowaliśmy stworzyć zmienną a następnie ręcznie dostarczyć implementację:


    var hashValue: Int {
        return name.hashValue ^ species.hashValue &* 18374110
    }

Dokładny opis zmian 👉 Swift Evolution proposal SE-0185

Conditional conformances

Druga ważna zmiana, którą dostajemy wraz z aktualizacją 4.1 dotyczy Conditional conformances, czyli po polskiemu tzw. Warunkowanie zgodności. W prostych słowach ➡️ od teraz typ może być zgodny z protokołem (implementować protokół) tylko wtedy, kiedy jest to konieczne.

Jakiś przykład 👇

Tworzymy protokół, który pozwala nam karmić zwierzęta:

struct Animal: Feedable {
    var species: String
    var name: String
    var age: Int
    var habitat: String
    
    func feed() {
        print("\(species) feeded. ">Yummy ">👻.")
    }
}

Do dobrze. Ale załóżmy że jesteśmy w Zoo, i tychże zwierząt jest wiele do wykarmienia. Możemy oczywiście zrobić pętlę po całej kolekcji i każdy obiekt nakarmić oddzielnie. Ale przecież My ➡️ dobrzy programiście chcemy to zrobić efektywniej, np. Poprzez rozszerzenie typu Array. No ale znowu problem 🤮 – jeśli napiszemy rozszerzenie dla całej kolekcji, to każdy rodzaj elementów tej kolekcji – String, Int, UIColor itp. Powinien dostać możliwość bycia nakarmionym.

Bez sensu.

I tu wkracza Swift 4.1 właśnie z conditional conformance! Oto jak teraz możemy zaimplementować nasz przykład w Swift:

extension Array: Feedable where Element: Feedable{
    func feed() {
        for item in self {
            item.feed()
        }
    }
}

Cudnie! Takich możliwości nie było we wcześniejszej wersji języka. Jest to spore ułatwienie, ale i duża poprawa dla stabilności. No bo weźmy np. Takie cudo:

var pets: [String?] = ["Cat", "Dog"]
var wilds: [String?] = ["Lion", "Tiger"]
var areSame = pets == wilds

W Swift 4.0 powyższy kod się nie skompiluje. Ma to związek z tym, że zmienna o typie opcjonalnym nie może być porównywana, bo nie implementuje protokołu Equatable (mimo że zarówno String jak i [String] go implementują). Ale w Swift 4.1 już tak ze względu na warunkowanie zgodności – dopóki elementy w tablicy są porównywalne, dopóty całość jest porównywalna.

Dokładny opis zmian 👉 SE-0143

Konkluzje

Swift 4.1 przyniósł więcej nowości u usprawnień, z mojego punktu widzenia te dwie wydały się najbardziej użyteczne w codziennej pracy i w zasadzie nadają się do zastosowania od zaraz.

Więcej o zmianach w aktualizacji do Swift 4.1 do poczytania na oficjalnej stronie projektu tutaj 👉 https://swift.org/blog/swift-4-1-release-process/

Uff… dotrwałeś do końca! Jeśli ten artykuł był dla Ciebie pomocny to daj proszę znać w komentarzu lub prywatnie na social media 😅! Będę bardzo wdzięczny za każdą przychylną i mniej przychylną opinię, żeby tworzyć jeszcze lepszy kontent dla Ciebie.

Tymczasem dzięki za przeczytania i zapraszam do pogadania:

Twitter

Instagram

Snapchat

Lub wpadnij na fanpage na Facebook’u!

Dzięki i do następnego wpisu!

@jkornat

Kategorie: Swift

2 Komentarze

Mari95 · Kwiecień 12, 2018 o 21:27

Swift 4.1 wprowadził tez decodong strategy dla Decodable, ale rozumiem tez ze te zmiany były dla Ciebie najważniejsze. Możesz opisać wszystkie zmiany w 4.1?

    Jakub Kornatowski

    Jakub Kornatowski · Kwiecień 14, 2018 o 18:21

    Cześć! Dzięki za Twój komentarz.
    Tak, dla mnie te zmiany opisane tutaj są praktyczne, gotowe do implementacji zaraz po aktualizacji MacOS i Xcode.
    Co do opisu reszty… już teraz pewnie nie ma sensu na wzgląd na Swift 5 w czerwcu na WWDC 😁.
    Odsyłam do Paul’a Hudsona, który w momencie wyjścia ładnie wyłożył zmiany ➡️ https://www.hackingwithswift.com/articles/50/whats-new-in-swift-4-1

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *