Swift 4.0 kontra Swift 3.0 – różnice i nowe funkcje
Opublikowany: 2021-10-05Uderzył w nas dzień, w którym Apple wypuszcza nową wersję znanego języka Swift. Czego powinniśmy się po nim spodziewać? Drżąc w oczekiwaniu, postanowiliśmy przedstawić mały przegląd świeżych aktualizacji, które pojawią się w wersji Swift 4 .
3 kamienie węgielne Swifta.
Jako fantastyczny język do pisania kodu, Swift ma swoje zalety i twierdzi się, że „przeżył” język Objective-C.
Zapraszamy do zapoznania się z głównymi różnicami między Swiftem a Objective-C
Swift jest szybki , bezpieczny w pisaniu i bardzo wyrazisty . Można go wykorzystać do pisania oprogramowania na telefony i tablety, komputery stacjonarne i serwery - najwyraźniej na wszystkim, co uruchamia kod. Zachęca do zabawy – dzięki aplikacji Apple do nauki programowania Swift Playgrounds lub Playgrounds w Xcode możesz natychmiast zobaczyć wyniki swojej pracy, bez konieczności wkładania nosa w tworzenie i uruchamianie aplikacji na pierwsze miejsce. Z każdą nową wersją dodatków staje się lepszy i szybszy, tak jest w przypadku wersji Swift 4.
Gotowy na stałe?
Kolejna świetna funkcja, którą Xcode 9 posiada dla Swift 4 - nie musisz się zbytnio martwić nadchodzącą migracją, a dowiesz się dlaczego czytając ten artykuł.
Skoro o tym mowa, przyjrzyjmy się pokrótce, jakie bombonierki i nowe funkcje Swift 4 przyniosą nam tej jesieni.
Pierwsze kroki
Sam język nie jest zbyt przydatny bez poręcznego IDE, jakim jest Xcode w świecie deweloperów. Możesz pobrać najnowszą wersję Xcode 9 z Mac App Store lub ze strony Pobieranie w witrynie Apple Developer, ale najpierw upewnij się, że masz aktywne konto programisty. Jest dość stabilny, więc możesz zastąpić nim Xcode 8 w codziennych procedurach kodowania.
Możesz także zainstalować wiele wersji Xcode za pomocą xcversion
Jeśli zaczynasz nowy projekt - dobrze jest iść. Ale jeśli masz już projekt napisany w Swift 3.x - musisz przejść przez proces migracji.
Zalecamy najpierw wypróbować na Placu Zabaw - aby przyzwyczaić się do korzystania z nowych funkcji.
Podczas czytania tego artykułu zauważysz linki do propozycji Swift Evolution w formacie „SE-____” .
Migracja do Swift 4
Migracja z jednej głównej wersji Swift do następnej zawsze była dość intensywna, zwłaszcza z Swift 2.x do 3.0. Zwykle zajmuje to około 1-2 dni na projekt, ale migracja do Swift 4 jest nieco łatwiejsza i można ją przejść znacznie szybciej.
Przygotowanie przed migracją
Xcode 9 obsługuje nie tylko Swift 4, ale także przejściową wersję 3.2, więc Twój projekt powinien się skompilować bez większych trudności. Jest to możliwe, ponieważ kompilator i narzędzie do migracji Swift 4 obsługują obie wersje języka. Możesz określić różne wersje Swift na cel, jest to bardzo pomocne, jeśli niektóre biblioteki innych firm nie zostały jeszcze zaktualizowane lub jeśli masz wiele celów w swoim projekcie. Jednak nie tylko język, ale także SDK ma pewne zmiany, więc jest bardzo prawdopodobne, że niektóre aktualizacje będą musiały zostać zastosowane w twoim kodzie, ponieważ Apple kontynuuje porządkowanie interfejsów API SDK...
Narzędzie do szybkiej migracji
Jak zawsze, Apple zapewnia narzędzie do migracji Swift dołączone do Xcode, które może pomóc w migracji z poprzedniej wersji Swift. Możesz uruchomić go w Xcode, przechodząc do Edycja -> Konwertuj -> Do bieżącej składni Swift… i wybierając cele, które chcesz przekonwertować.
Następnie zostaniesz zapytany, którą preferencję wnioskowania celu C chcesz zastosować:
Ponieważ zmiany addytywne dominują w Swift 4, narzędzie do migracji Swift będzie zarządzać większością zmian za Ciebie.
CocoaPods
Większość programistów używa menedżera zależności CocoaPods do swoich projektów, ponieważ Swift Package Manager nie jest tak dojrzały, jak mógłby być, chociaż bardzo szybko się poprawia. Jak wspomniano powyżej, nie wszystkie biblioteki innych firm zostały jeszcze zaktualizowane do Swift 4, więc podczas kompilacji niektórych z nich można było zobaczyć błędy. Jednym z możliwych rozwiązań tego problemu jest określenie Swift w wersji 3.2
dla tych post_install
które nie zostały jeszcze zaktualizowane poprzez dodanie skryptu post_install
do Podfile
:
old_swift_3_pods = [ 'PodName1', 'PodName2', ] post_install do |installer| installer.pods_project.targets.each do |target| if old_swift_3_pods.include? target.name target.build_configurations.each do |config| config.build_settings['SWIFT_VERSION'] = '3.2' end end end end
Następnie uruchomić
pod install
Teraz możesz kompilować pody bez błędów.
Przyjrzyjmy się zmianom i dodatkom Swift 4 API.
Zmiany i dodatki API
Smyczki
String
jest teraz zgodny z protokołem Collection
dzięki propozycji SE-0163. Pamiętasz Swifta 1.x?
Nie ma teraz potrzeby stosowania characters
tablicy characters
ponieważ możesz bezpośrednio iterować po String
:
let string = "Hello, Mind Studios!" for character in string { print(character) }
Oznacza to również, że możesz używać dowolnych metod i właściwości Collection
na String
, takich jak count
, isEmpty
, map()
, filter()
, index(of:)
i wielu innych:
string.count // No more `string.characters.count` string.isEmpty // false let index = string.index(of: " ") // 6 let reversedCollection = "abc".reversed() let reversedString = String(reversedCollection) // "cba" // String filtering let string = "ni123n456iniASijasod! 78a9-kasd aosd0" let numbersString = string.filter { Int(String($0)) != nil } // "1234567890"
Nowy typ Substring
Swift 4 wprowadza nowy typ Substring
który reprezentuje podsekwencję String
(jak opisano w SE-0163 wspomnianym powyżej).
// Split string into substrings let string = "Hello, Mind Studios!" let parts = string.split(separator: " ") // ["Hello,", "Mind", "Studios!"] type(of: parts.first!) // Substring.Type
Zarówno String
i Substring
teraz wspierać nową StringProtocol
co czyni je niemal identyczne i interoperacyjne:
var hello = parts.first! // Concatenate a String onto a Substring hello += " !" // "Hello, !" // Create a String from a Substring let helloDog = String(hello) // "Hello, !"
Ważna uwaga
SE-0163 ma bardzo ważną uwagę:
Long-term storage of `Substring` instances is discouraged. A substring holds a reference to the entire storage of a larger string, not just to the portion it presents, even after the original string's lifetime ends. Long-term storage of a substring may therefore prolong the lifetime of elements that are no longer otherwise accessible, which can appear to be memory leakage.
Oznacza to, że Substring
ma być używany jako tymczasowy magazyn dla podsekwencji String
. Jeśli chcesz przekazać go do jakichś metod lub innych klas - najpierw przekonwertuj go na String
:
let substring: Substring = ... // Substring let string = String(substring) // String someMethod(string)
W każdym razie system typów Swifta pomoże ci nie przekazywać Substring
gdzieś, gdzie oczekiwany jest String
(zakładając, że nie używasz nowego StringProtocol
jako typu parametru).
Wielowierszowe literały ciągów
SE-0168 wprowadza prostą składnię dla wielowierszowych literałów łańcuchowych przy użyciu trzech podwójnych cudzysłowów """
co oznacza, że większość formatów tekstowych (takich jak JSON lub HTML) lub niektóre długie teksty można wkleić bez żadnego znaku ucieczki:
let multilineString = """ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam mattis lorem et leo laoreet fermentum. Mauris pretium enim ac mi tempor viverra et fermentum nisl. Sed diam nibh, posuere non lectus at, ornare bibendum erat. Fusce mattis sem ac feugiat vulputate. Morbi at nunc maximus, vestibulum orci et, dictum neque. Vestibulum vulputate augue ac libero vulputate vestibulum. Nullam blandit et sapien non fermentum. Proin mollis nisl at vulputate euismod. """
Unikanie znaków nowej linii w literałach łańcuchowych
SE-0182 dodaje możliwość zmiany znaku nowej linii w wieloliniowych literałach łańcuchowych z odwrotnym ukośnikiem na końcu linii.
let escapedNewline = """ Line 1, Line 2 \ next part of line 2, Line 3 """ print(escapedNewline)
Line 1, Line 2 next part of line 2, Line 3
Ulepszona obsługa Unicode
Swift 4 zapewnia obsługę Unicode 9, co oznacza, że problemy z liczeniem znaków Unicode zniknęły:
"".count // 1, in Swift 3: 2 "".count // 1, in Swift 3: 2 "".count // 1, in Swift 3: 2 - person + skin tone "".count // 1, in Swift 3: 4 "".count // 3, in Swift 3: 1
Wszystkie wymienione powyżej zmiany i wdrożone propozycje (podobnie jak wiele innych) wywodzą się z szeroko opisanego zestawu funkcji zwanego Manifestem smyczkowym.
Kontrola dostępu
Swift 3 wprowadził bardzo sprzeczny element do kontroli dostępu - modyfikator dostępu fileprivate
który może być naprawdę mylący.
Wcześniej modyfikator poziomu dostępu private
był używany do ukrywania elementów członkowskich typu przed innymi typami, a do prywatnych elementów członkowskich można było uzyskać dostęp tylko za pomocą metod i właściwości zdefiniowanych w definicji typu, pozostawiając te same rozszerzenia typu na bok, ponieważ nie mogą uzyskać dostępu do tych elementów członkowskich.
fileprivate
może służyć do współdzielenia dostępu dla członków typu, takich jak właściwości i metody, w tym samym pliku.
W rzeczywistości użycie private
prowadziło do problemu, gdy rozszerzenia na niektórych typach nie miały dostępu do członków tego typu, więc użycie fileprivate
w takich okolicznościach było bardzo powszechnym rozwiązaniem, co doprowadziło do innego problemu: inne typy w ten sam plik może również uzyskać dostęp do tych członków.
Swift 4 porządkuje, zezwalając rozszerzeniom typu na dostęp do private
członków tego typu w tym samym pliku, jak opisano w SE-0169:
struct User { private let firstName: String private let lastName: String } extension User: CustomStringConvertible { var description: String { return "User: \(firstName) \(lastName)" } }
Słownik i zestaw
Inicjalizacja Dictionary
z Sequence
Dictionary
można teraz zainicjować za pomocą Sequence
, ale nie wszystkie sekwencje mogą być przekazywane w tym inicjatorze, tylko te zawierające krotki (Key, Value)
, gdzie Key
jest typem klucza Dictionary, a Value
reprezentuje typ wartości Dictionary:
let stocksIdentifiers = ["AAPL", "GOOGL", "NKE"] let stocksValues = [158.28, 940.13, 53.73] let pairs = zip(stocksIdentifiers, stocksValues) let stocksValuesDict = Dictionary(uniqueKeysWithValues: pairs) // ["GOOGL": 940.13, "NKE": 53.73, "AAPL": 158.28]
Tutaj funkcja zip
tworzy parę ( Tuple
s) z 2 sekwencji, możesz przeczytać więcej o tej funkcji w dokumentacji Swift Standard Library.
Scalanie słowników
Możesz określić sposób obsługi zduplikowanych kluczy podczas tworzenia słownika z sekwencji Tuple
, przekazując zamknięcie do parametru uniquingKeysWith
, który służy do łączenia wartości z 2 identycznych kluczy.
Przykład 1:
let duplicates = [("a", 1), ("b", 5), ("a", 3), ("b", 3)] let dictionary = Dictionary(duplicates, uniquingKeysWith: { (first, _) in return first }) // ["b": 5, "a": 1]
Tutaj zostawiamy pierwszą wartość ignorując wszystkie następne wartości z tym samym kluczem.
Przykład 2:
Zliczanie, ile razy każdy znak pojawia się w ciągu.
let string = "Hello!" let pairs = Array(zip(string, repeatElement(1, count: string.count))) let counts = Dictionary(pairs, uniquingKeysWith: +) // ["H": 1, "e": 1, "o": 1, "l": 2, "!": 1]
Przykład 3:
Za pomocą metody merge
:
let values = ["a": 1, "b": 5] var additionalValues = ["b": 3, "c": 2, "a": 3] additionalValues.merge(values, uniquingKeysWith: +) // ["b": 8, "c": 2, "a": 4]
Indeks dolny z wartością domyślną
Wcześniej powszechną praktyką było używanie operatora łączenia nil w celu podania wartości domyślnej w przypadku, gdy wartość ta wynosi zero.
Szybki 3:
let dict = ["a": 1, "b": 5] dict["c"] ?? 0 // 0
Swift 4 wprowadza nową default
wartość indeksów dolnych (część SE-0165):
let dict = ["a": 1, "b": 5] dict["c", default: 0] // 0, equals to `dict["c"] ?? 0` in Swift 3
Możesz także zmutować słownik, jednocześnie dodając do niego wartość domyślną:
let string = """ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam mattis lorem et leo laoreet fermentum. Mauris pretium enim ac mi tempor viverra et fermentum nisl. Sed diam nibh, posuere non lectus at, ornare bibendum erat. Fusce mattis sem ac feugiat vulputate. Morbi at nunc maximus, vestibulum orci et, dictum neque. Vestibulum vulputate augue ac libero vulputate vestibulum. Nullam blandit et sapien non fermentum. Proin mollis nisl at vulputate euismod. """ var wordsCountByLine = [Int: Int]() let lines = string.split(separator: "\n") for (index, line) in lines.enumerated() { let lineWordsCount = line.split(separator: " ").count wordsCountByLine[index, default: 0] += lineWordsCount } print(wordsCountByLine) // [2: 10, 4: 15, 5: 7, 6: 6, 7: 6, 0: 8, 1: 7, 3: 10]
Mapa i filtr specyficzny dla słownika
Grupowanie elementów sekwencji
Ograniczone typy skojarzone w protokołach
Propozycja SE-0142 wprowadza dodanie klauzul warunkowych do powiązanych deklaracji typu.
extension Sequence where Element: Numeric { var sum: Element { var result: Element = 0 for element in self { result += element } return result } } [1,2,3,4].sum
Archiwizacja i serializacja (kodowanie/dekodowanie)
Wcześniej, w celu serializacji jakiegoś niestandardowego typu, trzeba było użyć starego i dobrze znanego protokołu NSCoding
. Problem polega na tym, że typy struct
takie jak struct
i enum
nie mogą być zgodne z tym protokołem, więc programiści nie mieli nic innego do roboty niż użycie hacków, takich jak zapewnienie dodatkowej warstwy zgodności poprzez utworzenie zagnieżdżonej klasy, która mogłaby być zgodna z NSCoding
.
Swift 4 ma bardzo wygodne rozwiązanie tego problemu dzięki SE-0166 - wprowadzenie protokołu Codable
:
struct Employee: Codable { let name: String let age: Int let role: Role enum Role: String, Codable { case manager case developer case admin } } struct Company { let name: String let officeLocation: Location? let employees: [Employee] } struct Location : Codable { let latitude: Double let longitude: Double }
W prostym przypadku, takim jak ten, wystarczy dodać Codable
protokołu Codable
do wszystkich niestandardowych typów, kompilator zrobi za Ciebie całą magię. Otóż to!
Codable
jest typealias
dla kompozycji protokołów Decodable
& Encodable
, dzięki czemu można na przykład zadeklarować tylko Decodable
protokołu Decodable
, jeśli chcesz zdekodować instancję typu z danych JSON.
Kodowanie
Jeśli chcesz serializować lub deserializować wartość Codable
— musisz użyć obiektu i kodera lub dekodera. Swift 4 zawiera już zestaw koderów/dekoderów dla JSON i list właściwości, a także nowe CocoaError
dla różnych typów błędów, które mogą zostać CocoaError
podczas kodowania/dekodowania. NSKeyedArchiver
i NSKeyedUnarchiver
obsługują również typy Codable
.
let employee = Employee(name: "Peter", age: 27, role: .manager) let company = Company(name: "Awesome Company", officeLocation: nil, employees: [employee]) let encoder = JSONEncoder() let companyData = try encoder.encode(company) let string = String(data: companyData, encoding: .utf8)! print(string) >>> { "name" : "Awesome Company", "employees" : [ { "name" : "Peter", "age" : 27, "role" : "manager" } ] }
Kawałek ciasta, prawda?
Rozszyfrowanie
Dekoder służy do deserializacji niestandardowego typu Codable
z Data
. Nie wie, jaki typ dekodować z samych danych, więc należy określić, jaki typ dekodować, na przykład Employee
lub [Employee]
:
let decoder = JSONDecoder() let jsonData = """ [ { "name" : "Peter", "age" : 27, "role" : "manager" }, { "name" : "Alex", "age" : 26, "role" : "developer" }, { "name" : "Eugene", "age" : 30, "role" : "admin" } ] """.data(using: .utf8)! let employees = try decoder.decode([Employee].self, from: jsonData)
If one of `Codable` type instances fails to decode, then whole collection will fail to decode.
Niestandardowe nazwy kluczy
W większości przypadków nazwy używane w niestandardowych typach Swift nie pasują do kluczy w danych JSON, które reprezentują ten typ. Aby utworzyć mapowanie między niestandardowymi nazwami właściwości typu a kluczami JSON, możesz utworzyć zagnieżdżone wyliczenie o nazwie CodingKeys
które powinno być zgodne z protokołem CodingKey
:
struct Country: Decodable { let id: String let name: String let phoneCode: String private enum CodingKeys: String, CodingKey { case id = "alpha3" case name case phoneCode = "phone_code" } }
Dekodowanie niestandardowe
Jeśli masz złożony przypadek, możesz zaimplementować niestandardowy inicjator z protokołu Decodable
:
struct Transaction { let id: Int let action: String let source: String let amount: Int let state: TransactionState let createdAt: Date let authorName: String enum TransactionState: String, Decodable { case done case canceled case processed } } extension Transaction: Decodable { private enum CodingKeys: String, CodingKey { case id case action = "action_name" case source = "source_name" case amount case state case createdAt = "created_at" case author } private enum AuthorKeys: String, CodingKey { case fullName = "full_name" } init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) id = try container.decode(Int.self, forKey: .id) actionName = try container.decode(String.self, forKey: .action) sourceName = try container.decode(String.self, forKey: .source) let createdAtValue = try container.decode(Double.self, forKey: .createdAt) createdAt = Date(timeIntervalSince1970: createdAtValue) state = try container.decode(TransactionState.self, forKey: .state) amount = try container.decodeIfPresent(Int.self, forKey: .amount) ?? 0 do { let authorContainer = try container.nestedContainer(keyedBy: AuthorKeys.self, forKey: .author) authorName = try authorContainer.decode(String.self, forKey: .fullName) } catch { authorName = "" } } }
Kodowanie klucza wartości
Jedną z przydatnych funkcji oferowanych przez Swift 4 są inteligentne ścieżki klawiszy opisane w SE-0161. W przeciwieństwie do Swift 3 #keyPath()
, który nie jest silnie wpisany i działa tylko dla elementów członkowskich celu C, Swift 4 KeyPath jest klasą ogólną, co oznacza, że ścieżki kluczy są teraz silnie wpisane. Przyjrzyjmy się kilku przykładom:
struct User { var username: String }
Ogólna forma ścieżki klucza \<Type>.<path>
, gdzie <Type>
to nazwa typu, a <path>
to łańcuch co najmniej jednej właściwości, na przykład \User.username
:
let user = User(username: "max") let username = user[keyPath: \User.username] // "max"
Możesz również napisać nową wartość tą ścieżką klucza, jeśli jest zmienna:
var user = User(username: "max") user[keyPath: \User.username] = "alex" // "alex"
Kluczowe ścieżki nie są ograniczone do jednego poziomu hierarchii:
struct Comment { let content: String var author: User } let max = User(username: "max") let comment = Comment(content: "Nice post!", author: max) let authorUsername = comment[keyPath: \Comment.author.username] // "max"
Ścieżki kluczy mogą być przechowywane w zmiennej:
let authorKeyPath = \Comment.author let usernameKeyPath = authorKeyPath.appending(path: \.username) let authorUsername = comment[keyPath: usernameKeyPath] // "max"
Możesz również użyć ścieżek kluczowych dla właściwości opcjonalnych i obliczanych:
struct Post { let title: String var comments: [Comment] var topComment: Comment? { return comments.first } } let max = User(username: "max") let alex = User(username: "alex") var post = Post(title: "What's new in Swift 4", comments: []) let topCommentAuthorUsernameKeyPath = \Post.topComment?.author.username post[keyPath: topCommentAuthorUsernameKeyPath] // nil let comment = Comment(content: "", author: alex) let anotherComment = Comment(content: "Nice post!", author: max) post.comments = [comment, anotherComment] post[keyPath: topCommentAuthorUsernameKeyPath] // "alex"
Pomimo tego, że SE-0161 podkreśla wsparcie indeksów w kluczowych ścieżkach, nie zostały one jeszcze zaimplementowane:
post.comments[keyPath: \.[0].content] // error: key path support for subscript components is not implemented let firstCommentAuthorKeyPath = \Post.comments[0].author // error: key path support for subscript components is not implemented
KVO
Oprócz nowych ścieżek kluczy, w Swift 4 zaktualizowano również interfejs API do obserwacji wartości klucz-wartość.
New KVO APIs depend on Objective-C runtime and works for `NSObject` subclasses only, so it can't be used for Swift structs and classes which don't inherit `NSObject`. In order to observe property it should be marked as `@objc dynamic var`.
class User: NSObject { @objc dynamic var name: String var username: String init(name: String, username: String) { self.name = name self.userName = userName super.init() } } let user = User(name: "Max", username: "max") let nameObservation = user.observe(\.name, options: [.new, .old]) { user, change in // NSKeyValueObservation if let oldValue = change.oldValue, let newValue = change.newValue { print("fullName has changed from \(oldValue) to \(newValue)") } else { print("fullName is now \(user.name)") } } user.name = "Alex" // name has changed from Max to Alex
Wywołaj metodę invalidate()
jeśli chcesz zatrzymać obserwację
nameObservation.invalidate() user.name = "Elina" // observer isn't get called
Jest również zatrzymywany po deinicjacji, więc upewnij się, że przechowujesz go w nieruchomości lub w innym miejscu, jeśli chcesz go zachować.
Zakresy jednostronne
SE-0172 wprowadza "jednostronne" zakresy, tworzone za pomocą wersji prefiksowych/postfiksowych istniejących operatorów zakresu oraz nowy protokół RangeExpression
, aby uprościć tworzenie metod, które przyjmują różne rodzaje zakresów.
Nieskończone sekwencje
Możesz użyć jednostronnego zakresu do skonstruowania nieskończonego ciągu:
let letters = ["a", "b", "c", "d"] let numberedLetters = Array(zip(1..., letters)) // [(1, "a"), (2, "b"), (3, "c"), (4, "d")]
let string = "Hello, Mind Studios!" let index = string.index(of: ",")! string[..<index] // "Hello" string[...index] // "Hello,"
Stosowanie zakresów jednostronnych w dopasowywaniu wzorców
let value = 5 switch value { case 1...: print("greater than zero") case 0: print("zero") case ..<0: print("less than zero") default: break }
Ogólne indeksy
SE-0148 Indeksy dolne mogą teraz mieć ogólne argumenty i typy zwracane
struct JSON { let data: [String: Any] subscript<T>(key: String) -> T? { return data[key] as? T } } let jsonDictionary: [String: Any] = [ "name": "Ukraine", "flag": "", "population": 42_500_000 ] let json = JSON(data: jsonDictionary) let population: Int? = json["population"] // 42500600
extension Dictionary where Value == String { subscript<T: RawRepresentable>(key: Key) -> T? where T.RawValue == Value { guard let string = self[key] else { return nil } return T(rawValue: string) } } enum Color: String { case red case green case blue } let dictionary = [1: "red"] let color: Color? = dictionary[1] // red
Ograniczanie wnioskowania celu C
Swift 4 minimalizuje wnioskowanie @objc, ograniczając je tylko do tych przypadków, w których deklaracja musi być dostępna dla celu C (SE-0160).
Zmniejsza to rozmiar binarny aplikacji przez nie kompilowanie nadmiarowego kodu celu C, jeśli go nie używasz, i daje większą kontrolę nad tym, kiedy zostanie wywnioskowany @objc. Klasy pochodne NSObject nie wywnioskują już @objc.
Ale są sytuacje, w których kod Swift nadal będzie miał domniemane wnioskowanie:
Deklaracje, które mają atrybut @objc
Deklaracje spełniające wymagania protokołu @objc
Deklaracje, które mają atrybuty @IBAction, @IBInspectable, @IBOutlet, @NSManaged, @GKInspectable
Aby włączyć wnioskowanie @objc dla całej klasy, możesz użyć nowego atrybutu @objcmembers.
Aby wyłączyć wnioskowanie @objc dla określonego rozszerzenia lub funkcji — dodaj nowy atrybut @nonobjc.
Komponowanie klas i protokołów
W Swift 4 możemy teraz komponować protokoły razem z innymi typami Swift:
User & Codable & CustomStringConvertible typealias MyType = User & Codable & CustomStringConvertible
Korzyści z Swifta 4.
Zalety Swift 4 są naprawdę ogromne, jak to często bywa, gdy Apple wypuszcza nową wersję językową. Oprócz lepszej wydajności języka, znacznie ustabilizował proces migracji. Wracając myślami do procesu migracji Swift 2.2 do 3.0, przypominamy sobie zawiły proces przenoszenia wszystkich zależności. Zmiany w Swift 4.0 pozwalają nam opuścić biblioteki innych firm bez faktycznego ich „przenoszenia” – wystarczy zaktualizować sam Swift.
Również w odniesieniu do ulepszeń Swift 4.0 vs 3.0 zmieniono rozmiar skompilowanych plików binarnych, co spowodowało zmniejszenie rozmiaru aplikacji; np. aplikacja mobilna kiedyś ważyła 20 MB, aw najnowszej wersji Swift zajmie około 17 MB. I jest podstawowa różnica między Swiftem 4 i Swiftem 3 - naprawiono błąd, a język stał się nieco szybszy.
Minęły lata, odkąd Swift był używany i wciąż ewoluuje z każdą nadchodzącą aktualizacją. Z każdym nowym językiem pojawiają się nowe perspektywy rozwoju, nieznane wcześniej, i nie możemy się doczekać odkrywania nowych horyzontów iOS.
Nie przegap naszego artykułu o MVP vs MVC vs MVVM vs VIPER dla rozwoju iOS.
Napisane przez Maxa Maszkowa i Elinę Bessarabovą .