Swift - szybki przewodnik

Swift 4 to nowy język programowania opracowany przez firmę Apple Inc do tworzenia aplikacji na systemy iOS i OS X. Swift 4 wykorzystuje to, co najlepsze w C i Objective-C, bez ograniczeń kompatybilności C.

  • Swift 4 wykorzystuje bezpieczne wzorce programowania.

  • Swift 4 zapewnia nowoczesne funkcje programowania.

  • Swift 4 zapewnia składnię podobną do Objective-C.

  • Swift 4 to fantastyczny sposób na pisanie aplikacji na iOS i OS X.

  • Swift 4 zapewnia bezproblemowy dostęp do istniejących frameworków Cocoa.

  • Swift 4 ujednolica proceduralne i obiektowe części języka.

  • Swift 4 nie potrzebuje oddzielnego importu biblioteki do obsługi funkcji, takich jak wejście / wyjście lub obsługa ciągów.

Swift 4 używa tego samego środowiska uruchomieniowego, co istniejący system Obj-C w systemach Mac OS i iOS, co umożliwia programom Swift 4 działanie na wielu istniejących platformach iOS 6 i OS X 10.8.

Swift 4 jest wyposażony w funkcję placu zabaw, w której programiści Swift 4 mogą napisać swój kod i wykonać go, aby natychmiast zobaczyć wyniki.

Pierwsza publiczna wersja Swift została wydana w 2010 roku. Zajęło Chris Lattnerprawie 14 lat na opracowanie pierwszej oficjalnej wersji, a później było wspierane przez wielu innych autorów. Swift 4 został dołączony do wersji beta Xcode 6.

Szybcy projektanci wzięli pomysły z różnych innych popularnych języków, takich jak Objective-C, Rust, Haskell, Ruby, Python, C # i CLU.

Konfiguracja środowiska lokalnego

Swift 4 zapewnia platformę Playground do celów edukacyjnych i zamierzamy skonfigurować to samo. Potrzebujesz oprogramowania xCode, aby rozpocząć kodowanie Swift 4 w Playground. Gdy już zaznajomisz się z koncepcjami Swift 4, możesz użyć środowiska xCode IDE do tworzenia aplikacji na iOS / OS x.

Na początek uważamy, że masz już konto w witrynie Apple Developer. Po zalogowaniu przejdź do następującego łącza - Pobierz dla programistów Apple

Spowoduje to wyświetlenie listy dostępnych programów w następujący sposób -

Teraz wybierz xCode i pobierz go, klikając podany link obok obrazu dysku. Po pobraniu pliku dmg można go zainstalować, klikając go dwukrotnie i postępując zgodnie z podanymi instrukcjami. Na koniec postępuj zgodnie z podanymi instrukcjami i upuść ikonę xCode do folderu aplikacji.

Teraz masz zainstalowany xCode na swoim komputerze. Następnie otwórz Xcode z folderu aplikacji i kontynuuj po zaakceptowaniu warunków. Jeśli wszystko jest w porządku, pojawi się następujący ekran -

Wybierz Get started with a playgroundopcję i wprowadź nazwę placu zabaw i wybierz iOS jako platformę. Na koniec otrzymasz okno Playground w następujący sposób -

Poniżej znajduje się kod pobrany z domyślnego okna Swift 4 Playground.

import UIKit
var str = "Hello, playground"

Jeśli utworzysz ten sam program dla programu OS X, będzie on zawierał import Cocoa, a program będzie wyglądał następująco -

import Cocoa
var str = "Hello, playground"

Gdy powyższy program zostanie załadowany, powinien wyświetlić następujący wynik w obszarze wyników Playground (po prawej stronie).

Hello, playground

Gratulacje, masz gotowe środowisko programowania Swift 4 i możesz kontynuować naukę swojego pojazdu „Tutorials Point”.

Widzieliśmy już fragment programu Swift 4 podczas konfigurowania środowiska. Zacznijmy jeszcze raz od następującegoHello, World! program stworzony dla placu zabaw OS X, który zawiera import Cocoa jak pokazano poniżej -

/* My first program in Swift 4 */
var myString = "Hello, World!"

print(myString)

Jeśli utworzysz ten sam program dla placu zabaw iOS, będzie on zawierał import UIKit a program będzie wyglądał następująco -

import UIKit
var myString = "Hello, World!"
print(myString)

Gdy uruchomimy powyższy program na odpowiednim placu zabaw, otrzymamy następujący wynik -

Hello, World!

Przyjrzyjmy się teraz podstawowej strukturze programu Swift 4, aby łatwo było zrozumieć podstawowe elementy składowe języka programowania Swift 4.

Importuj w Swift 4

Możesz użyć importinstrukcja, aby zaimportować dowolną strukturę Objective-C (lub bibliotekę C) bezpośrednio do programu Swift 4. Na przykład powyższeimport cocoa Instrukcja sprawia, że ​​wszystkie biblioteki, interfejsy API i środowiska wykonawcze Cocoa, które tworzą warstwę programistyczną dla całego systemu OS X, są dostępne w języku Swift 4.

Kakao jest zaimplementowane w Objective-C, które jest nadzbiorem języka C, więc łatwo jest mieszać C, a nawet C ++ w aplikacjach Swift 4.

Żetony w Swift 4

Program w języku Swift 4 składa się z różnych tokenów, a token jest słowem kluczowym, identyfikatorem, stałą, literałem ciągu lub symbolem. Na przykład następująca instrukcja Swift 4 składa się z trzech tokenów -

print("test!")
The individual tokens are:
print("test!")

Komentarze

Komentarze są jak teksty pomocnicze w programie Swift 4. Są one ignorowane przez kompilator. Komentarze wieloliniowe zaczynają się od / * i kończą znakami * /, jak pokazano poniżej -

/* My first program in Swift 4 */

Komentarze wielowierszowe mogą być zagnieżdżane w Swift 4. Poniżej znajduje się poprawny komentarz w Swift 4 -

/* My first program in Swift 4 is Hello, World!
/* Where as second program is Hello, Swift 4! */ */

Komentarze jednowierszowe są zapisywane przy użyciu // na początku komentarza.

// My first program in Swift 4

Średniki

Swift 4 nie wymaga wpisywania średnika (;) po każdej instrukcji w kodzie, chociaż jest to opcjonalne; a jeśli użyjesz średnika, to kompilator nie narzeka na to.

Jeśli jednak używasz wielu instrukcji w tym samym wierszu, wymagane jest użycie średnika jako separatora, w przeciwnym razie kompilator zgłosi błąd składni. Powyższe możesz napisać Hello, World! program w następujący sposób -

/* My first program in Swift 4 */
var myString = "Hello, World!"; print(myString)

Identyfikatory

Identyfikator Swift 4 to nazwa używana do identyfikacji zmiennej, funkcji lub dowolnego innego elementu zdefiniowanego przez użytkownika. Identyfikator zaczyna się od alfabetu od A do Z lub od a do z lub podkreślenia _, po którym następuje zero lub więcej liter, podkreślników i cyfr (od 0 do 9).

Swift 4 nie zezwala na znaki specjalne, takie jak @, $ i% w identyfikatorach. Swift 4 tocase sensitivejęzyk programowania. Tak więc Manpower i Manpower to dwa różne identyfikatory w Swift 4. Oto kilka przykładów akceptowanych identyfikatorów -

Azad        zara   abc   move_name   a_123
myname50    _temp  j     a23b9       retVal

Aby użyć zastrzeżonego słowa jako identyfikatora, będziesz musiał umieścić lewy apostrof (`) przed nim i po nim. Na przykład,class nie jest prawidłowym identyfikatorem, ale „class`jest ważny.

Słowa kluczowe

Następujące słowa kluczowe są zarezerwowane w Swift 4. Te zarezerwowane słowa nie mogą być używane jako stałe lub zmienne ani żadne inne nazwy identyfikatorów, chyba że są poprzedzone znakami odwrotnymi -

Słowa kluczowe używane w deklaracjach

Klasa deinit Enum rozbudowa
Func import W tym wewnętrzny
Pozwolić operator prywatny protokół
publiczny statyczny struct indeks
typealias var

Słowa kluczowe użyte w wypowiedziach

przerwa walizka kontyntynuj domyślna
zrobić jeszcze upadek dla
gdyby w powrót przełącznik
gdzie podczas

Słowa kluczowe używane w wyrażeniach i typach

tak jak dynamicType fałszywy jest
zero samego siebie Samego siebie Wspaniały
prawdziwe _KOLUMNA_ _PLIK_ _FUNKCJONOWAĆ_
_LINIA_

Słowa kluczowe używane w określonych kontekstach

asocjatywność wygoda dynamiczny didSet
finał dostać infiks inout
leniwy lewo mutacja Żaden
niemutujący opcjonalny nadpisanie przyrostek
precedens prefiks Protokół wymagany
dobrze zestaw Rodzaj bezpański
słaby ustawi

Białe spacje

Linia zawierająca tylko białe znaki, prawdopodobnie z komentarzem, jest nazywana pustą linią, a kompilator Swift 4 całkowicie ją ignoruje.

Białe znaki to termin używany w języku Swift 4 do opisywania spacji, tabulatorów, znaków nowej linii i komentarzy. Białe spacje oddzielają jedną część instrukcji od drugiej i umożliwiają kompilatorowi określenie, gdzie kończy się jeden element instrukcji, na przykład int, a zaczyna następny element. Dlatego w poniższym oświadczeniu -

var age

Pomiędzy nimi musi znajdować się co najmniej jeden biały znak (zwykle spacja) var i ageaby kompilator mógł je rozróżnić. Z drugiej strony w poniższym stwierdzeniu -

int fruit = apples + oranges   //get the total fruits

Pomiędzy owocami a = lub między = a jabłkami nie są potrzebne żadne spacje, chociaż możesz dołączyć niektóre dla lepszej czytelności.

Przestrzenie po obu stronach operatora powinny być równe, np.

int fruit = apples +oranges    //is a wrong statement
int fruit = apples + oranges   //is a Correct statement

Literały

Literał to reprezentacja w kodzie źródłowym wartości w postaci liczby całkowitej, liczby zmiennoprzecinkowej lub typu łańcuchowego. Poniżej znajdują się przykłady literałów -

92               // Integer literal
4.24159          // Floating-point literal
"Hello, World!"  // String literal

Drukowanie w Swift

Aby szybko coś wydrukować, mamy słowo kluczowe „print”.

Nadruk ma trzy różne właściwości.

Items - Elementy do wydrukowania

Separator - separator między elementami

Terminator - wartość, jaką powinien kończyć wiersz, zobaczmy przykład i składnię tego samego.

print("Items to print", separator: "Value " , terminator: "Value")
// E.g. of print statement.

print("Value one")
// prints "Value one \n" Adds, \n as terminator and " " as separator by
default.

print("Value one","Value two", separator: " Next Value" , terminator: " End")
//prints "Value one Next Value Value two End"

W powyższym kodzie pierwsza instrukcja print dodaje \ n, nową linię Feed jako terminator, gdzie tak jak w drugiej instrukcji print, jako terminator daliśmy "End", stąd wypisze "End" zamiast \ n.

Możemy dostarczyć nasz niestandardowy separator i terminatory zgodnie z naszymi wymaganiami.

Robiąc programowanie w dowolnym języku programowania, musisz używać różnych typów zmiennych do przechowywania informacji. Zmienne to nic innego jak zarezerwowane miejsca w pamięci do przechowywania wartości. Oznacza to, że kiedy tworzysz zmienną, rezerwujesz trochę miejsca w pamięci.

Możesz chcieć przechowywać informacje o różnych typach danych, takich jak ciąg, znak, szeroki znak, liczba całkowita, zmiennoprzecinkowa, logiczna itp. Na podstawie typu danych zmiennej system operacyjny przydziela pamięć i decyduje, co może być przechowywane w zarezerwowanej pamięć.

Wbudowane typy danych

Swift 4 oferuje programiście bogaty asortyment wbudowanych i zdefiniowanych przez użytkownika typów danych. Następujące typy podstawowych typów danych występują najczęściej podczas deklarowania zmiennych -

  • Int or UInt- To jest używane dla liczb całkowitych. Mówiąc dokładniej, można użyć Int32, Int64 do zdefiniowania 32- lub 64-bitowej liczby całkowitej ze znakiem, natomiast UInt32 lub UInt64 do zdefiniowania 32- lub 64-bitowych zmiennych całkowitych bez znaku. Na przykład 42 i -23.

  • Float- Służy do reprezentowania 32-bitowej liczby zmiennoprzecinkowej i liczb z mniejszymi miejscami dziesiętnymi. Na przykład 3,14159, 0,1 i -273,158.

  • Double- Służy do reprezentowania 64-bitowej liczby zmiennoprzecinkowej i jest używany, gdy wartości zmiennoprzecinkowe muszą być bardzo duże. Na przykład 3,14159, 0,1 i -273,158.

  • Bool - reprezentuje wartość logiczną, która jest prawdą lub fałszem.

  • String- To jest uporządkowany zbiór znaków. Na przykład „Hello, World!”

  • Character- To jest jednoznakowy literał ciągu. Na przykład „C”

  • Optional - reprezentuje zmienną, która może zawierać wartość lub nie mieć żadnej wartości.

  • Tuples - Służy do grupowania wielu wartości w pojedynczą wartość złożoną.

Wymieniliśmy tutaj kilka ważnych punktów związanych z typami całkowitymi -

  • Na platformie 32-bitowej Int ma taki sam rozmiar jak Int32.

  • Na platformie 64-bitowej Int ma taki sam rozmiar jak Int64.

  • Na platformie 32-bitowej UInt ma taki sam rozmiar jak UInt32.

  • Na platformie 64-bitowej UInt ma taki sam rozmiar jak UInt64.

  • Int8, Int16, Int32, Int64 mogą służyć do reprezentowania 8-bitowych, 16-bitowych, 32-bitowych i 64-bitowych postaci liczb całkowitych ze znakiem.

  • UInt8, UInt16, UInt32 i UInt64 mogą być używane do reprezentowania 8-bitowych, 16-bitowych, 32-bitowych i 64-bitowych postaci liczb całkowitych bez znaku.

Wartości powiązane

Poniższa tabela pokazuje typ zmiennej, ile pamięci zajmuje przechowywanie wartości w pamięci oraz jaka jest maksymalna i minimalna wartość jaka może być przechowywana w tego typu zmiennych.

Rodzaj Typowa szerokość bitu Typowy zakres
Int8 1 bajt -127 do 127
UInt8 1 bajt Od 0 do 255
Int32 4 bajty Od -2147483648 do 2147483647
UInt32 4 bajty 0 do 4294967295
Int64 8 bajtów -9223372036854775808 do 9223372036854775807
UInt64 8 bajtów 0 do 18446744073709551615
Pływak 4 bajty 1,2E-38 do 3,4E + 38 (~ 6 cyfr)
Podwójnie 8 bajtów 2,3E-308 do 1,7E + 308 (~ 15 cyfr)

Wpisz Aliasy

Możesz utworzyć nową nazwę dla istniejącego typu za pomocą typealias. Oto prosta składnia definiowania nowego typu przy użyciu aliasów typu -

typealias newname = type

Na przykład poniższy wiersz instruuje kompilator, że Feet to inna nazwa Int -

typealias Feet = Int

Teraz poniższa deklaracja jest całkowicie poprawna i tworzy zmienną całkowitą o nazwie odległość -

typealias Feet = Int
var distance: Feet = 100
print(distance)

Uruchamiając powyższy program za pomocą placu zabaw, otrzymujemy następujący wynik.

100

Bezpieczeństwo typów

Swift 4 jest językiem bezpiecznym dla typów, co oznacza, że ​​jeśli część twojego kodu oczekuje String, nie możesz przez pomyłkę przekazać Int.

Ponieważ Swift 4 jest bezpieczny dla typów, sprawdza typy podczas kompilowania kodu i oznacza wszelkie niezgodne typy jako błędy.

var varA = 42
varA = "This is hello"
print(varA)

Kiedy kompilujemy powyższy program, generuje on następujący błąd czasu kompilacji.

main.swift:2:8: error: cannot assign value of type 'String' to type 'Int'
varA = "This is hello"

Wnioskowanie o typie

Wnioskowanie o typie umożliwia kompilatorowi automatyczne wywnioskowanie typu określonego wyrażenia podczas kompilowania kodu, po prostu sprawdzając podane wartości. Swift 4 wykorzystuje wnioskowanie o typie do obliczenia odpowiedniego typu w następujący sposób.

// varA is inferred to be of type Int
var varA = 42
print(varA)

// varB is inferred to be of type Double
var varB = 3.14159
print(varB)

// varC is also inferred to be of type Double
var varC = 3 + 0.14159
print(varC)

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

42
3.14159
3.14159

Zmienna zapewnia nam nazwane miejsce do przechowywania, którym nasze programy mogą manipulować. Każda zmienna w Swift 4 ma określony typ, który określa rozmiar i układ pamięci zmiennej; zakres wartości, które mogą być przechowywane w tej pamięci; oraz zestaw operacji, które można zastosować do zmiennej.

Swift 4 obsługuje następujące podstawowe typy zmiennych -

  • Int or UInt- To jest używane dla liczb całkowitych. Mówiąc dokładniej, można użyć Int32, Int64 do zdefiniowania 32- lub 64-bitowej liczby całkowitej ze znakiem, natomiast UInt32 lub UInt64 do zdefiniowania 32- lub 64-bitowych zmiennych całkowitych bez znaku. Na przykład 42 i -23.

  • Float- Służy do reprezentowania 32-bitowej liczby zmiennoprzecinkowej. Służy do przechowywania liczb z mniejszymi miejscami dziesiętnymi. Na przykład 3,14159, 0,1 i -273,158.

  • Double- Służy do reprezentowania 64-bitowej liczby zmiennoprzecinkowej i jest używany, gdy wartości zmiennoprzecinkowe muszą być bardzo duże. Na przykład 3.14159, 0.1 i -273.158.

  • Bool - reprezentuje wartość logiczną, która jest prawdą lub fałszem.

  • String- To jest uporządkowany zbiór znaków. Na przykład „Hello, World!”

  • Character- To jest jednoznakowy literał ciągu. Na przykład „C”

Swift 4 pozwala także na zdefiniowanie różnych innych typów zmiennych, którymi zajmiemy się w kolejnych rozdziałach, jak np Optional, Array, Dictionaries, Structures, i Classes.

W poniższej sekcji opisano, jak deklarować i używać różnych typów zmiennych w programowaniu w języku Swift 4.

Deklaracja zmiennej

Deklaracja zmiennej informuje kompilator, gdzie i ile ma utworzyć magazyn dla zmiennej. Zanim użyjesz zmiennych, musisz zadeklarować je używającvar słowo kluczowe w następujący sposób -

var variableName = <initial value>

Poniższy przykład pokazuje, jak zadeklarować zmienną w Swift 4 -

var varA = 42
print(varA)

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

42

Typ Adnotacje

Możesz podać plik type annotationkiedy deklarujesz zmienną, aby mieć jasność co do rodzaju wartości, które zmienna może przechowywać. Oto składnia -

var variableName:<data type> = <optional initial value>

Poniższy przykład pokazuje, jak zadeklarować zmienną w Swift 4 przy użyciu Annotation. W tym miejscu należy zauważyć, że jeśli nie używamy adnotacji typu, obowiązkowe staje się podanie wartości początkowej zmiennej, w przeciwnym razie możemy po prostu zadeklarować naszą zmienną za pomocą adnotacji typu.

var varA = 42
print(varA)

var varB:Float

varB = 3.14159
print(varB)

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

42
3.1415901184082

Nazewnictwo zmiennych

Nazwa zmiennej może składać się z liter, cyfr i znaku podkreślenia. Musi zaczynać się od litery lub podkreślenia. Wielkie i małe litery są różne, ponieważ Swift 4 jest językiem programowania uwzględniającym wielkość liter.

Do nazwania zmiennych można używać znaków prostych lub znaków Unicode. Poniższe przykłady pokazują, jak można nazwać zmienne -

var _var = "Hello, Swift 4!"
print(_var)

var 你好 = "你好世界"
print(你好)

Uruchamiając powyższy program za pomocą placu zabaw, otrzymujemy następujący wynik.

Hello, Swift 4!
你好世界

Drukowanie zmiennych

Możesz wydrukować bieżącą wartość stałej lub zmiennej za pomocą funkcji print. Możesz interpolować wartość zmiennej, zawijając nazwę w nawiasy i zmieniając ją z ukośnikiem odwrotnym przed nawiasem otwierającym: Poniżej znajdują się prawidłowe przykłady -

var varA = "Godzilla"
var varB = 1000.00

print("Value of \(varA) is more than \(varB) millions")

Uruchamiając powyższy program za pomocą placu zabaw, otrzymujemy następujący wynik.

Value of Godzilla is more than 1000.0 millions

Swift 4 wprowadza również Optionalstyp, który obsługuje brak wartości. Opcjonalne opcje mówią „istnieje wartość i równa się x” lub „nie ma żadnej wartości”.

Opcjonalny jest typem sam w sobie, a właściwie jednym z nowych wyliczeń o dużej mocy w Swift 4. Ma dwie możliwe wartości,None i Some(T), gdzie T jest skojarzoną wartością prawidłowego typu danych dostępną w Swift 4.

Oto opcjonalna deklaracja liczby całkowitej -

var perhapsInt: Int?

Oto opcjonalna deklaracja String -

var perhapsStr: String?

Powyższa deklaracja jest równoważna jawnemu zainicjowaniu jej do nil co oznacza brak wartości -

var perhapsStr: String? = nil

Weźmy następujący przykład, aby zrozumieć, jak działają opcje w Swift 4 -

var myString:String? = nil

if myString != nil {
   print(myString)
} else {
   print("myString has nil value")
}

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

myString has nil value

Opcje są podobne do using nil ze wskaźnikami w Objective-C, ale działają dla każdego typu, nie tylko dla klas.

Wymuszone rozpakowanie

Jeśli zdefiniowałeś zmienną jako optional, aby uzyskać wartość z tej zmiennej, będziesz musiał unwrapto. Oznacza to po prostu umieszczenie wykrzyknika na końcu zmiennej.

Weźmy prosty przykład -

var myString:String?

myString = "Hello, Swift 4!"

if myString != nil {
   print(myString)
} else {
   print("myString has nil value")
}

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

Optional("Hello, Swift 4!")

Teraz zastosujmy rozpakowywanie, aby uzyskać poprawną wartość zmiennej -

var myString:String?

myString = "Hello, Swift 4!"

if myString != nil {
   print( myString! )
} else {
   print("myString has nil value")
}

Uruchamiając powyższy program za pomocą placu zabaw, otrzymujemy następujący wynik.

Hello, Swift 4!

Automatyczne rozpakowywanie

Możesz zadeklarować zmienne opcjonalne, używając wykrzyknika zamiast znaku zapytania. Takie opcjonalne zmienne rozpakują się automatycznie i nie ma potrzeby używania żadnego dodatkowego wykrzyknika na końcu zmiennej, aby uzyskać przypisaną wartość. Weźmy prosty przykład -

var myString:String!
myString = "Hello, Swift 4!"

if myString != nil {
   print(myString)
} else {
   print("myString has nil value")
}

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

Hello, Swift 4!

Opcjonalne wiązanie

Użyj opcjonalnego powiązania, aby dowiedzieć się, czy opcja opcjonalna zawiera wartość, a jeśli tak, aby udostępnić tę wartość jako tymczasową stałą lub zmienną.

Opcjonalne wiązanie dla if oświadczenie jest następujące -

if let constantName = someOptional {
   statements
}

Weźmy prosty przykład, aby zrozumieć użycie opcjonalnego wiązania -

var myString:String?
myString = "Hello, Swift 4!"

if let yourString = myString {
   print("Your string has - \(yourString)")
} else {
   print("Your string does not have a value")
}

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

Your string has - Hello, Swift 4!

Swift 4 wprowadza również Tuples type, które są używane do grupowania wielu wartości w jednej wartości złożonej.

Wartości w krotce mogą być dowolnego typu i nie muszą być tego samego typu.

Na przykład („Tutorials Point”, 123) jest krotką z dwiema wartościami, jedną typu string, a drugą typu integer. To jest legalne polecenie.

let ImplementationError = (501, "Nie zaimplementowano") jest błędem, gdy coś na serwerze nie jest zaimplementowane, zwraca dwie wartości. Kod i opis błędu.

Możesz tworzyć krotki z dowolnej liczby wartości iz dowolnej liczby różnych typów danych.

Oto składnia deklaracji krotki -

var TupleName = (Value1, value2,… any number of values)

Oto deklaracja krotki -

var error501 = (501, “Not implemented”)

Dostęp do wartości krotki można uzyskać, używając numerów indeksów zaczynających się od 0.

Oto przykład uzyskiwania dostępu do wartości krotek -

print(“The code is\(error501.0)”)
print(“The definition of error is\(error501.1)”)

Podczas deklarowania można nazwać zmienne krotki i przywołać je, używając ich nazw

var error501 = (errorCode: 501, description: “Not Implemented”)
print(error501.errorCode)   // prints 501.

Krotki są pomocne w zwracaniu wielu wartości z funkcji. Na przykład aplikacja internetowa może zwracać krotkę typu („String”, Int), aby pokazać, czy ładowanie się powiodło, czy nie.

Zwracając różne wartości w krotce, możemy podejmować decyzje w zależności od różnych typów krotek.

Note - Krotki są przydatne w przypadku wartości tymczasowych i nie nadają się do złożonych danych.

Stałe odnoszą się do stałych wartości, których program nie może zmieniać podczas wykonywania. Stałe mogą być dowolnego z podstawowych typów danych, takich jak stała całkowita, stała zmiennoprzecinkowa, stała znakowa lub literał ciągu . Istnieją również stałe wyliczania .

Constants są traktowane jak zwykłe zmienne, z wyjątkiem faktu, że ich wartości nie mogą być modyfikowane po ich definicji.

Deklaracja stałych

Zanim użyjesz stałych, musisz zadeklarować je używając let słowo kluczowe w następujący sposób -

let constantName = <initial value>

Poniżej znajduje się prosty przykład pokazujący, jak zadeklarować stałą w języku Swift 4:

let constA = 42
print(constA)

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

42

Typ Adnotacje

Możesz podać plik type annotationkiedy deklarujesz stałą, aby mieć jasność co do rodzaju wartości, które stała może przechowywać. Poniżej znajduje się składnia -

var constantName:<data type> = <optional initial value>

Poniższy przykład pokazuje, jak zadeklarować stałą w Swift 4 przy użyciu Annotation. W tym miejscu należy zauważyć, że podczas tworzenia stałej - obowiązkowe jest podanie wartości początkowej

let constA = 42
print(constA)

let constB:Float = 3.14159
print(constB)

Uruchamiając powyższy program za pomocą placu zabaw, otrzymujemy następujący wynik.

42
3.1415901184082

Stałe nazewnictwa

Nazwa stałej może składać się z liter, cyfr i znaku podkreślenia. Musi zaczynać się od litery lub podkreślenia. Wielkie i małe litery są różne, ponieważ Swift 4 jest językiem programowania uwzględniającym wielkość liter.

Do nazwania zmiennych można używać znaków prostych lub znaków Unicode. Poniżej znajdują się prawidłowe przykłady -

let _const = "Hello, Swift 4!"
print(_const)

let 你好 = "你好世界"
print(你好)

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

Hello, Swift 4!
你好世界

Stałe drukowania

Możesz wydrukować bieżącą wartość stałej lub zmiennej za pomocą printfunkcjonować. Możesz interpolować wartość zmiennej, zawijając nazwę w nawiasy i zmieniając ją z ukośnikiem odwrotnym przed nawiasem otwierającym: Poniżej znajdują się prawidłowe przykłady -

let constA = "Godzilla"
let constB = 1000.00

print("Value of \(constA) is more than \(constB) millions")

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

Value of Godzilla is more than 1000.0 millions

Literał to reprezentacja w kodzie źródłowym wartości w postaci liczby całkowitej, liczby zmiennoprzecinkowej lub typu łańcuchowego. Poniżej znajdują się przykłady literałów -

42                // Integer literal
3.14159           // Floating-point literal
"Hello, world!"   // String literal

Literały całkowite

Literał liczby całkowitej może być stałą dziesiętną, binarną, ósemkową lub szesnastkową. Literały binarne zaczynają się od 0b, literały ósemkowe zaczynają się od 0o, a literały szesnastkowe zaczynają się od 0x i nic dla dziesiętnych.

Oto kilka przykładów literałów całkowitych -

let decimalInteger = 17         // 17 in decimal notation
let binaryInteger = 0b10001     // 17 in binary notation
let octalInteger = 0o21         // 17 in octal notation
let hexadecimalInteger = 0x11   // 17 in hexadecimal notation

Literały zmiennoprzecinkowe

Literał zmiennoprzecinkowy ma część całkowitą, przecinek dziesiętny, część ułamkową i część wykładniczą. Literały zmiennoprzecinkowe można przedstawić w postaci dziesiętnej lub szesnastkowej.

Dziesiętne literały zmiennoprzecinkowe składają się z sekwencji cyfr dziesiętnych, po których następuje ułamek dziesiętny, wykładnik dziesiętny lub oba te elementy.

Szesnastkowe literały zmiennoprzecinkowe składają się z przedrostka 0x, po którym następuje opcjonalny ułamek szesnastkowy, po którym następuje wykładnik szesnastkowy.

Oto kilka przykładów literałów zmiennoprzecinkowych -

let decimalDouble = 12.1875
let exponentDouble = 1.21875e1
let hexadecimalDouble = 0xC.3p0

Literały strunowe

Literał łańcuchowy to sekwencja znaków otoczona podwójnymi cudzysłowami o następującej postaci -

"characters"

Literały łańcuchowe nie mogą zawierać cudzysłowu podwójnego bez znaku zmiany znaczenia ("), ukośnika odwrotnego bez znaku zmiany znaczenia (\), powrotu karetki ani wysuwu wiersza. Znaki specjalne można umieszczać w literałach ciągu przy użyciu następujących sekwencji ucieczki -

Sekwencja ewakuacyjna Znaczenie
\ 0 Znak zerowy
\\ \postać
\b Backspace
\fa Form feed
\ n Nowa linia
\ r Powrót karetki
\ t Zakładka pozioma
\ v Zakładka pionowa
\ ' Pojedynczy cytat
\ " Cudzysłów
\ 000 Liczba ósemkowa składająca się z jednej do trzech cyfr
\ xhh ... Liczba szesnastkowa składająca się z jednej lub więcej cyfr

Poniższy przykład pokazuje, jak używać kilku literałów ciągów -

let stringL = "Hello\tWorld\n\nHello\'Swift 4\'"
print(stringL)

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

Hello World

Hello'Swift 4'

Literały logiczne

Istnieją trzy literały Boolean i są one częścią standardowych słów kluczowych Swift 4 -

  • Wartość true reprezentujące prawdę.

  • Wartość false reprezentujące fałsz.

  • Wartość nil bez wartości.

Operator to symbol, który mówi kompilatorowi, aby wykonał określone operacje matematyczne lub logiczne. Objective-C jest bogaty we wbudowane operatory i zapewnia następujące typy operatorów -

  • Operatory arytmetyczne
  • Operatory porównania
  • Operatory logiczne
  • Operatory bitowe
  • Operatory przypisania
  • Operatorzy zasięgu
  • Różne operatory

Ten samouczek wyjaśni po kolei operatory arytmetyczne, relacyjne, logiczne, bitowe, przypisania i inne.

Operatory arytmetyczne

Poniższa tabela przedstawia wszystkie operatory arytmetyczne obsługiwane przez język Swift 4. Przyjmij zmiennąA posiada 10 i zmienną B mieści 20, a następnie -

Operator Opis Przykład
+ Dodaje dwa operandy A + B da 30
- Odejmuje drugi operand od pierwszego A - B da -10
* Mnoży oba operandy A * B da 200
/ Dzieli licznik przez mianownik B / A da 2
% Operator modułu i reszta z dzielenia liczb całkowitych / zmiennoprzecinkowych B% A da 0

Operatory porównania

Poniższa tabela przedstawia wszystkie operatory relacyjne obsługiwane przez język Swift 4. Przyjmij zmiennąA posiada 10 i zmienną B mieści 20, a następnie -

Operator Opis Przykład
== Sprawdza, czy wartości dwóch operandów są równe, czy nie; jeśli tak, to warunek staje się prawdziwy. (A == B) nie jest prawdą.
! = Sprawdza, czy wartości dwóch operandów są równe, czy nie; jeśli wartości nie są równe, warunek staje się prawdziwy. (A! = B) jest prawdą.
> Sprawdza, czy wartość lewego operandu jest większa niż wartość prawego operandu; jeśli tak, to warunek staje się prawdziwy. (A> B) nie jest prawdą.
< Sprawdza, czy wartość lewego operandu jest mniejsza niż wartość prawego operandu; jeśli tak, to warunek staje się prawdziwy. (A <B) jest prawdą.
> = Sprawdza, czy wartość lewego operandu jest większa lub równa wartości prawego operandu; jeśli tak, to warunek staje się prawdziwy. (A> = B) nie jest prawdą.
<= Sprawdza, czy wartość lewego operandu jest mniejsza lub równa wartości prawego operandu; jeśli tak, to warunek staje się prawdziwy. (A <= B) jest prawdą.

Operatory logiczne

Poniższa tabela przedstawia wszystkie operatory logiczne obsługiwane przez język Swift 4. Przyjmij zmiennąA zawiera 1 i zmienną B posiada 0, a następnie -

Operator Opis Przykład
&& Nazywany operatorem logicznym AND. Jeśli oba operandy są niezerowe, warunek staje się prawdziwy. (A && B) jest fałszem.
|| Nazywany operatorem logicznym OR. Jeśli którykolwiek z dwóch operandów jest niezerowy, warunek staje się prawdziwy. (A || B) jest prawdą.
! Nazywany operatorem logicznym NOT. Służy do odwracania stanu logicznego operandu. Jeśli warunek jest prawdziwy, operator Logiczne NIE spowoduje, że będzie fałszywy. ! (A && B) jest prawdą.

Operatory bitowe

Operatory bitowe działają na bitach i wykonują operacje bit po bicie. Tabele prawdy dla &, | i ^ są następujące -

p q p & q p | q p ^ q
0 0 0 0 0
0 1 0 1 1
1 1 1 1 0
1 0 0 1 1
Assume A = 60; and B = 13;

In binary format, they will be as follows:

A = 0011 1100

B = 0000 1101

-----------------

A & B = 0000 1100

A|B = 0011 1101

A^B = 0011 0001

~A = 1100 0011

Operatory bitowe obsługiwane przez język Swift 4 są wymienione w poniższej tabeli. Przyjmij zmiennąA mieści 60 i zmienną B posiada 13, a następnie 7−

Operator Opis Przykład
& Operator binarny AND kopiuje trochę do wyniku, jeśli istnieje w obu operandach. (A i B) da 12, czyli 0000 1100
| Operator binarny OR kopiuje bit, jeśli istnieje w którymkolwiek z operandów. (A | B) da 61, czyli 0011 1101
^ Binarny operator XOR kopiuje bit, jeśli jest ustawiony w jednym operandzie, ale nie w obu. (A ^ B) da 49, czyli 0011 0001
~ Operator dopełniacza binarnego jest jednoargumentowy i powoduje „odwracanie” bitów. (~ A) da -61, czyli 1100 0011 w postaci dopełnienia 2.
<< Binarny operator przesunięcia w lewo. Wartość lewych operandów jest przesuwana w lewo o liczbę bitów określoną przez prawy operand. (A << 2 da 240, czyli 1111 0000
>> Binarny operator przesunięcia w prawo. Wartość lewego operandu jest przesuwana w prawo o liczbę bitów określoną przez prawy operand. >> 2 da 15, czyli 0000 1111

Operatory przypisania

SSwift 4 obsługuje następujące operatory przypisania -

Operator Opis Przykład
= Prosty operator przypisania, przypisuje wartości z operandów po prawej stronie do operandów po lewej stronie C = A + B przypisze wartość A + B do C.
+ = Dodaj operator przypisania AND, dodaje prawy operand do lewego operandu i przypisuje wynik do lewego operandu C + = A jest równoważne C = C + A
- = Operator odejmowania AND przypisania, odejmuje prawy operand od lewego operandu i przypisuje wynik do lewego operandu C - = A jest równoważne C = C - A
* = Operator mnożenia AND przypisania, mnoży prawy operand z lewym operandem i przypisuje wynik do lewego operandu C * = A jest równoważne C = C * A
/ = Operator dzielenia AND przypisania, dzieli lewy operand z prawym operandem i przypisuje wynik do lewego operandu C / = A jest równoważne C = C / A
% = Operator przypisania modułu AND, pobiera moduł przy użyciu dwóch operandów i przypisuje wynik lewemu operandowi C% = A jest równoważne C = C% A
<< = Operator przesunięcia w lewo AND przypisania C << = 2 to to samo, co C = C << 2
>> = Operator prawego przesunięcia AND przypisania C >> = 2 to to samo, co C = C >> 2
& = Operator przypisania bitowego AND C & = 2 to to samo, co C = C & 2
^ = bitowe wykluczające OR i operator przypisania C ^ = 2 to to samo, co C = C ^ 2
| = bitowy operator OR i przypisanie C | = 2 to to samo, co C = C | 2

Operatorzy zasięgu

Swift 4 zawiera dwa operatory zakresu, które są skrótami do wyrażania zakresu wartości. Poniższa tabela wyjaśnia te dwa operatory.

Operator Opis Przykład
Zakres zamknięty (a ... b) definiuje zakres od a do b i zawiera wartości a i b. 1 ... 5 daje 1, 2, 3, 4 i 5
Zakres półotwarty (a .. <b) definiuje zakres od a do b, ale nie obejmuje b. 1 .. <5 daje 1, 2, 3 i 4
Zakres jednostronny

a… definiuje zakres obejmujący od a do końca elementów

… A, definiuje zakres od początku do a

1… daje 1, 2,3… koniec elementów

… 2 daje początek… 1,2

Różne operatory

Swift 4 obsługuje kilku innych ważnych operatorów, w tym rangei ? : które wyjaśniono w poniższej tabeli.

Operator Opis Przykład
Jednoargumentowy minus Znak wartości liczbowej można przełączać za pomocą przedrostka - -3 lub -4
Unary Plus Zwraca wartość, na której działa, bez żadnych zmian. +6 daje 6
Warunkowe trójskładnikowe Stan: schorzenie ? X: Y Jeśli warunek jest prawdziwy? Wtedy wartość X: W przeciwnym razie wartość Y

Pierwszeństwo operatorów

Pierwszeństwo operatorów określa grupowanie terminów w wyrażeniu. Ma to wpływ na sposób oceny wyrażenia. Niektórzy operatorzy mają wyższy priorytet niż inni; na przykład operator mnożenia ma wyższy priorytet niż operator dodawania.

Na przykład x = 7 + 3 * 2; tutaj x ma przypisane 13, a nie 20, ponieważ operator * ma wyższy priorytet niż +, więc najpierw jest mnożony przez 3 * 2, a następnie sumowany do 7.

Tutaj operatory o najwyższym priorytecie pojawiają się na górze tabeli, a operatory o najniższym priorytecie - na dole. W wyrażeniu najpierw zostaną ocenione operatory o wyższym priorytecie.

Operator Opis Przykład
Podstawowe operatory wyrażeń () []. wyrażenie ++ wyrażenie-- z lewej na prawą
Operatory jednoargumentowe

* & + -! ~ ++ wyrażenie - wyr

* /%

+ -

>> <<

<> <=> =

==! =

od prawej do lewej
Operatory binarne

&

^

|

&&

||

z lewej na prawą
Operator trójskładnikowy ?: od prawej do lewej
Operatory przypisania = + = - = * = / =% = >> = << = & = ^ = | = od prawej do lewej
Przecinek , z lewej na prawą

Struktury decyzyjne wymagają, aby programista określił jeden lub więcej warunków, które mają być ocenione lub przetestowane przez program, wraz z instrukcją lub instrukcjami do wykonania, jeśli warunek zostanie określony jako truei opcjonalnie inne instrukcje do wykonania, jeśli warunek zostanie określony false.

Poniżej znajduje się ogólny zarys typowej struktury podejmowania decyzji występującej w większości języków programowania -

Swift 4 zapewnia następujące rodzaje oświadczeń decyzyjnych. Kliknij poniższe łącza, aby sprawdzić ich szczegóły.

Sr.No Oświadczenie i opis
1 jeśli oświadczenie

Instrukcja if składa się z wyrażenia boolowskiego, po którym następuje co najmniej jedna instrukcja.

2 if ... else oświadczenie

Po instrukcji if może następować opcjonalna instrukcja else, która jest wykonywana, gdy wyrażenie logiczne ma wartość false.

3 if ... else if ... else Instrukcja

Po instrukcji if może następować opcjonalna instrukcja else if ... else, która jest bardzo przydatna do testowania różnych warunków przy użyciu pojedynczej instrukcji if ... else if.

4 zagnieżdżone instrukcje if

Możesz użyć jednej instrukcji if lub else if wewnątrz innej instrukcji if lub else if.

5 instrukcja przełączania

Instrukcja switch umożliwia testowanie zmiennej pod kątem równości względem listy wartości.

The? : Operator

Omówiliśmy conditional operator ? : w poprzednim rozdziale, które można zastąpić if...elsesprawozdania. Ma następującą ogólną postać -

Exp1 ? Exp2 : Exp3;

Gdzie Exp1, Exp2 i Exp3 to wyrażenia. Zwróć uwagę na użycie i położenie okrężnicy.

Wartość? wyrażenie jest określane w następujący sposób: Exp1 jest oceniane. Jeśli to prawda, to Exp2 jest obliczane i staje się wartością całości? wyrażenie. Jeśli Exp1 ma wartość false, to Exp3 jest oceniane, a jego wartość staje się wartością wyrażenia.

Może zaistnieć sytuacja, w której trzeba będzie kilkakrotnie wykonać blok kodu. Ogólnie instrukcje są wykonywane sekwencyjnie: pierwsza instrukcja funkcji jest wykonywana jako pierwsza, po niej następuje druga i tak dalej.

Języki programowania zapewniają różne struktury kontrolne, które pozwalają na bardziej skomplikowane ścieżki wykonywania.

Instrukcja pętli umożliwia wielokrotne wykonanie instrukcji lub grupy instrukcji. Poniżej znajduje się ogólny opis instrukcji pętli w większości języków programowania -

Język programowania Swift 4 zapewnia następujące rodzaje pętli do obsługi wymagań dotyczących pętli. Kliknij poniższe łącza, aby sprawdzić ich szczegóły.

Sr.No Typ i opis pętli
1 dla w

Ta pętla wykonuje zestaw instrukcji dla każdego elementu w zakresie, sekwencji, kolekcji lub progresji.

2 pętla while

Powtarza instrukcję lub grupę instrukcji, gdy dany warunek jest prawdziwy. Testuje warunek przed wykonaniem treści pętli.

3 powtórz ... while pętla

Podobnie jak instrukcja while, z tą różnicą, że testuje warunek na końcu treści pętli.

Instrukcje sterowania pętlą

Instrukcje sterujące pętlą zmieniają wykonanie z jego normalnej sekwencji. Gdy wykonanie opuszcza zakres, wszystkie automatyczne obiekty utworzone w tym zakresie są niszczone.

Swift 4 obsługuje następujące instrukcje sterujące. Kliknij poniższe łącza, aby sprawdzić ich szczegóły.

Sr.No Oświadczenie i opis kontroli
1 kontynuuj oświadczenie

Ta instrukcja nakazuje pętli zatrzymanie tego, co robi i rozpoczęcie od nowa na początku następnej iteracji pętli.

2 instrukcja break

Kończy instrukcję pętli i przenosi wykonanie do instrukcji bezpośrednio po pętli.

3 stwierdzenie upadku

Instrukcja fallthrough symuluje zachowanie przełącznika Swift 4 na przełącznik w stylu C.

Ciągi znaków w języku Swift 4 to uporządkowany zbiór znaków, na przykład „Hello, World!” i są reprezentowane przez typ danych Swift 4String, co z kolei reprezentuje zbiór wartości Character rodzaj.

Utwórz ciąg

Możesz utworzyć String za pomocą literału ciągu lub tworząc wystąpienie klasy String w następujący sposób -

// String creation using String literal
var stringA = "Hello, Swift 4!"
print( stringA )

// String creation using String instance
var stringB = String("Hello, Swift 4!")
print( stringB )

//Multiple line string

let stringC = """
Hey this is a
example of multiple Line
string by tutorialsPoint 

"""
print(stringC)

Kiedy powyższy kod jest kompilowany i wykonywany, daje następujący wynik

Hello, Swift 4!
Hello, Swift 4!
Hey this is a
example of multiple Line
string by tutorialsPoint

Pusta struna

Możesz utworzyć pusty ciąg, używając literału pustego ciągu lub tworząc wystąpienie klasy String, jak pokazano poniżej. Możesz również sprawdzić, czy ciąg jest pusty, czy nie, używając właściwości BooleanisEmpty.

// Empty string creation using String literal
var stringA = ""

if stringA.isEmpty {
   print( "stringA is empty" )
} else {
   print( "stringA is not empty" )
}

// Empty string creation using String instance
let stringB = String()

if stringB.isEmpty {
   print( "stringB is empty" )
} else {
   print( "stringB is not empty" )
}

Kiedy powyższy kod jest kompilowany i wykonywany, daje następujący wynik -

stringA is empty
stringB is empty

Stałe łańcuchowe

Możesz określić, czy Twój ciąg może być modyfikowany (lub mutowany), przypisując go do zmiennej, czy też będzie stały, przypisując go do stałej za pomocą let słowo kluczowe, jak pokazano poniżej -

// stringA can be modified
var stringA = "Hello, Swift 4!"
stringA + = "--Readers--"
print( stringA )

// stringB can not be modified
let stringB = String("Hello, Swift 4!")
stringB + = "--Readers--"
print( stringB )

Kiedy powyższy kod jest kompilowany i wykonywany, daje następujący wynik -

Playground execution failed: error: <EXPR>:10:1: error: 'String' is not
convertible to '@lvalue UInt8'
stringB + = "--Readers--"

Interpolacja ciągów

Interpolacja ciągów to sposób na skonstruowanie nowej wartości typu String z kombinacji stałych, zmiennych, literałów i wyrażeń poprzez uwzględnienie ich wartości wewnątrz literału ciągu.

Każdy element (zmienny lub stała) wstawiony do literału ciągu jest zawinięty w parę nawiasów, poprzedzonych ukośnikiem odwrotnym. Oto prosty przykład -

var varA = 20
let constA = 100
var varC:Float = 20.0

var stringA = "\(varA) times \(constA) is equal to \(varC * 100)"
print( stringA )

Kiedy powyższy kod jest kompilowany i wykonywany, daje następujący wynik -

20 times 100 is equal to 2000.0

Konkatenacja ciągów

Możesz użyć operatora +, aby połączyć dwa ciągi lub ciąg i znak lub dwa znaki. Oto prosty przykład -

let constA = "Hello,"
let constB = "World!"

var stringA = constA + constB
print( stringA )

Kiedy powyższy kod jest kompilowany i wykonywany, daje następujący wynik -

Hello,World!

Długość łańcucha

Swift 4 struny nie mają lengthwłaściwość, ale możesz użyć funkcji global count (), aby policzyć liczbę znaków w ciągu. Oto prosty przykład -

var varA = "Hello, Swift 4!"

print( "\(varA), length is \((varA.count))" )

Kiedy powyższy kod jest kompilowany i wykonywany, daje następujący wynik -

Hello, Swift 4!, length is 15

Porównanie ciągów

Możesz użyć operatora ==, aby porównać dwie zmienne łańcuchowe lub stałe. Oto prosty przykład -

var varA = "Hello, Swift 4!"
var varB = "Hello, World!"

if varA == varB {
   print( "\(varA) and \(varB) are equal" )
} else {
   print( "\(varA) and \(varB) are not equal" )
}

Kiedy powyższy kod jest kompilowany i wykonywany, daje następujący wynik -

Hello, Swift 4! and Hello, World! are not equal

Iterowanie ciągów

Łańcuchy są znowu zbiorem wartości w swift 4, więc możemy iterować po łańcuchu używając pętli. -

for chars in "ThisString" {
   print(chars, terminator: " ")
}

Kiedy powyższy kod jest kompilowany i wykonywany, daje następujący wynik -

T h i s S t r i n g

Ciągi Unicode

Możesz uzyskać dostęp do reprezentacji String w formacie UTF-8 i UTF-16, wykonując iterację po jego właściwościach utf8 i utf16, jak pokazano w poniższym przykładzie -

var unicodeString = "Dog???"

print("UTF-8 Codes: ")
for code in unicodeString.utf8 {
   print("\(code) ")
}

print("\n")

print("UTF-16 Codes: ")
for code in unicodeString.utf16 {
   print("\(code) ")
}

Kiedy powyższy kod jest kompilowany i wykonywany, daje następujący wynik -

UTF-8 Codes: 
68 
111 
103 
63 
63 
63 


UTF-16 Codes: 
68 
111 
103 
63 
63 
63

Funkcje i operatory ciągów znaków

Swift 4 obsługuje szeroką gamę metod i operatorów związanych z ciągami znaków -

Sr.No Funkcje / operatory i cel
1

isEmpty

Wartość logiczna, która określa, czy ciąg jest pusty, czy nie.

2

hasPrefix(prefix: String)

Funkcja sprawdzająca, czy dany ciąg parametrów istnieje jako prefiks ciągu, czy nie.

3

hasSuffix(suffix: String)

Funkcja sprawdzająca, czy podany łańcuch parametrów istnieje jako sufiks ciągu, czy nie.

4

toInt()

Funkcja do konwersji liczbowej wartości ciągu na liczbę całkowitą.

5

count()

Funkcja globalna do zliczania liczby znaków w ciągu.

6

utf8

Właściwość, aby zwrócić reprezentację ciągu znaków w formacie UTF-8.

7

utf16

Właściwość, aby zwrócić reprezentację ciągu znaków w formacie UTF-16.

8

unicodeScalars

Właściwość, aby zwrócić reprezentację skalarną Unicode ciągu.

9

+

Operator łączący dwa ciągi lub ciąg i znak lub dwa znaki.

10

+=

Operator dołączający ciąg lub znak do istniejącego ciągu.

11

==

Operator określający równość dwóch ciągów.

12

<

Operator wykonujący porównanie leksykograficzne w celu określenia, czy jeden ciąg jest mniejszy od drugiego.

13

startIndex

Aby uzyskać wartość na początku indeksu ciągu.

14

endIndex

Aby uzyskać wartość na końcu indeksu ciągu.

15

Indices

Aby uzyskać dostęp do indeces jeden po drugim. tzn. wszystkie znaki łańcucha jeden po drugim.

16

insert("Value", at: position)

Aby wstawić wartość w pozycji.

17

remove(at: position)

removeSubrange(range)

aby usunąć wartość na pozycji lub usunąć zakres wartości z łańcucha.

18

reversed()

zwraca odwrotność ciągu

ZA character w Swift to pojedynczy znak literał String, do którego odnosi się typ danych Character. Spójrz na poniższy przykład. Wykorzystuje dwie stałe znakowe -

let char1: Character = "A"
let char2: Character = "B"

print("Value of char1 \(char1)")
print("Value of char2 \(char2)")

Kiedy powyższy kod jest kompilowany i wykonywany, daje następujący wynik -

Value of char1 A
Value of char2 B

Jeśli spróbujesz zapisać więcej niż jeden znak w zmiennej lub stałej typu znakowego, Swift 4 na to nie pozwoli. Spróbuj wpisać następujący przykład w Swift 4 Playground, a otrzymasz błąd nawet przed kompilacją.

// Following is wrong in Swift 4
let char: Character = "AB"

print("Value of char \(char)")

Puste zmienne znakowe

Nie jest możliwe utworzenie pustej zmiennej znakowej lub stałej, która będzie miała pustą wartość. Następująca składnia nie jest możliwa -

// Following is wrong in Swift 4
let char1: Character = ""
var char2: Character = ""

print("Value of char1 \(char1)")
print("Value of char2 \(char2)")

Dostęp do znaków z ciągów znaków

Jak wyjaśniono podczas omawiania ciągów znaków Swift 4, String reprezentuje zbiór wartości znaków w określonej kolejności. Możemy więc uzyskać dostęp do poszczególnych znaków z danego ciągu, wykonując iterację po tym ciągu za pomocąfor-in pętla -

for ch in "Hello" {
   print(ch)
}

Kiedy powyższy kod jest kompilowany i wykonywany, daje następujący wynik -

H
e
l
l
o

Łączenie ciągów ze znakami

Poniższy przykład ilustruje, jak znak Swift 4 można łączyć z ciągiem Swift 4.

var varA:String = "Hello "
let varB:Character = "G"

varA.append( varB )

print("Value of varC = \(varA)")

Kiedy powyższy kod jest kompilowany i wykonywany, daje następujący wynik -

Value of varC = Hello G

Tablice Swift 4 służą do przechowywania uporządkowanych list wartości tego samego typu. Swift 4 stawia ścisłe sprawdzanie, które nie pozwala na wprowadzenie niewłaściwego typu w tablicy, nawet przez pomyłkę.

Jeśli przypiszesz utworzoną tablicę do zmiennej, to jest ona zawsze zmienna, co oznacza, że ​​możesz ją zmienić, dodając, usuwając lub zmieniając jej elementy; ale jeśli przypiszesz tablicę do stałej, to ta tablica jest niezmienna, a jej rozmiaru i zawartości nie można zmienić.

Tworzenie tablic

Możesz utworzyć pustą tablicę określonego typu, używając następującej składni inicjatora -

var someArray = [SomeType]()

Oto składnia tworzenia tablicy o podanym rozmiarze a * i inicjalizacji jej wartością -

var someArray = [SomeType](count: NumbeOfElements, repeatedValue: InitialValue)

Możesz użyć poniższej instrukcji, aby utworzyć pustą tablicę Int typ mający 3 elementy i wartość początkową równą zero -

var someInts = [Int](count: 3, repeatedValue: 0)

Poniżej znajduje się jeszcze jeden przykład tworzenia tablicy trzech elementów i przypisywania trzech wartości do tej tablicy -

var someInts:[Int] = [10, 20, 30]

Dostęp do tablic

Możesz pobrać wartość z tablicy przy użyciu subscript składnia, przekazując indeks wartości, którą chcesz pobrać w nawiasach kwadratowych, bezpośrednio po nazwie tablicy w następujący sposób -

var someVar = someArray[index]

Tutaj indexzaczyna się od 0, co oznacza, że ​​dostęp do pierwszego elementu można uzyskać przy użyciu indeksu równego 0, do drugiego elementu można uzyskać dostęp przy użyciu indeksu 1 i tak dalej. Poniższy przykład pokazuje, jak tworzyć, inicjować i uzyskiwać dostęp do tablic -

var someInts = [Int](count: 3, repeatedValue: 10)

var someVar = someInts[0]
print( "Value of first element is \(someVar)" )
print( "Value of second element is \(someInts[1])" )
print( "Value of third element is \(someInts[2])" )

Kiedy powyższy kod jest kompilowany i wykonywany, daje następujący wynik -

Value of first element is 10
Value of second element is 10
Value of third element is 10

Modyfikowanie tablic

Możesz użyć append()metoda lub operator przypisania dodawania (+ =), aby dodać nowy element na końcu tablicy. Spójrz na poniższy przykład. Tutaj początkowo tworzymy pustą tablicę, a następnie dodajemy nowe elementy do tej samej tablicy -

var someInts = [Int]()

someInts.append(20)
someInts.append(30)
someInts += [40]

var someVar = someInts[0]

print( "Value of first element is \(someVar)" )
print( "Value of second element is \(someInts[1])" )
print( "Value of third element is \(someInts[2])" )

Kiedy powyższy kod jest kompilowany i wykonywany, daje następujący wynik -

Value of first element is 20
Value of second element is 30
Value of third element is 40

Możesz zmodyfikować istniejący element tablicy, przypisując nową wartość pod danym indeksem, jak pokazano w poniższym przykładzie -

var someInts = [Int]()

someInts.append(20)
someInts.append(30)
someInts += [40]

// Modify last element
someInts[2] = 50

var someVar = someInts[0]

print( "Value of first element is \(someVar)" )
print( "Value of second element is \(someInts[1])" )
print( "Value of third element is \(someInts[2])" )

Kiedy powyższy kod jest kompilowany i wykonywany, daje następujący wynik -

Value of first element is 20
Value of second element is 30
Value of third element is 50

Iterowanie po tablicy

Możesz użyć for-in pętla do iteracji po całym zestawie wartości w tablicy, jak pokazano w poniższym przykładzie -

var someStrs = [String]()

someStrs.append("Apple")
someStrs.append("Amazon")
someStrs += ["Google"]
for item in someStrs {
   print(item)
}

Kiedy powyższy kod jest kompilowany i wykonywany, daje następujący wynik -

Apple
Amazon
Google

Możesz użyć enumerate() funkcja, która zwraca indeks elementu wraz z jego wartością, jak pokazano poniżej w poniższym przykładzie -

var someStrs = [String]()

someStrs.append("Apple")
someStrs.append("Amazon")
someStrs += ["Google"]

for (index, item) in someStrs.enumerated() {
   print("Value at index = \(index) is \(item)")
}

Kiedy powyższy kod jest kompilowany i wykonywany, daje następujący wynik -

Value at index = 0 is Apple
Value at index = 1 is Amazon
Value at index = 2 is Google

Dodawanie dwóch tablic

Możesz użyć operatora dodawania (+), aby dodać dwie tablice tego samego typu, co da nową tablicę z kombinacją wartości z dwóch tablic w następujący sposób -

var intsA = [Int](count:2, repeatedValue: 2)
var intsB = [Int](count:3, repeatedValue: 1)

var intsC = intsA + intsB
for item in intsC {
   print(item)
}

Kiedy powyższy kod jest kompilowany i wykonywany, daje następujący wynik -

2
2
1
1
1

Hrabia Property

Możesz użyć tylko do odczytu count właściwość tablicy, aby znaleźć liczbę elementów w tablicy pokazanej poniżej -

var intsA = [Int](count:2, repeatedValue: 2)
var intsB = [Int](count:3, repeatedValue: 1)

var intsC = intsA + intsB

print("Total items in intsA = \(intsA.count)")
print("Total items in intsB = \(intsB.count)")
print("Total items in intsC = \(intsC.count)")

Kiedy powyższy kod jest kompilowany i wykonywany, daje następujący wynik -

Total items in intsA = 2
Total items in intsB = 3
Total items in intsC = 5

Pusta nieruchomość

Możesz użyć tylko do odczytu empty właściwość tablicy, aby dowiedzieć się, czy tablica jest pusta, czy nie, jak pokazano poniżej -

var intsA = [Int](count:2, repeatedValue: 2)
var intsB = [Int](count:3, repeatedValue: 1)
var intsC = [Int]()

print("intsA.isEmpty = \(intsA.isEmpty)")
print("intsB.isEmpty = \(intsB.isEmpty)")
print("intsC.isEmpty = \(intsC.isEmpty)")

Kiedy powyższy kod jest kompilowany i wykonywany, daje następujący wynik -

intsA.isEmpty = false
intsB.isEmpty = false
intsC.isEmpty = true

Szybki 4 sets są używane do przechowywania różnych wartości tego samego typu, ale nie mają określonej kolejności, jaką mają tablice.

Możesz użyć zestawów zamiast tablic, jeśli kolejność elementów nie stanowi problemu lub jeśli chcesz mieć pewność, że nie ma zduplikowanych wartości. (zestawy dopuszczają tylko różne wartości).

Aby typ był przechowywany w zestawie, musi mieć możliwość mieszania. Wartość skrótu to wartość Int, która jest równa dla równych obiektów. Na przykład, jeśli x == y, tox.hashvalue == y.hashvalue.

Wszystkie podstawowe wartości Swift są domyślnie typu hashable i mogą być używane jako wartości ustawione.

Tworzenie zestawów

Możesz utworzyć pusty zestaw określonego typu, używając następującej składni inicjatora -

var someSet = Set<Character>()     //Character can be replaced by data type of set.

Dostęp i modyfikowanie zestawów

Możesz uzyskać dostęp do zestawu lub zmodyfikować go za pomocą jego metod i właściwości -

Aby pokazać liczbę elementów w zestawie, można użyć metody „count”.

someSet.count        // prints the number of elements

Do wstawienia wartości w zestawie można użyć metody „wstaw”.

someSet.insert("c")   // adds the element to Set.

Podobnie isEmpty może służyć do sprawdzenia, czy zestaw jest pusty.

someSet.isEmpty       // returns true or false depending on the set Elements.

Do usunięcia wartości w zestawie można użyć metody „usuń”.

someSet.remove("c")     // removes a element , removeAll() can be used to remove all elements

Metoda „zawiera” może służyć do sprawdzenia istnienia wartości w zbiorze.

someSet.contains("c")     // to check if set contains this value.

Iteracja po zestawie

Możesz iterować po zestawie za pomocą pętli for-in -

for items in someSet {
   print(someSet)
}

//Swift sets are not in an ordered way, to iterate over a set in ordered way use

for items in someSet.sorted() {
   print(someSet)
}

Wykonywanie operacji na zbiorach

Możesz wykonywać podstawowe operacje na zestawach szybkich.

Poniżej przedstawiono metody wykonywania operacji na zbiorach -

  • Intersection
  • Union
  • subtracting
let evens: Set = [10,12,14,16,18]
let odds: Set = [5,7,9,11,13]
let primes = [2,3,5,7]
odds.union(evens).sorted()
// [5,7,9,10,11,12,13,14,16,18]
odds.intersection(evens).sorted()
//[]
odds.subtracting(primes).sorted()
//[9, 11, 13]

Szybki 4 dictionariessłużą do przechowywania nieuporządkowanych list wartości tego samego typu. Swift 4 stawia ścisłe sprawdzanie, które nie pozwala na wprowadzenie niewłaściwego typu do słownika nawet przez pomyłkę.

Słowniki Swift 4 używają unikalnego identyfikatora znanego jako keydo przechowywania wartości, do której można się później odwołać i wyszukać za pomocą tego samego klucza. W przeciwieństwie do elementów w tablicy, elementy w plikudictionarynie mają określonego zamówienia. Możesz użyćdictionary kiedy musisz wyszukać wartości na podstawie ich identyfikatorów.

Klucz słownika może być liczbą całkowitą lub łańcuchem bez ograniczeń, ale powinien być unikalny w obrębie słownika.

Jeśli przypiszesz utworzony słownik do zmiennej, to jest on zawsze zmienny, co oznacza, że ​​możesz go zmienić, dodając, usuwając lub zmieniając jego elementy. Ale jeśli przypiszesz słownik do stałej, słownik ten jest niezmienny, a jego rozmiar i zawartość nie mogą zostać zmienione.

Tworzenie słownika

Możesz utworzyć pusty słownik określonego typu, używając następującej składni inicjatora -

var someDict = [KeyType: ValueType]()

Możesz użyć następującej prostej składni, aby utworzyć pusty słownik, którego klucz będzie typu Int, a powiązane wartości będą ciągami -

var someDict = [Int: String]()

Oto przykład tworzenia słownika z zestawu podanych wartości -

var someDict:[Int:String] = [1:"One", 2:"Two", 3:"Three"]

Inicjalizacja oparta na sekwencji

Swift 4 umożliwia tworzenie słowników z tablic (par klucz-wartość).

var cities = [“Delhi”,”Bangalore”,”Hyderabad”]

Możesz użyć następującej prostej składni, aby utworzyć pusty słownik, którego klucz będzie typu Int, a powiązane wartości będą ciągami -

var Distance = [2000,10, 620]

Oto przykład tworzenia słownika z zestawu podanych wartości -

let cityDistanceDict = Dictionary(uniqueKeysWithValues: zip(cities, Distance))

Powyższe wiersze kodu utworzą słownik z miastami jako kluczem i odległością jako wartością -

Filtracja

Swift 4 umożliwia filtrowanie wartości ze słownika.

var closeCities = cityDistanceDict.filter { $0.value < 1000 }

Jeśli uruchomimy powyższy kod, nasz słownik closeCities będzie.

["Bangalore" : 10 , "Hyderabad" : 620]

Grupowanie słowników

Swift 4 umożliwia grupowanie wartości Dictionary.

var cities = ["Delhi","Bangalore","Hyderabad","Dehradun","Bihar"]

Możesz użyć następującej prostej składni, aby pogrupować wartości słownika według pierwszego alfabetu.

var GroupedCities = Dictionary(grouping: cities ) { $0.first! }

Wynik powyższego kodu będzie

["D" :["Delhi","Dehradun"], "B" : ["Bengaluru","Bihar"], "H" : ["Hyderabad"]]

Dostęp do słowników

Możesz pobrać wartość ze słownika, używając składni indeksu dolnego, przekazując klucz wartości, którą chcesz pobrać, w nawiasach kwadratowych bezpośrednio po nazwie słownika w następujący sposób:

var someVar = someDict[key]

Sprawdźmy następujący przykład, aby utworzyć, zainicjować i uzyskać dostęp do wartości ze słownika -

var someDict:[Int:String] = [1:"One", 2:"Two", 3:"Three"]
var someVar = someDict[1]

print( "Value of key = 1 is \(someVar)" )
print( "Value of key = 2 is \(someDict[2])" )
print( "Value of key = 3 is \(someDict[3])" )

Kiedy powyższy kod jest kompilowany i wykonywany, daje następujący wynik -

Value of key = 1 is Optional("One")
Value of key = 2 is Optional("Two")
Value of key = 3 is Optional("Three")

Modyfikowanie słowników

Możesz użyć updateValue(forKey:)metoda, aby dodać istniejącą wartość do danego klucza słownika. Ta metoda zwraca opcjonalną wartość typu wartości słownika. Oto prosty przykład -

var someDict:[Int:String] = [1:"One", 2:"Two", 3:"Three"]
var oldVal = someDict.updateValue("New value of one", forKey: 1)
var someVar = someDict[1]

print( "Old value of key = 1 is \(oldVal)" )
print( "Value of key = 1 is \(someVar)" )
print( "Value of key = 2 is \(someDict[2])" )
print( "Value of key = 3 is \(someDict[3])" )

Kiedy powyższy kod jest kompilowany i wykonywany, daje następujący wynik -

Old value of key = 1 is Optional("One")
Value of key = 1 is Optional("New value of one")
Value of key = 2 is Optional("Two")
Value of key = 3 is Optional("Three")

Możesz zmodyfikować istniejący element słownika, przypisując nową wartość do danego klucza, jak pokazano w poniższym przykładzie -

var someDict:[Int:String] = [1:"One", 2:"Two", 3:"Three"]
var oldVal = someDict[1]
someDict[1] = "New value of one"
var someVar = someDict[1]

print( "Old value of key = 1 is \(oldVal)" )
print( "Value of key = 1 is \(someVar)" )
print( "Value of key = 2 is \(someDict[2])" )
print( "Value of key = 3 is \(someDict[3])" )

Kiedy powyższy kod jest kompilowany i wykonywany, daje następujący wynik -

Old value of key = 1 is Optional("One")
Value of key = 1 is Optional("New value of one")
Value of key = 2 is Optional("Two")
Value of key = 3 is Optional("Three")

Usuń pary klucz-wartość

Możesz użyć removeValueForKey()metoda usuwania pary klucz-wartość ze słownika. Ta metoda usuwa parę klucz-wartość, jeśli istnieje, i zwraca usuniętą wartość lub zwraca nil, jeśli żadna wartość nie istnieje. Oto prosty przykład -

var someDict:[Int:String] = [1:"One", 2:"Two", 3:"Three"]
var removedValue = someDict.removeValue(forKey: 2)

print( "Value of key = 1 is \(someDict[1])" )
print( "Value of key = 2 is \(someDict[2])" )
print( "Value of key = 3 is \(someDict[3])" )

Kiedy powyższy kod jest kompilowany i wykonywany, daje następujący wynik -

Value of key = 1 is Optional("One")
Value of key = 2 is nil
Value of key = 3 is Optional("Three")

Możesz również użyć składni indeksu dolnego, aby usunąć parę klucz-wartość ze słownika, przypisując wartość nildla tego klucza. Oto prosty przykład -

var someDict:[Int:String] = [1:"One", 2:"Two", 3:"Three"]

someDict[2] = nil

print( "Value of key = 1 is \(someDict[1])" )
print( "Value of key = 2 is \(someDict[2])" )
print( "Value of key = 3 is \(someDict[3])" )

Kiedy powyższy kod jest kompilowany i wykonywany, daje następujący wynik -

Value of key = 1 is Optional("One")
Value of key = 2 is nil
Value of key = 3 is Optional("Three")

Iteracja po słowniku

Możesz użyć for-in pętla do iteracji po całym zestawie par klucz-wartość w słowniku, jak pokazano w poniższym przykładzie -

var someDict:[Int:String] = [1:"One", 2:"Two", 3:"Three"]

for (index, keyValue) in someDict.enumerated() {
   print("Dictionary key \(index) - Dictionary value \(keyValue)")
}

Kiedy powyższy kod jest kompilowany i wykonywany, daje następujący wynik -

Dictionary key 2 - Dictionary value Two
Dictionary key 3 - Dictionary value Three
Dictionary key 1 - Dictionary value One

Możesz użyć enumerate() funkcja, która zwraca indeks elementu wraz z jego parą (klucz, wartość), jak pokazano poniżej w przykładzie -

var someDict:[Int:String] = [1:"One", 2:"Two", 3:"Three"]
for (key, value) in someDict.enumerated() {
   print("Dictionary key \(key) - Dictionary value \(value)")
}

Kiedy powyższy kod jest kompilowany i wykonywany, daje następujący wynik -

Dictionary key 0 - Dictionary value (key: 2, value: "Two")
Dictionary key 1 - Dictionary value (key: 3, value: "Three")
Dictionary key 2 - Dictionary value (key: 1, value: "One")

Konwertuj na tablice

Możesz wyodrębnić listę par klucz-wartość z danego słownika, aby utworzyć oddzielne tablice dla kluczy i wartości. Oto przykład -

var someDict:[Int:String] = [1:"One", 2:"Two", 3:"Three"]

let dictKeys = [Int](someDict.keys)
let dictValues = [String](someDict.values)

print("Print Dictionary Keys")

for (key) in dictKeys {
   print("\(key)")
}
print("Print Dictionary Values")

for (value) in dictValues {
   print("\(value)")
}

Kiedy powyższy kod jest kompilowany i wykonywany, daje następujący wynik -

Print Dictionary Keys
2
3
1
Print Dictionary Values
Two
Three
One

Hrabia Property

Możesz użyć tylko do odczytu count właściwość słownika, aby znaleźć liczbę elementów w słowniku, jak pokazano poniżej -

var someDict1:[Int:String] = [1:"One", 2:"Two", 3:"Three"]
var someDict2:[Int:String] = [4:"Four", 5:"Five"]

print("Total items in someDict1 = \(someDict1.count)")
print("Total items in someDict2 = \(someDict2.count)")

Kiedy powyższy kod jest kompilowany i wykonywany, daje następujący wynik -

Total items in someDict1 = 3
Total items in someDict2 = 2

Pusta nieruchomość

Możesz użyć tylko do odczytu empty właściwość słownika, aby sprawdzić, czy słownik jest pusty, czy nie, jak pokazano poniżej -

var someDict1:[Int:String] = [1:"One", 2:"Two", 3:"Three"]
var someDict2:[Int:String] = [4:"Four", 5:"Five"]
var someDict3:[Int:String] = [Int:String]()

print("someDict1 = \(someDict1.isEmpty)")
print("someDict2 = \(someDict2.isEmpty)")
print("someDict3 = \(someDict3.isEmpty)")

Kiedy powyższy kod jest kompilowany i wykonywany, daje następujący wynik -

someDict1 = false
someDict2 = false
someDict3 = true

Funkcja to zestaw instrukcji zorganizowanych razem w celu wykonania określonego zadania. Funkcja języka Swift 4 może być tak prosta, jak prosta funkcja w języku C, albo tak złożona, jak funkcja języka Objective C. Pozwala nam przekazywać lokalne i globalne wartości parametrów wewnątrz wywołań funkcji.

  • Function Declaration - informuje kompilator o nazwie funkcji, zwracanym typie i parametrach.

  • Function Definition - Dostarcza rzeczywistą treść funkcji.

Funkcje Swift 4 zawierają typ parametru i jego typy zwracane.

Definicja funkcji

W języku Swift 4 funkcja jest definiowana przez słowo kluczowe „func”. Gdy funkcja jest nowo zdefiniowana, może przyjąć jedną lub kilka wartości jako „parametry” wejściowe do funkcji i będzie przetwarzać funkcje w części głównej i przekazywać wartości z powrotem do funkcji jako wyjściowe „typy zwracane”.

Każda funkcja ma nazwę, która opisuje zadanie, które funkcja wykonuje. Aby użyć funkcji, należy ją „wywołać”, podając jej nazwę i przekazać wartości wejściowe (znane jako argumenty), które pasują do typów parametrów funkcji. Parametry funkcji są również nazywane „krotkami”.

Argumenty funkcji muszą być zawsze podawane w tej samej kolejności, co lista parametrów funkcji, a po wartościach zwracanych następuje →.

Składnia

func funcname(Parameters) -> returntype {
   Statement1
   Statement2
   ---
   Statement N
   return parameters
}

Spójrz na poniższy kod. Nazwisko ucznia jest zadeklarowane jako łańcuchowy typ danych zadeklarowany wewnątrz funkcji „student”, a wywołanie funkcji zwróci nazwisko ucznia.

func student(name: String) -> String {
   return name
}

print(student(name: "First Program"))
print(student(name: "About Functions"))

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

First Program
About Functions

Wywołanie funkcji

Załóżmy, że zdefiniowaliśmy funkcję o nazwie „display” do rozważenia, na przykład do wyświetlania liczb, funkcja o nazwie „display” jest inicjowana jako pierwsza z argumentem „no1”, który przechowuje dane typu integer. Następnie argument „no1” jest przypisywany do argumentu „a”, który odtąd będzie wskazywał na tę samą liczbę całkowitą typu danych. Teraz argument „a” jest zwracany do funkcji. Tutaj funkcja display () zachowa wartość całkowitą i zwróci wartości całkowite przy każdym wywołaniu funkcji.

func display(no1: Int) -> Int {
   let a = no1
   return a
}

print(display(no1: 100))
print(display(no1: 200))

Kiedy uruchomimy powyższy program za pomocą placu zabaw, otrzymamy następujący wynik -

100
200

Parametry i wartości zwracane

Swift 4 zapewnia elastyczne parametry funkcji i wartości zwracane od prostych do złożonych wartości. Podobnie jak w C i Objective C, funkcje w Swift 4 mogą również przybierać różne formy.

Funkcje z parametrami

Dostęp do funkcji uzyskuje się, przekazując wartości jej parametrów do treści funkcji. Możemy przekazywać pojedyncze wartości wielu parametrów jako krotki wewnątrz funkcji.

func mult(no1: Int, no2: Int) -> Int {
   return no1*no2
}

print(mult(no1: 2, no2: 20))
print(mult(no1: 3, no2: 15))
print(mult(no1: 4, no2: 30))

Kiedy uruchomimy powyższy program za pomocą placu zabaw, otrzymamy następujący wynik -

40
45
120

Funkcje bez parametrów

Możemy również mieć funkcje bez parametrów.

Składnia

func funcname() -> datatype {
   return datatype
}

Poniżej znajduje się przykład funkcji bez parametru -

func votersname() -> String {
   return "Alice"
}
print(votersname())

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

Alice

Funkcje z wartościami zwracanymi

Funkcje są również używane do zwracania wartości typu string, integer i float jako typy zwracane. Aby znaleźć największą i najmniejszą liczbę w danej tablicy, funkcja „ls” jest zadeklarowana z dużymi i małymi typami danych całkowitymi.

Tablica jest inicjowana do przechowywania wartości całkowitych. Następnie tablica jest przetwarzana i każda wartość w tablicy jest odczytywana i porównywana z jej poprzednią wartością. Gdy wartość jest mniejsza od poprzedniej, jest przechowywana w argumencie „small”, w przeciwnym razie w argumencie „large”, a wartości są zwracane przez wywołanie funkcji.

func ls(array: [Int]) -> (large: Int, small: Int) {
   var lar = array[0]
   var sma = array[0]

   for i in array[1..<array.count] {
      if i < sma {
         sma = i
      } else if i > lar {
         lar = i
      }
   }
   return (lar, sma)
}

let num = ls(array: [40,12,-5,78,98])
print("Largest number is: \(num.large) and smallest number is: \(num.small)")

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

Largest number is: 98 and smallest number is: -5

Funkcje bez wartości zwracanych

Niektóre funkcje mogą mieć argumenty zadeklarowane wewnątrz funkcji bez zwracanych wartości. Poniższy program deklarujea i bjako argumenty funkcji sum (). wewnątrz samej funkcji wartości argumentówa i b są przekazywane przez wywołanie funkcji sum (), a jej wartości są drukowane, eliminując w ten sposób zwracane wartości.

func sum(a: Int, b: Int) {
   let a = a + b
   let b = a - b
   print(a, b)
}

sum(a: 20, b: 10)
sum(a: 40, b: 10)
sum(a: 24, b: 6)

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

30 20
50 40
30 24

Funkcje z opcjonalnymi typami zwrotu

Swift 4 wprowadza „opcjonalną” funkcję, aby pozbyć się problemów poprzez wprowadzenie środków bezpieczeństwa. Rozważmy na przykład, że deklarujemy zwracane wartości funkcji jako liczby całkowite, ale co się stanie, gdy funkcja zwróci wartość ciągu lub wartość zerową. W takim przypadku kompilator zwróci wartość błędu. „opcjonalne” są wprowadzane, aby pozbyć się tych problemów.

Funkcje opcjonalne przyjmą dwie formy „wartość” i „zero”. Wspomnimy „Opcje” ze znakiem zastrzeżonym klucza „?” aby sprawdzić, czy krotka zwraca wartość czy wartość zerową.

func minMax(array: [Int]) -> (min: Int, max: Int)? {
   if array.isEmpty { return nil }
   var currentMin = array[0]
   var currentMax = array[0]
   
   for value in array[1..<array.count] {
      if value < currentMin {
         currentMin = value
      } else if value > currentMax {
         currentMax = value
      }
   }
   return (currentMin, currentMax)
}

if let bounds = minMax(array: [8, -6, 2, 109, 3, 71]) {
   print("min is \(bounds.min) and max is \(bounds.max)")
}

Gdy uruchomimy powyższy program za pomocą placu zabaw, otrzymamy następujący wynik -

min is -6 and max is 109

„Opcje” są używane do sprawdzania wartości „zero” lub śmieci, przez co zajmują dużo czasu podczas debugowania i sprawiają, że kod jest wydajny i czytelny dla użytkownika.

Funkcje Lokalne i zewnętrzne nazwy parametrów

Nazwy parametrów lokalnych

Lokalne nazwy parametrów są dostępne w samej funkcji.

func sample(number: Int) {
   print(number)
}

Tutaj funcpróbka numer argumentu jest zadeklarowana jako zmienna wewnętrzna, ponieważ jest dostępna wewnętrznie przez funkcję sample (). Tutaj `` liczba '' jest zadeklarowana jako zmienna lokalna, ale odniesienie do zmiennej jest dokonywane poza funkcją za pomocą następującej instrukcji -

func sample(number: Int) {
   print(number)
}

sample(number: 1)
sample(number: 2)
sample(number: 3)

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

1
2
3

Nazwy parametrów zewnętrznych

Nazwy parametrów zewnętrznych pozwalają nam nazwać parametry funkcji, aby lepiej wyjaśnić ich przeznaczenie. Na przykład poniżej możesz nazwać dwa parametry funkcji, a następnie wywołać tę funkcję w następujący sposób -

func pow(firstArg a: Int, secondArg b: Int) -> Int {
   var res = a
   for _ in 1..<b {
      res = res * a
   }
   print(res)
   return res
}

pow(firstArg:5, secondArg:3)

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

125

Parametry zmienne

Kiedy chcemy zdefiniować funkcję z wieloma argumentami, możemy zadeklarować składowe jako parametry „wariadyczne”. Parametry można określić jako zmienne przez (···) po nazwie parametru.

func vari<N>(members: N...){
   for i in members {
      print(i)
   }
}

vari(members: 4,3,5)
vari(members: 4.5, 3.1, 5.6)
vari(members: "Swift 4", "Enumerations", "Closures")

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

4
3
5
4.5
3.1
5.6
Swift 4
Enumerations
Closures

Parametry stałe, zmienne i we / wy

Funkcje domyślnie traktują parametry jako „stałe”, podczas gdy użytkownik może zadeklarować argumenty funkcji również jako zmienne. Wspomnieliśmy już, że słowo kluczowe „let” służy do deklarowania parametrów stałych, a parametry zmiennych są definiowane za pomocą słowa kluczowego „var”.

Parametry we / wy w języku Swift 4 zapewniają funkcjonalność zachowania wartości parametrów, nawet jeśli ich wartości są modyfikowane po wywołaniu funkcji. Na początku definicji parametru funkcji zadeklarowano słowo kluczowe „inout”, aby zachować wartości składowe.

Wywodzi słowo kluczowe „inout”, ponieważ jego wartości są przekazywane „in” do funkcji, a jej treść jest uzyskiwana i modyfikowana przez jej treść, a następnie jest zwracana „na zewnątrz” funkcji w celu zmodyfikowania oryginalnego argumentu.

Zmienne są przekazywane tylko jako argument dla parametru in-out, ponieważ same ich wartości są modyfikowane wewnątrz i na zewnątrz funkcji. Dlatego nie ma potrzeby deklarowania łańcuchów i literałów jako parametrów wejściowych. „&” przed nazwą zmiennej wskazuje, że przekazujemy argument do parametru in-out.

func temp(a1: inout Int, b1: inout Int) {
   let t = a1
   a1 = b1
   b1 = t
}

var no = 2
var co = 10
temp(a1: &no, b1: &co)
print("Swapped values are \(no), \(co)")

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

Swapped values are 10, 2

Typy funkcji i ich użycie

Każda funkcja jest zgodna z określoną funkcją, biorąc pod uwagę parametry wejściowe i generuje pożądany wynik.

func inputs(no1: Int, no2: Int) -> Int {
   return no1/no2
}

Oto przykład -

func inputs(no1: Int, no2: Int) -> Int {
   return no1/no2
}

print(inputs(no1: 20, no2: 10))
print(inputs(no1: 36, no2: 6))

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

2
6

Tutaj funkcja jest inicjalizowana dwoma argumentami no1 i no2 jako typy danych całkowitych, a typ zwracany jest również deklarowany jako „int”

Func inputstr(name: String) -> String {
   return name
}

Tutaj funkcja jest zadeklarowana jako string typ danych.

Funkcje mogą również mieć void typy danych i takie funkcje nic nie zwrócą.

func inputstr() {
   print("Swift 4 Functions")
   print("Types and its Usage")
}
inputstr()

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

Swift 4 Functions
Types and its Usage

Powyższa funkcja jest zadeklarowana jako funkcja void bez argumentów i wartości zwracanych.

Korzystanie z typów funkcji

Funkcje są najpierw przekazywane z argumentami typu integer, float lub string, a następnie są przekazywane jako stałe lub zmienne do funkcji, jak wspomniano poniżej.

var addition: (Int, Int) -> Int = sum

Tutaj suma jest nazwą funkcji mającą zmienne całkowite „a” i „b”, która jest teraz zadeklarowana jako zmienna w dodatku do nazwy funkcji. Odtąd obie funkcje dodawania i sumowania mają taką samą liczbę argumentów zadeklarowanych jako całkowity typ danych, a także zwracają wartości całkowite jako odwołania.

func sum(a: Int, b: Int) -> Int {
   return a + b
}
var addition: (Int, Int) -> Int = sum
print("Result: \(addition(40, 89))")

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

Result: 129

Typy funkcji jako typy parametrów i typy zwrotów

Możemy również przekazać samą funkcję jako typy parametrów do innej funkcji.

func sum(a: Int, b: Int) -> Int {
   return a + b
}
var addition: (Int, Int) -> Int = sum
print("Result: \(addition(40, 89))")

func another(addition: (Int, Int) -> Int, a: Int, b: Int) {
   print("Result: \(addition(a, b))")
}
another(sum, 10, 20)

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

Result: 129
Result: 30

Funkcje zagnieżdżone

Zagnieżdżona funkcja zapewnia możliwość wywołania funkcji zewnętrznej przez wywołanie funkcji inside.

func calcDecrement(forDecrement total: Int) -> () -> Int {
   var overallDecrement = 0
   func decrementer() -> Int {
      overallDecrement -= total
      return overallDecrement
   }
   return decrementer
}

let decrem = calcDecrement(forDecrement: 30)
print(decrem())

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

-30

Zamknięcia w Swift 4 są podobne do zamkniętych funkcji zorganizowanych w bloki i nazywanych wszędzie, jak języki C i Objective C. Stałe i odwołania do zmiennych zdefiniowane wewnątrz funkcji są przechwytywane i przechowywane w domknięciach. Funkcje są uważane za specjalne przypadki domknięć i przyjmują następujące trzy formy -

Funkcje globalne Funkcje zagnieżdżone Wyrażenia końcowe
Miej imię. Nie rejestruj żadnych wartości Miej imię. Przechwyć wartości z otaczającej funkcji Nienazwane Zamknięcia przechwytują wartości z sąsiednich bloków

Wyrażenia zamykające w języku Swift 4 są zgodne z wyraźnymi, optymalizacyjnymi i lekkimi stylami składni, które obejmują.

  • Wnioskowanie o typach parametrów i zwracanych wartościach z kontekstu.
  • Niejawne zwroty z zamknięć pojedynczych wyrażeń.
  • Skrócone nazwy argumentów i
  • Składnia zamknięcia końcowego

Składnia

Poniżej znajduje się ogólna składnia definiująca zamknięcie, które akceptuje parametry i zwraca typ danych -

{
   (parameters) −> return type in
   statements
}

Oto prosty przykład -

let studname = { print("Welcome to Swift Closures") }
studname()

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

Welcome to Swift Closures

Poniższe zamknięcie akceptuje dwa parametry i zwraca wartość logiczną -

{     
   (Int, Int) −> Bool in
   Statement1
   Statement 2
   ---
   Statement n
}

Oto prosty przykład -

let divide = {
   (val1: Int, val2: Int) -> Int in 
   return val1 / val2 
}

let result = divide(200, 20)
print (result)

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

10

Wyrażenia w zamknięciach

Zagnieżdżone funkcje zapewniają wygodny sposób nazywania i definiowania bloków kodu. Zamiast reprezentować całą deklarację funkcji i konstrukcje nazw są używane do oznaczania krótszych funkcji. Przedstawienie funkcji w jasnej, krótkiej instrukcji z ukierunkowaną składnią osiąga się za pomocą wyrażeń zamykających.

Program porządku rosnącego

Sortowanie ciągu odbywa się za pomocą zarezerwowanej funkcji klucza Swift 4s „sortowane”, która jest już dostępna w bibliotece standardowej. Funkcja posortuje podane ciągi w kolejności rosnącej i zwróci elementy w nowej tablicy o takim samym rozmiarze i typie danych, jak w starej tablicy. Stara tablica pozostaje taka sama.

W posortowanej funkcji reprezentowane są dwa argumenty -

  • Wartości typu Known reprezentowane jako tablice.

  • Zawartość tablicy (Int, Int) i zwraca wartość logiczną (Bool), jeśli tablica jest poprawnie posortowana, zwróci wartość true, w przeciwnym razie zwróci wartość false.

Normalna funkcja z ciągiem wejściowym jest zapisywana i przekazywana do posortowanej funkcji, aby uzyskać ciągi posortowane do nowej tablicy, która jest pokazana poniżej -

func ascend(s1: String, s2: String) -> Bool {
   return s1 > s2
}

let stringcmp = ascend(s1: "Swift 4", s2: "great")
print (stringcmp)

Gdy uruchomimy powyższy program za pomocą placu zabaw, otrzymamy następujący wynik -

true

Początkowa tablica, która ma być posortowana pod kątem lodów, jest podana jako „Swift 4” i „świetna”. Funkcja sortowania tablicy jest zadeklarowana jako łańcuchowy typ danych, a jej zwracany typ jest określany jako Boolean. Oba ciągi są porównywane i sortowane w kolejności rosnącej i zapisywane w nowej tablicy. Jeśli sortowanie zakończy się pomyślnie, funkcja zwróci wartość true, w przeciwnym razie zwróci false.

Używa składni wyrażenia zamknięcia -

  • stałe parametry,
  • zmienne parametry i
  • parametry inout.

Wyrażenie zamknięcia nie obsługuje wartości domyślnych. Parametry zmienne i krotki mogą być również używane jako typy parametrów i typy zwracane.

let sum = {
   (no1: Int, no2: Int) -> Int in 
   return no1 + no2 
}

let digits = sum(10, 20)
print(digits)

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

30

Parametry i deklaracje typu zwracanego wymienione w instrukcji funkcji mogą być również reprezentowane przez funkcję wyrażenia inline closure ze słowem kluczowym „in”. Po zadeklarowaniu parametru i zwracanych typów słowo kluczowe „in” służy do oznaczenia treści zamknięcia.

Niejawne zwroty pojedynczego wyrażenia

W tym przypadku typ funkcji drugiego argumentu posortowanej funkcji wyjaśnia, że ​​wartość logiczna musi zostać zwrócona przez zamknięcie. Ponieważ treść zamknięcia zawiera pojedyncze wyrażenie (s1> s2), które zwraca wartość logiczną, nie ma niejednoznaczności, a słowo kluczowe return można pominąć.

Aby zwrócić instrukcję Single expression w zamknięciu wyrażenia, słowo kluczowe „return” jest pomijane w części deklaracji.

var count:[Int] = [5, 10, -6, 75, 20]
let descending = count.sorted(by: { n1, n2 in n1 > n2 })
let ascending = count.sorted(by: { n1, n2 in n1 < n2 })

print(descending)
print(ascending)

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

[75, 20, 10, 5, -6]
[-6, 5, 10, 20, 75]

Samo stwierdzenie jasno definiuje, że gdy string1 jest większe niż string 2, zwraca true, w przeciwnym razie false, stąd instrukcja return jest tutaj pominięta.

Zamknięcia znanych typów

Rozważ dodanie dwóch liczb. Wiemy, że dodanie zwróci całkowity typ danych. Stąd znane zamknięcia typu są deklarowane jako -

let sub = {
   (no1: Int, no2: Int) -> Int in 
   return no1 - no2 
}

let digits = sub(10, 20)
print(digits)

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

-10

Deklarowanie skróconych nazw argumentów jako domknięć

Swift 4 automatycznie dostarcza skrócone nazwy argumentów do domknięć w wierszu, których można użyć do odniesienia się do wartości argumentów domknięcia nazwami $ 0, $1, $2 i tak dalej.

var shorthand: (String, String) -> String
shorthand = { $1 }
print(shorthand("100", "200"))

Tutaj $ 0 i $ 1 odnoszą się do pierwszego i drugiego argumentu String zamknięcia.

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

200

Swift 4 ułatwia użytkownikowi reprezentowanie domknięć Inline jako skróconych nazw argumentów, reprezentując $ 0, $1, $2 --- $ n.

Lista argumentów zamknięć jest pomijana w sekcji definicji, gdy reprezentujemy skrócone nazwy argumentów w wyrażeniach zamknięcia. Na podstawie typu funkcji zostaną wyprowadzone skrócone nazwy argumentów. Ponieważ argument skrótu jest zdefiniowany w treści wyrażenia, słowo kluczowe „in” jest pomijane.

Zamknięcia jako funkcje operatora

Swift 4 zapewnia łatwy dostęp do elementów, zapewniając po prostu funkcje operatora jako zamknięcia. W poprzednich przykładach słowo kluczowe „Bool” jest używane do zwracania „prawda”, gdy łańcuchy są równe, w przeciwnym razie zwraca „fałsz”.

Wyrażenie jest jeszcze prostsze dzięki funkcji operatora w zamknięciu, ponieważ -

let numb = [98, -20, -30, 42, 18, 35]
var sortedNumbers = numb.sorted ({
   (left: Int, right: Int) -> Bool in
   return left < right
})

let asc = numb.sorted(<)
print(asc)

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

[-30, -20, 18, 35, 42, 98]

Zamknięcia jako zwiastuny

Przekazanie końcowego argumentu funkcji do wyrażenia zamykającego deklarowane jest za pomocą „Końcowych zamknięć”. Jest napisany poza funkcją () z {}. Jego użycie jest potrzebne, gdy nie jest możliwe zapisanie funkcji w jednej linii.

reversed = sorted(names) { $0 > $1}

gdzie {$ 0> $ 1} są reprezentowane jako końcowe zamknięcia zadeklarowane na zewnątrz (nazwy).

import Foundation
var letters = ["North", "East", "West", "South"]

let twoletters = letters.map({ 
   (state: String) -> String in
   return state.substringToIndex(advance(state.startIndex, 2)).uppercaseString
})

let stletters = letters.map() { 
   $0.substringToIndex(advance($0.startIndex, 2)).uppercaseString 
}
print(stletters)

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

[NO, EA, WE, SO]

Przechwytywanie wartości i typów odwołań

W Swift 4 przechwytywanie stałych i wartości zmiennych odbywa się za pomocą domknięć. Ponadto odwołuje się i modyfikuje wartości tych stałych i zmiennych w treści zamknięcia, mimo że zmienne już nie istnieją.

Przechwytywanie wartości stałych i zmiennych uzyskuje się za pomocą funkcji zagnieżdżonej, zapisując funkcję w treści innej funkcji.

Zagnieżdżona funkcja przechwytuje -

  • Argumenty funkcji zewnętrznej.
  • Przechwytuj stałe i zmienne zdefiniowane w funkcji Outer.

W Swift 4, gdy stała lub zmienna jest zadeklarowana wewnątrz funkcji, odniesienie do tych zmiennych jest również tworzone automatycznie przez zamknięcie. Zapewnia również możliwość odniesienia więcej niż dwóch zmiennych jako tego samego zamknięcia w następujący sposób -

let decrem = calcDecrement(forDecrement: 18)
decrem()

Tutaj oneDecrement i zmienne Decrement będą wskazywać ten sam blok pamięci jako odniesienie zamknięcia.

func calcDecrement(forDecrement total: Int) -> () -> Int {
   var overallDecrement = 100
   func decrementer() -> Int {
      overallDecrement -= total
      print(overallDecrement)
      return overallDecrement
   }
   return decrementer
}

let decrem = calcDecrement(forDecrement: 18)
decrem()
decrem()
decrem()

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

82
64
46

Za każdym razem, gdy wywoływana jest funkcja zewnętrzna calcDecrement, wywołuje ona funkcję dekrementer (), zmniejsza wartość o 18 i zwraca wynik za pomocą funkcji zewnętrznej calcDecrement. Tutaj calcDecrement działa jak zamknięcie.

Mimo że funkcja decrementer () nie ma domyślnie żadnych argumentów, zamknięcie odwołuje się do zmiennych „generalDecrement” i „total”, przechwytując istniejące wartości. Kopia wartości określonych zmiennych jest przechowywana za pomocą nowej funkcji dekrementacji (). Swift 4 obsługuje funkcje zarządzania pamięcią poprzez przydzielanie i zwalnianie przestrzeni pamięci, gdy zmienne nie są używane.

Wyliczenie to typ danych zdefiniowany przez użytkownika, który składa się z zestawu powiązanych wartości. Słowo kluczoweenum jest używany do zdefiniowanego wyliczeniowego typu danych.

Funkcjonalność wyliczania

Wyliczenie w Swift 4 również przypomina strukturę C i Objective C.

  • Jest zadeklarowana w klasie, a jej wartości są dostępne za pośrednictwem instancji tej klasy.

  • Początkowa wartość elementu członkowskiego jest definiowana przy użyciu funkcji inicjujących wyliczenia.

  • Jego funkcjonalność jest również rozszerzona poprzez zapewnienie standardowej funkcjonalności protokołu.

Składnia

Wyliczenia są wprowadzane za pomocą słowa kluczowego enum i umieszczają całą ich definicję w parze nawiasów klamrowych -

enum enumname {
   // enumeration values are described here
}

Na przykład możesz zdefiniować wyliczenie dla dni tygodnia w następujący sposób -

enum DaysofaWeek {
   case Sunday
   case Monday
   ---
   case Saturday
}

Przykład

enum names {
   case Swift
   case Closures
}

var lang = names.Closures
lang = .Closures

switch lang {
   case .Swift:
      print("Welcome to Swift")
   case .Closures:
      print("Welcome to Closures")
   default:
      print("Introduction")
}

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

Welcome to Closures

Wyliczenie Swift 4 nie przypisuje swoim członkom wartości domyślnej, takiej jak C i Objective C. Zamiast tego członkowie są jawnie definiowani przez ich nazwy wyliczeniowe. Nazwa wyliczenia powinna zaczynać się wielką literą (np. Wyliczenie DaysofaWeek).

var weekDay = DaysofaWeek.Sunday

Tutaj nazwa wyliczenia „DaysofaWeek” jest przypisana do zmiennej weekday.Sunday. Informuje kompilator, że typ danych należący do Sunday zostanie przypisany kolejnym członkom wyliczenia tej konkretnej klasy. Po zdefiniowaniu typu danych elementu członkowskiego wyliczenia dostęp do elementów członkowskich można uzyskać, przekazując wartości i wykonując dalsze obliczenia.

Wyliczenie za pomocą instrukcji Switch

Instrukcja Swift 4 „Switch” jest również następująca po wyborze wielostronnym. Dostęp do tylko jednej zmiennej jest możliwy w określonym czasie na podstawie określonego warunku. Domyślny przypadek w instrukcji switch służy do przechwytywania nieokreślonych przypadków.

enum Climate {
   case India
   case America
   case Africa
   case Australia
}

var season = Climate.America
season = .America
switch season {
   case .India:
      print("Climate is Hot")
   case .America:
      print("Climate is Cold")
   case .Africa:
      print("Climate is Moderate")
   case .Australia:
      print("Climate is Rainy")
   
}

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

Climate is Cold

Program najpierw definiuje Climate jako nazwę wyliczenia. Następnie jej członkowie, tacy jak „Indie”, „Ameryka”, „Afryka” i „Australia”, zostają uznani za należących do klasy „Klimat”. Teraz członek America jest przypisany do zmiennej sezonowej. Co więcej, przypadek przełącznika zobaczy wartości odpowiadające .America i przejdzie do tej konkretnej instrukcji. Wynik zostanie wyświetlony jako „Klimat jest zimny”. Podobnie, dostęp do wszystkich członków można uzyskać za pomocą instrukcji przełącznika. Gdy warunek nie jest spełniony, domyślnie drukowany jest komunikat „Klimat nie jest przewidywalny”.

Wyliczenie można dalej sklasyfikować na powiązane wartości i wartości surowe.

Różnica między wartościami skojarzonymi a wartościami surowymi

Powiązane wartości Surowe wartości
Różne typy danych Te same typy danych
Np .: wyliczenie {10,0.8, „Cześć”} Np .: wyliczenie {10,35,50}
Wartości są tworzone na podstawie stałej lub zmiennej Wstępnie wypełnione wartości
Różni się za każdym razem Wartość dla członka jest taka sama

Wyliczenie z powiązanymi wartościami

enum Student {
   case Name(String)
   case Mark(Int,Int,Int)
}

var studDetails = Student.Name("Swift 4")
var studMarks = Student.Mark(98,97,95)

switch studMarks {
   case .Name(let studName):
      print("Student name is: \(studName).")
   case .Mark(let Mark1, let Mark2, let Mark3):
      print("Student Marks are: \(Mark1),\(Mark2),\(Mark3).")
}

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

Student Marks are: 98,97,95.

Rozważmy na przykład dostęp do nazwisk studentów i ocen zabezpieczonych w trzech przedmiotach wyliczenie nazwa jest zadeklarowana jako student, a członkowie obecni w klasie enum to nazwa należąca do typu string, znaki są reprezentowane jako mark1, mark2 i mark3 typu danych Integer. Aby uzyskać dostęp do nazwiska ucznia lub ocen, które otrzymali

var studDetails = Student.Name("Swift")
var studMarks = Student.Mark(98,97,95)

Teraz obudowa przełącznika wydrukuje nazwisko ucznia, jeśli ten blok przypadku zostanie wykonany, w przeciwnym razie wydrukuje znaki zabezpieczone przez ucznia. Jeśli oba warunki nie spełnią się, zostanie wykonany blok domyślny.

Wyliczenie z wartościami surowymi

Nieprzetworzone wartości mogą być łańcuchami, znakami lub dowolnym typem liczb całkowitych lub zmiennoprzecinkowych. Każda wartość surowa musi być unikalna w ramach swojej deklaracji wyliczenia. Gdy liczby całkowite są używane dla wartości surowych, są one automatycznie zwiększane, jeśli nie określono wartości dla niektórych elementów członkowskich wyliczenia.

enum Month: Int {
   case January = 1, February, March, April, May, June, July, August,
      September, October, November, December
}

let yearMonth = Month.May.rawValue
print("Value of the Month is: \(yearMonth).")

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

Value of the Month is: 5.

Swift 4 zapewnia elastyczny blok konstrukcyjny umożliwiający używanie konstrukcji jako struktur. Korzystając z tych struktur, można raz zdefiniować metody i właściwości konstrukcji.

W przeciwieństwie do C i Objective C

  • Struktura nie musi wymagać plików implementacyjnych i interfejsu.

  • Struktura pozwala nam stworzyć pojedynczy plik i automatycznie rozszerzyć jego interfejs na inne bloki.

W Structure wartości zmiennych są kopiowane i przekazywane w kolejnych kodach poprzez zwrócenie kopii starych wartości, aby nie można było ich zmienić.

Składnia

Structures are defined with a 'Struct' Keyword.
struct nameStruct {
   Definition 1
   Definition 2
   ---
   Definition N
}

Definicja konstrukcji

Rozważmy na przykład, załóżmy, że musimy uzyskać dostęp do rekordu uczniów zawierającego oceny z trzech przedmiotów i znaleźć w sumie trzy przedmioty. Tutaj markStruct jest używany do inicjalizacji struktury z trzema znacznikami jako typem danych „Int”.

struct MarkStruct {
   var mark1: Int
   var mark2: Int
   var mark3: Int
}

Dostęp do struktury i jej właściwości

Dostęp do członków struktury uzyskuje się za pomocą nazwy struktury. Instancje struktury są inicjowane za pomocą słowa kluczowego „let”.

struct studentMarks {
   var mark1 = 100
   var mark2 = 200
   var mark3 = 300
}

let marks = studentMarks()
print("Mark1 is \(marks.mark1)")
print("Mark2 is \(marks.mark2)")
print("Mark3 is \(marks.mark3)")

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

Mark1 is 100
Mark2 is 200
Mark3 is 300

Oceny uczniów są dostępne po nazwie struktury „studentMarks”. Składowe struktury są inicjowane jako mark1, mark2, mark3 z wartościami typu integer. Następnie struktura studentMarks () jest przekazywana do 'marks' za pomocą słowa kluczowego 'let'. Odtąd „znaki” będą zawierały wartości elementów konstrukcji. Teraz wartości są drukowane po uzyskaniu dostępu do wartości elementów struktury za pomocą '.' z jego zainicjowanymi nazwami.

struct MarksStruct {
   var mark: Int

   init(mark: Int) {
      self.mark = mark
   }
}

var aStruct = MarksStruct(mark: 98)
var bStruct = aStruct     // aStruct and bStruct are two structs with the same value!
bStruct.mark = 97

print(aStruct.mark)      // 98
print(bStruct.mark)      // 97

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

98
97

Najlepsze praktyki użytkowania konstrukcji

Język Swift 4 zapewnia funkcjonalność definiowania struktur jako niestandardowych typów danych do budowania bloków funkcyjnych. Instancje struktury są przekazywane przez jej wartość do zdefiniowanych bloków w celu dalszych manipulacji.

Potrzeba posiadania struktur

  • Aby hermetyzować proste wartości danych.

  • Aby skopiować zhermetyzowane dane i związane z nimi właściwości za pomocą „wartości” zamiast „odniesień”.

  • Struktura „Kopiuj” i „Odnośnik”.

Struktury w Swift 4 przekazują swoim członkom swoje wartości, a nie referencje.

struct markStruct {
   var mark1: Int
   var mark2: Int
   var mark3: Int

   init(mark1: Int, mark2: Int, mark3: Int) {
      self.mark1 = mark1
      self.mark2 = mark2
      self.mark3 = mark3
   }
}

var marks = markStruct(mark1: 98, mark2: 96, mark3:100)
print(marks.mark1)
print(marks.mark2)
print(marks.mark3)

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

98
96
100

Inny przykład

struct markStruct {
   var mark1: Int
   var mark2: Int
   var mark3: Int
   
   init(mark1: Int, mark2: Int, mark3: Int) {
      self.mark1 = mark1
      self.mark2 = mark2
      self.mark3 = mark3
   }
}

var fail = markStruct(mark1: 34, mark2: 42, mark3: 13)

print(fail.mark1)
print(fail.mark2)
print(fail.mark3)

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

34
42
13

Strukturę „markStruct” definiuje się najpierw z jej elementami składowymi mark1, mark2 i mark3. Teraz zmienne klas składowych są inicjalizowane do przechowywania wartości całkowitych. Następnie tworzona jest kopia elementów struktury za pomocą słowa kluczowego „self”. Po utworzeniu kopii prętów konstrukcji blok strukturalny wraz ze znacznikami parametrów jest przekazywany do zmiennej „marks”, która będzie teraz zawierała oceny uczniów. Następnie znaki są drukowane jako 98, 96, 100. W następnym kroku dla tych samych elementów konstrukcji używa się innego wystąpienia o nazwie „fail”, aby wskazać te same elementy konstrukcji różnymi znakami. Następnie wyniki są teraz drukowane jako 34, 42, 13. To jasno wyjaśnia, że ​​struktury będą miały kopię zmiennych składowych, a następnie przekażą składowe do swoich przyszłych bloków funkcyjnych.

Klasy w Swift 4 to bloki konstrukcyjne elastycznych konstrukcji. Podobnie jak w przypadku stałych, zmiennych i funkcji, użytkownik może definiować właściwości i metody klas. Swift 4 zapewnia nam funkcjonalność, dzięki której deklarując klasy użytkownicy nie muszą tworzyć interfejsów ani plików implementacyjnych. Swift 4 pozwala nam tworzyć klasy jako pojedynczy plik, a zewnętrzne interfejsy zostaną utworzone domyślnie po zainicjowaniu klas.

Korzyści z zajęć

  • Dziedziczenie przejmuje właściwości jednej klasy do innej klasy

  • Rzutowanie typów umożliwia użytkownikowi sprawdzenie typu klasy w czasie wykonywania

  • Deinicjatory dbają o zwolnienie zasobów pamięci

  • Zliczanie odwołań umożliwia instancji klasy posiadanie więcej niż jednego odwołania

Wspólne cechy klas i struktur

  • Właściwości są zdefiniowane w celu przechowywania wartości
  • Indeksy są zdefiniowane w celu zapewnienia dostępu do wartości
  • Metody są inicjowane w celu poprawy funkcjonalności
  • Stan początkowy jest definiowany przez inicjatory
  • Funkcjonalność jest rozszerzona poza wartości domyślne
  • Potwierdzenie standardów funkcjonalności protokołów

Składnia

Class classname {
   Definition 1
   Definition 2
   --- 
   Definition N
}

Definicja klasy

class student {
   var studname: String
   var mark: Int 
   var mark2: Int 
}

Składnia tworzenia instancji

let studrecord = student()

Przykład

class MarksStruct {
   var mark: Int
   init(mark: Int) {
      self.mark = mark
   }
}

class studentMarks {
   var mark = 300
}

let marks = studentMarks()
print("Mark is \(marks.mark)")

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

Mark is 300

Dostęp do właściwości klasy jako typów odwołań

Dostęp do właściwości klasy można uzyskać za pomocą „.” składnia. Nazwa właściwości jest oddzielona znakiem „.” po nazwie instancji.

class MarksStruct {
   var mark: Int
   init(mark: Int) {
      self.mark = mark
   }
}

class studentMarks {
   var mark1 = 300
   var mark2 = 400
   var mark3 = 900
}

let marks = studentMarks()
print("Mark1 is \(marks.mark1)")
print("Mark2 is \(marks.mark2)")
print("Mark3 is \(marks.mark3)")

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

Mark1 is 300
Mark2 is 400
Mark3 is 900

Operatory tożsamości klas

Klasy w Swift 4 odwołują się do wielu stałych i zmiennych wskazujących na jedną instancję. Aby dowiedzieć się o stałych i zmiennych wskazujących na konkretną instancję klasy, używane są operatory tożsamości. Instancje klas są zawsze przekazywane przez odwołanie. W klasach wystąpienia NSString, NSArray i NSDictionary są zawsze przypisywane i przekazywane jako referencje do istniejącej instancji, a nie jako kopia.

Identyczne z operatorami Nie identyczne z operatorami
Użyty operator to (===) Użyty operator to (! ==)
Zwraca wartość true, gdy dwie stałe lub zmienne wskazują na to samo wystąpienie Zwraca wartość true, gdy dwie stałe lub zmienne wskazują na inną instancję
class SampleClass: Equatable {
   let myProperty: String
   init(s: String) {
      myProperty = s
   }
}

func ==(lhs: SampleClass, rhs: SampleClass) -> Bool {
   return lhs.myProperty == rhs.myProperty
}

let spClass1 = SampleClass(s: "Hello")
let spClass2 = SampleClass(s: "Hello")

spClass1 === spClass2 // false
print("\(spClass1)")

spClass1 !== spClass2 // true
print("\(spClass2)")

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

main.SampleClass
main.SampleClass

Język Swift 4 zapewnia właściwości dla klasy, wyliczenia lub struktury w celu skojarzenia wartości. Właściwości można dalej podzielić na Właściwości przechowywane i Właściwości obliczone.

Różnica między właściwościami przechowywanymi i obliczonymi

Majątek składowany Obliczona właściwość
Przechowuj wartości stałe i zmienne jako instancję Oblicz wartość zamiast ją zapisywać
Dostarczane przez klasy i struktury Dostarczane przez klasy, wyliczenia i struktury

Zarówno właściwości Stored, jak i Computed są skojarzone z typem instancji. Gdy właściwości są skojarzone z wartościami typu, jest to definiowane jako „Właściwości typu”. Właściwości przechowywane i obliczane są zwykle kojarzone z wystąpieniami określonego typu. Jednak właściwości mogą być również skojarzone z samym typem. Takie właściwości są znane jako właściwości typu. Korzysta się również z obserwatorów nieruchomości

  • Aby obserwować wartość przechowywanych właściwości
  • Aby obserwować właściwość dziedziczonej podklasy pochodzącej z nadklasy

Przechowywane właściwości

Swift 4 wprowadza koncepcję Stored Property do przechowywania wystąpień stałych i zmiennych. Przechowywane właściwości stałych są definiowane przez słowo kluczowe „let”, a przechowywane właściwości zmiennych za pomocą słowa kluczowego „var”.

  • Podczas definiowania Właściwość przechowywana zapewnia `` wartość domyślną ''
  • Podczas inicjalizacji użytkownik może inicjalizować i modyfikować wartości początkowe
struct Number {
   var digits: Int
   let pi = 3.1415
}

var n = Number(digits: 12345)
n.digits = 67

print("\(n.digits)")
print("\(n.pi)")

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

67
3.1415

Rozważ następujący wiersz w powyższym kodzie -

let pi = 3.1415

Tutaj zmienna pi jest inicjalizowana jako przechowywana wartość właściwości z instancją pi = 3,1415. Tak więc za każdym razem, gdy odwołujemy się do instancji, sama będzie miała wartość 3.1415.

Inną metodą przechowywania właściwości jest posiadanie stałych struktur. Zatem cała instancja struktur będzie traktowana jako „Przechowywane właściwości stałych”.

struct Number {
   var digits: Int
   let numbers = 3.1415
}

var n = Number(digits: 12345)
n.digits = 67

print("\(n.digits)")
print("\(n.numbers)")
n.numbers = 8.7

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

error: cannot assign to 'numbers' in 'n'
n.numbers = 8.7

Zamiast ponownej inicjalizacji „liczby” do 8,7 zwróci komunikat o błędzie wskazujący, że „liczba” jest zadeklarowana jako stała.

Leniwa nieruchomość przechowywana

Swift 4 zapewnia elastyczną właściwość o nazwie „Lazy Stored Property”, w której nie oblicza wartości początkowych, gdy zmienna jest inicjowana po raz pierwszy. Modyfikator „leniwy” jest używany przed deklaracją zmiennej, aby był przechowywany jako leniwa właściwość.

Leniwe właściwości są używane -

  • Aby opóźnić tworzenie obiektów.
  • Gdy właściwość jest zależna od innych części klasy, które nie są jeszcze znane
class sample {
   lazy var no = number()    // `var` declaration is required.
}

class number {
   var name = "Swift 4"
}

var firstsample = sample()
print(firstsample.no.name)

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

Swift 4

Zmienne instancji

W celu C właściwości przechowywane mają również zmienne instancji do celów kopii zapasowej w celu przechowywania wartości zadeklarowanych we właściwości przechowywanej.

Swift 4 integruje obie te koncepcje w jednej deklaracji „przechowywanej własności”. Zamiast posiadania odpowiedniej zmiennej instancji i wartości kopii zapasowej „właściwość przechowywana” zawiera wszystkie zintegrowane informacje zdefiniowane w jednym miejscu na temat właściwości zmiennych według nazwy zmiennej, typu danych i funkcji zarządzania pamięcią.

Obliczone właściwości

Zamiast przechowywać wartości obliczone właściwości zapewniają metodę pobierającą i opcjonalną metodę ustawiającą, która pośrednio pobiera i ustawia inne właściwości i wartości.

class sample {
   var no1 = 0.0, no2 = 0.0
   var length = 300.0, breadth = 150.0

   var middle: (Double, Double) {
      get {
         return (length / 2, breadth / 2)
      }
      
      set(axis){
         no1 = axis.0 - (length / 2)
         no2 = axis.1 - (breadth / 2)
      }
   }
}

var result = sample()
print(result.middle)
result.middle = (0.0, 10.0)

print(result.no1)
print(result.no2)

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

(150.0, 75.0)
-150.0
-65.0

Gdy obliczona właściwość pozostawi nową wartość jako niezdefiniowaną, wartość domyślna zostanie ustawiona dla tej konkretnej zmiennej.

Obliczone właściwości jako właściwości tylko do odczytu

Właściwość tylko do odczytu we właściwości obliczonej jest definiowana jako właściwość z funkcją pobierającą, ale bez metody ustawiającej. Jest zawsze używany do zwracania wartości. Dostęp do zmiennych dalej uzyskuje się poprzez „.” Składnia, ale nie można jej ustawić na inną wartość.

class film {
   var head = ""
   var duration = 0.0
   var metaInfo: [String:String] {
      return [
         "head": self.head,
         "duration":"\(self.duration)"
      ]
   }
}

var movie = film()
movie.head = "Swift 4 Properties"
movie.duration = 3.09

print(movie.metaInfo["head"]!)
print(movie.metaInfo["duration"]!)

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

Swift 4 Properties
3.09

Obliczone właściwości jako obserwatory właściwości

W języku Swift 4 do obserwowania wartości właściwości i reagowania na nie używane są obserwatory właściwości. Za każdym razem, gdy ustawiane są wartości właściwości, wywoływane są obserwatory właściwości. Oprócz leniwych przechowywanych właściwości możemy dodawać obserwatory właściwości do właściwości „dziedziczonej” za pomocą metody „przesłaniania”.

Obserwatory właściwości mogą być definiowane przez jedną z nich

  • Przed zapisaniem wartości - willset

  • Po zapisaniu nowej wartości - didset

  • Gdy właściwość jest ustawiona w inicjatorze, nie można wywołać obserwatorów willset i didset.

class Samplepgm {
   var counter: Int = 0 {
      willSet(newTotal){
         print("Total Counter is: \(newTotal)")
      }
      
      didSet {
         if counter > oldValue {
            print("Newly Added Counter \(counter - oldValue)")
         }
      }
   }
}

let NewCounter = Samplepgm()
NewCounter.counter = 100
NewCounter.counter = 800

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

Total Counter is: 100
Newly Added Counter 100
Total Counter is: 800
Newly Added Counter 700

Zmienne lokalne i globalne

Do obliczania i obserwowania właściwości deklarowane są zmienne lokalne i globalne.

Zmienne lokalne Zmienne globalne
Zmienne zdefiniowane w ramach funkcji, metody lub kontekstu zamknięcia. Zmienne zdefiniowane poza kontekstem funkcji, metody, zamknięcia lub typu.
Służy do przechowywania i pobierania wartości. Służy do przechowywania i pobierania wartości.
Przechowywane właściwości służą do pobierania i ustawiania wartości. Przechowywane właściwości służą do pobierania i ustawiania wartości.
Wykorzystywane są również obliczone właściwości. Wykorzystywane są również obliczone właściwości.

Właściwości typu

Właściwości są zdefiniowane w sekcji Definicja typu za pomocą nawiasów klamrowych {}, a zakres zmiennych został również zdefiniowany wcześniej. Do definiowania właściwości typu dla typów wartości używane jest słowo kluczowe „static”, a dla typów klas - słowo kluczowe „class”.

Składnia

struct Structname {
   static var storedTypeProperty = " "
   static var computedTypeProperty: Int {
      // return an Int value here
   }
}

enum Enumname {
   static var storedTypeProperty = " "
   static var computedTypeProperty: Int {
      // return an Int value here
   }
}

class Classname {
   class var computedTypeProperty: Int {
      // return an Int value here
   }
}

Zapytania i ustawianie właściwości

Podobnie jak właściwości instancji Właściwości typu są odpytywane i ustawiane za pomocą „.” Składnia tylko dla samego typu zamiast wskazywać na instancję.

struct StudMarks {
   static let markCount = 97
   static var totalCount = 0
   
   var InternalMarks: Int = 0 {
      didSet {
         if InternalMarks > StudMarks.markCount {
            InternalMarks = StudMarks.markCount
         }
         if InternalMarks > StudMarks.totalCount {
            StudMarks.totalCount = InternalMarks
         }
      }
   }
}

var stud1Mark1 = StudMarks()
var stud1Mark2 = StudMarks()

stud1Mark1.InternalMarks = 98
print(stud1Mark1.InternalMarks)

stud1Mark2.InternalMarks = 87
print(stud1Mark2.InternalMarks)

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

97
87

W języku Swift 4 Funkcje powiązane z określonymi typami nazywane są metodami. W Objective C klasy są używane do definiowania metod, podczas gdy język Swift 4 zapewnia użytkownikowi elastyczność w zakresie posiadania metod dla klas, struktur i wyliczeń.

Metody instancji

W języku Swift 4 do klas, struktur i wyliczeń można uzyskać dostęp za pośrednictwem metod instancji.

Metody instancji zapewniają funkcjonalność

  • Dostęp i modyfikowanie właściwości instancji
  • funkcjonalność związana z potrzebą instancji

Metoda instancji może być zapisana w nawiasach klamrowych {}. Ma niejawny dostęp do metod i właściwości wystąpienia typu. Gdy zostanie wywołana konkretna instancja typu, uzyska ona dostęp do tej konkretnej instancji.

Składnia

func funcname(Parameters) -> returntype {
   Statement1
   Statement2
   ---
   Statement N
   return parameters
}

Przykład

class calculations {
   let a: Int
   let b: Int
   let res: Int

   init(a: Int, b: Int) {
      self.a = a
      self.b = b
      res = a + b
   }
   
   func tot(c: Int) -> Int {
      return res - c
   }
   
   func result() {
      print("Result is: \(tot(c: 20))")
      print("Result is: \(tot(c: 50))")
   }
}
let pri = calculations(a: 600, b: 300)
pri.result()

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

Result is: 880
Result is: 850

Class Calculations definiuje dwie metody instancji -

  • init () jest zdefiniowany w celu dodania dwóch liczb a i b i zapisania ich w wyniku 'res'
  • tot () służy do odejmowania wartości „res” od przekazywania wartości „c”

Wreszcie, aby wydrukować metody obliczeń z wartościami a i b, jest wywoływana. Dostęp do metod instancji uzyskuje się za pomocą „.” składnia kropkowa

Nazwy parametrów lokalnych i zewnętrznych

Funkcje Swift 4 opisują zarówno lokalne, jak i globalne deklaracje swoich zmiennych. Podobnie, konwencje nazewnictwa metod Swift 4 są również podobne do konwencji Celu C. Jednak cechy deklaracji nazw parametrów lokalnych i globalnych są różne dla funkcji i metod. Pierwszy parametr w Swift 4 jest określany przez nazwy przyimków jako „with”, „for” i „by” w celu ułatwienia dostępu do konwencji nazewnictwa.

Swift 4 zapewnia elastyczność metod poprzez deklarowanie nazwy pierwszego parametru jako lokalnych nazw parametrów, a pozostałe nazwy parametrów jako globalne nazwy parametrów. Tutaj „no1” jest zadeklarowane przez metody Swift 4 jako lokalne nazwy parametrów. „no2” jest używane do deklaracji globalnych i dostępne za pośrednictwem programu.

class division {
   var count: Int = 0
   func incrementBy(no1: Int, no2: Int) {
      count = no1 / no2
      print(count)
   }
}

let counter = division()
counter.incrementBy(no1: 1800, no2: 3)
counter.incrementBy(no1: 1600, no2: 5)
counter.incrementBy(no1: 11000, no2: 3)

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

600
320
3666

Nazwa parametru zewnętrznego z # i _ Symbolem

Mimo że metody Swift 4 zapewniają nazwy pierwszych parametrów dla deklaracji lokalnych, użytkownik ma możliwość modyfikowania nazw parametrów z deklaracji lokalnych na globalne. Można to zrobić, poprzedzając symbol „#” nazwą pierwszego parametru. W ten sposób pierwszy parametr jest dostępny globalnie w modułach.

Kiedy użytkownik potrzebuje dostępu do kolejnych nazw parametrów z nazwą zewnętrzną, nazwa metody jest nadpisywana przy pomocy symbolu „_”.

class multiplication {
   var count: Int = 0
   func incrementBy(no1: Int, no2: Int) {
      count = no1 * no2
      print(count)
   }
}

let counter = multiplication()

counter.incrementBy(no1: 800, no2: 3)
counter.incrementBy(no1: 100, no2: 5)
counter.incrementBy(no1: 15000, no2: 3)

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

2400
500
45000

Własność własna w metodach

Metody mają niejawną właściwość znaną jako „self” dla wszystkich jej zdefiniowanych wystąpień typu. Właściwość „Self” służy do odwoływania się do bieżących instancji dla zdefiniowanych metod.

class calculations {
   let a: Int
   let b: Int
   let res: Int

   init(a: Int, b: Int) {
      self.a = a
      self.b = b
      res = a + b
      print("Inside Self Block: \(res)")
   }
   
   func tot(c: Int) -> Int {
      return res - c
   }
   
   func result() {
      print("Result is: \(tot(c: 20))")
      print("Result is: \(tot(c: 50))")
   }
}

let pri = calculations(a: 600, b: 300)
let sum = calculations(a: 1200, b: 300)

pri.result()
sum.result()

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

Inside Self Block: 900
Inside Self Block: 1500
Result is: 880
Result is: 850
Result is: 1480
Result is: 1450

Modyfikowanie typów wartości z metod instancji

W języku Swift 4 struktury i wyliczenia należą do typów wartości, których nie można zmienić za pomocą metod instancji. Jednak język Swift 4 zapewnia elastyczność w modyfikowaniu typów wartości poprzez „mutowanie” zachowania. Mutate dokona wszelkich zmian w metodach instancji i powróci do pierwotnej postaci po wykonaniu metody. Ponadto właściwość „self” tworzy nową instancję dla jej niejawnej funkcji i zastępuje istniejącą metodę po jej wykonaniu

struct area {
   var length = 1
   var breadth = 1
   
   func area() -> Int {
      return length * breadth
   }
   mutating func scaleBy(res: Int) {
      length *= res
      breadth *= res
      print(length)
      print(breadth)
   }
}

var val = area(length: 3, breadth: 5)
val.scaleBy(res: 3)
val.scaleBy(res: 30)
val.scaleBy(res: 300)

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

9
15
270
450
81000
135000

Własność metody mutacji

Mutowanie metod w połączeniu z właściwością „self” przypisuje nową instancję do zdefiniowanej metody.

struct area {
   var length = 1
   var breadth = 1
   func area() -> Int {
      return length * breadth
   }
   mutating func scaleBy(res: Int) {
      self.length *= res
      self.breadth *= res
      print(length)
      print(breadth)
   }
}

var val = area(length: 3, breadth: 5)
val.scaleBy(res: 13)

Uruchamiając powyższy program za pomocą placu zabaw, otrzymujemy następujący wynik. -

39
65

Metody typu

Gdy wywoływana jest określona instancja metody, jest ona wywoływana jako metoda instancji; a kiedy metoda wywołuje określony typ metody, nazywana jest „Metody typu”. Metody typu dla „klas” są definiowane za pomocą słowa kluczowego „func”, a struktury i metody typu wyliczeń są definiowane za pomocą słowa kluczowego „static” przed słowem kluczowym „func”.

Metody typu są wywoływane i dostępne przez '.' składnia, w której zamiast wywoływać określoną instancję, wywoływana jest cała metoda.

class Math {
   class func abs(number: Int) -> Int {
      if number < 0 {
         return (-number)
      } else {
         return number
      }
   }
}

struct absno {
   static func abs(number: Int) -> Int {
      if number < 0 {
         return (-number)
      } else {
         return number
      }
   }
}

let no = Math.abs(number: -35)
let num = absno.abs(number: -5)

print(no)
print(num)

Uruchamiając powyższy program za pomocą placu zabaw, otrzymujemy następujący wynik. -

35
5

Dostęp do elementów składowych kolekcji, sekwencji i listy w klasach, strukturach i wyliczeniach odbywa się za pomocą indeksów dolnych. Te indeksy służą do przechowywania i pobierania wartości za pomocą indeksu. Dostęp do elementów tablicy uzyskuje się za pomocą someArray [index], a do kolejnych elementów składowych w instancji Dictionary można uzyskać dostęp jako someDicitonary [klucz].

W przypadku jednego typu indeksy dolne mogą obejmować od jednej do wielu deklaracji. Możemy użyć odpowiedniego indeksu, aby przeciążyć typ wartości indeksu przekazanej do indeksu. Indeksy dolne wahają się również od pojedynczego wymiaru do wielu wymiarów, zgodnie z wymaganiami użytkowników w zakresie deklaracji typu danych wejściowych.

Składnia deklaracji indeksu dolnego i jej użycie

Podsumujmy obliczone właściwości. Również indeksy dolne mają taką samą składnię, jak obliczone właściwości. W przypadku instancji typu zapytania indeksy dolne są zapisywane w nawiasach kwadratowych, po których następuje nazwa instancji. Składnia indeksu ma taką samą strukturę jak w przypadku „metody instancji” i „właściwości obliczonej”. Słowo kluczowe „subscript” służy do definiowania indeksów, a użytkownik może określić jeden lub wiele parametrów z ich typami zwracanymi. Indeksy mogą mieć właściwości tylko do odczytu lub tylko do odczytu, a instancje są przechowywane i pobierane za pomocą właściwości „getter” i „setter”, podobnie jak właściwości obliczone.

Składnia

subscript(index: Int) −> Int {
   get {
      // used for subscript value declarations
   }
   set(newValue) {
      // definitions are written here
   }
}

Przykład 1

struct subexample {
   let decrementer: Int
   subscript(index: Int) -> Int {
      return decrementer / index
   }
}
let division = subexample(decrementer: 100)

print("The number is divisible by \(division[9]) times")
print("The number is divisible by \(division[2]) times")
print("The number is divisible by \(division[3]) times")
print("The number is divisible by \(division[5]) times")
print("The number is divisible by \(division[7]) times")

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

The number is divisible by 11 times
The number is divisible by 50 times
The number is divisible by 33 times
The number is divisible by 20 times
The number is divisible by 14 times

Przykład 2

class daysofaweek {
   private var days = ["Sunday", "Monday", "Tuesday", "Wednesday",
      "Thursday", "Friday", "saturday"]
   subscript(index: Int) -> String {
      get {
         return days[index]
      }
      set(newValue) {
         self.days[index] = newValue
      }
   }
}
var p = daysofaweek()

print(p[0])
print(p[1])
print(p[2])
print(p[3])

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

Sunday
Monday
Tuesday
Wednesday

Opcje w indeksie dolnym

Indeksy dolne mają od jednego do wielu parametrów wejściowych, a te parametry wejściowe również należą do dowolnego typu danych. Mogą również używać zmiennych i zmiennych parametrów. Indeksy dolne nie mogą podawać domyślnych wartości parametrów ani używać żadnych parametrów wejściowych i wyjściowych.

Definiowanie wielu indeksów dolnych nazywane jest „przeciążeniem indeksów dolnych”, w przypadku których klasa lub struktura może zapewnić wiele definicji indeksów dolnych zgodnie z wymaganiami. Te liczne indeksy dolne są wywnioskowane na podstawie typów wartości zadeklarowanych w nawiasach dolnych.

struct Matrix {
   let rows: Int, columns: Int
   var print: [Double]
   init(rows: Int, columns: Int) {
      self.rows = rows
      self.columns = columns
      print = Array(count: rows * columns, repeatedValue: 0.0)
   }
   subscript(row: Int, column: Int) -> Double {
      get {
         return print[(row * columns) + column]
      }
      set {
         print[(row * columns) + column] = newValue
      }
   }
}
var mat = Matrix(rows: 3, columns: 3)

mat[0,0] = 1.0
mat[0,1] = 2.0
mat[1,0] = 3.0
mat[1,1] = 5.0

print("\(mat[0,0])")

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

1.0

Skrypt Swift 4 obsługuje jeden parametr do wielu deklaracji parametrów dla odpowiednich typów danych. Program deklaruje strukturę „Matrix” jako macierz tablicową 2 * 2 wymiarową do przechowywania typów danych „Double”. Parametr Matrix jest wprowadzany z typami danych Integer do deklarowania wierszy i kolumn.

Nowa instancja Matrix jest tworzona przez przekazanie liczby wierszy i kolumn do inicjalizacji, jak pokazano poniżej.

var mat = Matrix(rows: 3, columns: 3)

Wartości macierzy można zdefiniować, przekazując wartości wierszy i kolumn do indeksu dolnego, oddzielone przecinkiem, jak pokazano poniżej.

mat[0,0] = 1.0  
mat[0,1] = 2.0
mat[1,0] = 3.0
mat[1,1] = 5.0

Zdolność do przyjęcia większej liczby form jest definiowana jako dziedziczenie. Ogólnie klasa może dziedziczyć metody, właściwości i funkcjonalności z innej klasy. Klasy można dalej podzielić na podklasy i superklasy.

  • Sub Class - gdy klasa dziedziczy właściwości, metody i funkcje z innej klasy, jest nazywana podklasą

  • Super Class - Klasa zawierająca właściwości, metody i funkcje do dziedziczenia innych klas od siebie jest nazywana superklasą

Klasy Swift 4 zawierają nadklasę, która wywołuje i uzyskuje dostęp do metod, właściwości, funkcji i metod nadpisywania. Ponadto obserwatory właściwości są również używane do dodawania właściwości i modyfikowania przechowywanych lub obliczanych metod właściwości.

Klasa podstawowa

Klasa, która nie dziedziczy metod, właściwości ani funkcji z innej klasy, nazywana jest „klasą bazową”.

class StudDetails {
   var stname: String!
   var mark1: Int!
   var mark2: Int!
   var mark3: Int!
   
   init(stname: String, mark1: Int, mark2: Int, mark3: Int) {
      self.stname = stname
      self.mark1 = mark1
      self.mark2 = mark2
      self.mark3 = mark3
   }
}

let stname = "Swift 4"
let mark1 = 98
let mark2 = 89
let mark3 = 76

print(stname)
print(mark1)
print(mark2)
print(mark3)

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

Swift 4
98
89
76

Klasa z nazwą klasy StudDetails jest tutaj zdefiniowana jako klasa bazowa, która jest używana do przechowywania nazwisk uczniów i trzech przedmiotów oznaczonych jako mark1, mark2 i mark3. Słowo kluczowe „let” służy do inicjalizacji wartości dla klasy bazowej, a wartość klasy bazowej jest wyświetlana na placu zabaw przy pomocy funkcji „print”.

Podklasa

Oparcie nowej klasy na istniejącej klasie jest definiowane jako „podklasa”. Podklasa dziedziczy właściwości, metody i funkcje swojej klasy bazowej. Aby zdefiniować podklasę, znak „:” jest używany przed nazwą klasy bazowej

class StudDetails {
   var mark1: Int;
   var mark2: Int;
   
   init(stm1:Int, results stm2:Int) {
      mark1 = stm1;
      mark2 = stm2;
   }
   func print() {
      print("Mark1:\(mark1), Mark2:\(mark2)")
   }
}

class display : StudDetails {
   init() {
      super.init(stm1: 93, results: 89)
   }
}

let marksobtained = display()
marksobtained.print()

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

Mark1:93, Mark2:89

Klasa „StudDetails” jest zdefiniowana jako superklasa, w której deklarowane są oceny uczniów, a podklasa „display” jest używana do dziedziczenia ocen z jej superklasy. Podklasa definiuje oceny uczniów i wywołuje metodę print () w celu wyświetlenia oceny uczniów.

Nadrzędny

Dostęp do instancji superklasy, metod typu, instancji, właściwości typu i podklasy indeksów zapewnia koncepcję przesłaniania. Słowo kluczowe „override” służy do przesłonięcia metod zadeklarowanych w nadklasie.

Dostęp do metod, właściwości i indeksów superklasy

Słowo kluczowe „super” jest używane jako przedrostek umożliwiający dostęp do metod, właściwości i indeksów zadeklarowanych w superklasie

Nadrzędny Dostęp do metod, właściwości i indeksów
Metody super.somemethod ()
Nieruchomości super.someProperty ()
Indeksy super [someIndex]

Metody zastępujące

Dziedziczone metody instancji i typów można przesłonić słowem kluczowym „override” do naszych metod zdefiniowanych w naszej podklasie. Tutaj print () jest zastępowany w podklasie, aby uzyskać dostęp do właściwości type wspomnianej w superklasie print (). Również nowa instancja super klasy cricket () jest tworzona jako „cricinstance”.

class cricket {
   func print() {
      print("Welcome to Swift 4 Super Class")
   }
}

class tennis: cricket {
   override func print() {
      print("Welcome to Swift 4 Sub Class")
   }
}

let cricinstance = cricket()
cricinstance.print()

let tennisinstance = tennis()
tennisinstance.print()

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

Welcome to Swift Super Class
Welcome to Swift Sub Class

Zastąpienie właściwości

Można przesłonić dziedziczone wystąpienie lub właściwość klasy, aby zapewnić własny niestandardowy moduł pobierający i ustawiający dla tej właściwości lub dodać obserwatory właściwości, aby umożliwić obserwowanie właściwości zastępującej, gdy zmienia się podstawowa wartość właściwości.

Zastępowanie metod pobierających i ustawiających właściwości

Swift 4 umożliwia użytkownikowi dostarczenie niestandardowego programu pobierającego i ustawiającego, aby zastąpić dziedziczoną właściwość, niezależnie od tego, czy jest to właściwość przechowywana, czy obliczana. Podklasa nie zna odziedziczonej nazwy i typu właściwości. Dlatego ważne jest, aby użytkownik określił w podklasie nazwę i typ nadpisującej właściwości określonej w superklasie.

Można to zrobić na dwa sposoby -

  • Gdy ustawiający jest zdefiniowany do przesłaniania właściwości, użytkownik musi również zdefiniować metodę pobierającą.

  • Kiedy nie chcemy modyfikować dziedziczonej wartości pobierającej właściwość, możemy po prostu przekazać odziedziczoną wartość składnią „super.someProperty” do superklasy.

class Circle {
   var radius = 12.5
   var area: String {
      return "of rectangle for \(radius) "
   }
}

class Rectangle: Circle {
   var print = 7
   override var area: String {
      return super.area + " is now overridden as \(print)"
   }
}

let rect = Rectangle()
rect.radius = 25.0
rect.print = 3
print("Radius \(rect.area)")

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

Radius of rectangle for 25.0  is now overridden as 3

Zastępowanie obserwatorów właściwości

Gdy trzeba dodać nową właściwość do dziedziczonej właściwości, w języku Swift 4 wprowadzono pojęcie „przesłaniania właściwości”. Powiadamia to użytkownika o zmianie odziedziczonej wartości właściwości. Jednak zastępowanie nie ma zastosowania w przypadku dziedziczonych stałych przechowywanych właściwości i dziedziczonych obliczonych właściwości tylko do odczytu.

class Circle {
   var radius = 12.5
   var area: String {
     return "of rectangle for \(radius) "
   }
}

class Rectangle: Circle {
   var print = 7
   override var area: String {
      return super.area + " is now overridden as \(print)"
   }
}

let rect = Rectangle()
rect.radius = 25.0
rect.print = 3
print("Radius \(rect.area)")

class Square: Rectangle {
   override var radius: Double {
      didSet {
         print = Int(radius/5.0)+1
      }
   }
}

let sq = Square()
sq.radius = 100.0
print("Radius \(sq.area)")

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

Radius of rectangle for 25.0  is now overridden as 3
Radius of rectangle for 100.0  is now overridden as 21

Ostateczna właściwość, aby zapobiec zastępowaniu

Gdy użytkownik nie chce, aby inni mieli dostęp do metod, właściwości lub indeksów superklasy, Swift 4 wprowadza właściwość „final”, aby zapobiec nadpisywaniu. Po zadeklarowaniu właściwości „final”, indeksy nie pozwolą na nadpisanie metod superklasy, właściwości i ich indeksów. Nie ma przepisu, aby mieć „ostateczną” właściwość w „superklasie”. Po zadeklarowaniu właściwości „final” użytkownik jest ograniczony do tworzenia dalszych podklas.

final class Circle {
   final var radius = 12.5
   var area: String {
      return "of rectangle for \(radius) "
   }
}

class Rectangle: Circle {
   var print = 7
   override var area: String {
      return super.area + " is now overridden as \(print)"
   }
}

let rect = Rectangle()
rect.radius = 25.0
rect.print = 3
print("Radius \(rect.area)")

class Square: Rectangle {
   override var radius: Double {
      didSet {
         print = Int(radius/5.0)+1
      }
   }
}

let sq = Square()
sq.radius = 100.0
print("Radius \(sq.area)")

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

<stdin>:14:18: error: var overrides a 'final' var
override var area: String {
^
<stdin>:7:9: note: overridden declaration is here
var area: String {
^
<stdin>:12:11: error: inheritance from a final class 'Circle'
class Rectangle: Circle {
^
<stdin>:25:14: error: var overrides a 'final' var
override var radius: Double {
^
<stdin>:6:14: note: overridden declaration is here
final var radius = 12.5

Ponieważ superklasa jest zadeklarowana jako „ostateczna”, a jej typy danych są również deklarowane jako „ostateczne”, program nie pozwoli na dalsze tworzenie podklas i będzie generował błędy.

Klasy, struktury i wyliczenia raz zadeklarowane w Swift 4 są inicjowane w celu przygotowania wystąpienia klasy. Wartość początkowa jest inicjowana dla przechowywanej właściwości, a także dla nowych instancji wartości są inicjowane, aby przejść dalej. Słowo kluczowe do tworzenia funkcji inicjalizacyjnej jest wykonywane przez metodę 'init ()'. Inicjator Swift 4 różni się od Objective-C tym, że nie zwraca żadnych wartości. Jego funkcją jest sprawdzenie inicjalizacji nowo utworzonych instancji przed ich przetworzeniem. Swift 4 zapewnia również proces „deinicjalizacji” w celu wykonywania operacji zarządzania pamięcią po zwolnieniu instancji.

Rola inicjatora dla przechowywanych właściwości

Właściwość przechowywana musi zainicjować instancje dla swoich klas i struktur przed przetworzeniem instancji. Przechowywane właściwości używają inicjatora do przypisywania i inicjowania wartości, eliminując w ten sposób potrzebę wywoływania obserwatorów właściwości. Inicjator jest używany we właściwości przechowywanej

  • Aby utworzyć wartość początkową.

  • Aby przypisać domyślną wartość właściwości w definicji właściwości.

  • Do zainicjowania instancji dla określonego typu danych używana jest funkcja „init ()”. W funkcji init () nie są przekazywane żadne argumenty.

Składnia

init() {
   //New Instance initialization goes here
}

Przykład

struct rectangle {
   var length: Double
   var breadth: Double
   init() {
      length = 6
      breadth = 12
   }
}

var area = rectangle()
print("area of rectangle is \(area.length*area.breadth)")

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

area of rectangle is 72.0

Tutaj struktura „prostokąt” jest inicjalizowana z długością i szerokością elementów jako typami danych „Double”. Init () służy do inicjalizacji wartości dla nowo utworzonych elementów length i double. Powierzchnia prostokąta jest obliczana i zwracana przez wywołanie funkcji rectangle.

Domyślne ustawienie wartości właściwości

Język Swift 4 udostępnia funkcję Init () do inicjowania przechowywanych wartości właściwości. Ponadto użytkownik ma możliwość domyślnej inicjalizacji wartości właściwości podczas deklarowania członków klasy lub struktury. Gdy właściwość przyjmuje tę samą wartość w całym programie, możemy zadeklarować ją w samej sekcji deklaracji, zamiast inicjować ją w init (). Domyślne ustawienie wartości właściwości umożliwia użytkownikowi, gdy dziedziczenie jest zdefiniowane dla klas lub struktur.

struct rectangle {
   var length = 6
   var breadth = 12
}

var area = rectangle()
print("area of rectangle is \(area.length*area.breadth)")

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

area of rectangle is 72

Tutaj zamiast deklarować długość i szerokość w init (), wartości są inicjalizowane w samej deklaracji.

Inicjalizacja parametrów

W języku Swift 4 użytkownik ma możliwość inicjowania parametrów w ramach definicji inicjatora za pomocą funkcji init ().

struct Rectangle {
   var length: Double
   var breadth: Double
   var area: Double
   
   init(fromLength length: Double, fromBreadth breadth: Double) {
      self.length = length
      self.breadth = breadth
      area = length * breadth
   }
   init(fromLeng leng: Double, fromBread bread: Double) {
      self.length = leng
      self.breadth = bread
      area = leng * bread
   }
}

let ar = Rectangle(fromLength: 6, fromBreadth: 12)
print("area is: \(ar.area)")

let are = Rectangle(fromLeng: 36, fromBread: 12)
print("area is: \(are.area)")

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

area is: 72.0
area is: 432.0

Parametry lokalne i zewnętrzne

Parametry inicjalizacji mają zarówno lokalne, jak i globalne nazwy parametrów podobne do parametrów funkcji i metod. Deklaracja parametru lokalnego jest używana do uzyskiwania dostępu w treści inicjalizacji, a deklaracja parametru zewnętrznego jest używana do wywołania inicjatora. Inicjatory Swift 4 różnią się od inicjatorów funkcji i metod tym, że nie identyfikują, który inicjator jest używany do wywoływania jakich funkcji.

Aby temu zaradzić, Swift 4 wprowadza automatyczną nazwę zewnętrzną dla każdego parametru init (). Ta automatyczna nazwa zewnętrzna jest równoważna nazwie lokalnej zapisywanej przed każdym parametrem inicjującym.

struct Days {
   let sunday, monday, tuesday: Int
   init(sunday: Int, monday: Int, tuesday: Int) {
      self.sunday = sunday
      self.monday = monday
      self.tuesday = tuesday
   }
   init(daysofaweek: Int) {
      sunday = daysofaweek
      monday = daysofaweek
      tuesday = daysofaweek
   }
}

let week = Days(sunday: 1, monday: 2, tuesday: 3)
print("Days of a Week is: \(week.sunday)")
print("Days of a Week is: \(week.monday)")
print("Days of a Week is: \(week.tuesday)")

let weekdays = Days(daysofaweek: 4)
print("Days of a Week is: \(weekdays.sunday)")
print("Days of a Week is: \(weekdays.monday)")
print("Days of a Week is: \(weekdays.tuesday)")

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

Days of a Week is: 1
Days of a Week is: 2
Days of a Week is: 3
Days of a Week is: 4
Days of a Week is: 4
Days of a Week is: 4

Parametry bez nazw zewnętrznych

Gdy nazwa zewnętrzna nie jest potrzebna do podkreślenia inicjalizacji, do przesłonięcia domyślnego zachowania używany jest znak „_”.

struct Rectangle {
   var length: Double
   
   init(frombreadth breadth: Double) {
      length = breadth * 10
   }
   init(frombre bre: Double) {
      length = bre * 30
   }
   init(_ area: Double) {
      length = area
   }
}

let rectarea = Rectangle(180.0)
print("area is: \(rectarea.length)")

let rearea = Rectangle(370.0)
print("area is: \(rearea.length)")

let recarea = Rectangle(110.0)
print("area is: \(recarea.length)")

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

area is: 180.0
area is: 370.0
area is: 110.0

Opcjonalne typy nieruchomości

Jeśli przechowywana właściwość w jakimś wystąpieniu nie zwraca żadnej wartości, wówczas właściwość jest zadeklarowana z typem „opcjonalnym” wskazującym, że „brak wartości” jest zwracana dla tego konkretnego typu. Gdy przechowywana właściwość jest zadeklarowana jako „opcjonalna”, automatycznie inicjalizuje wartość na „nil” podczas samej inicjalizacji.

struct Rectangle {
   var length: Double?
   
   init(frombreadth breadth: Double) {
      length = breadth * 10
   }
   init(frombre bre: Double) {
      length = bre * 30
   }
   init(_ area: Double) {
      length = area
   }
}

let rectarea = Rectangle(180.0)
print("area is: \(rectarea.length)")

let rearea = Rectangle(370.0)
print("area is: \(rearea.length)")

let recarea = Rectangle(110.0)
print("area is: \(recarea.length)")

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

area is: Optional(180.0)
area is: Optional(370.0)
area is: Optional(110.0)

Modyfikowanie stałych właściwości podczas inicjalizacji

Inicjalizacja umożliwia również użytkownikowi modyfikację wartości stałej właściwości. Podczas inicjalizacji właściwość klasy pozwala na modyfikowanie instancji jej klas przez superklasę, a nie przez podklasę. Rozważmy na przykład, że w poprzednim programie „długość” została zadeklarowana jako „zmienna” w klasie głównej. Poniższa zmienna programu „długość” jest modyfikowana jako zmienna „stała”.

struct Rectangle {
   let length: Double?
   
   init(frombreadth breadth: Double) {
      length = breadth * 10
   }
   init(frombre bre: Double) {
      length = bre * 30
   }
   init(_ area: Double) {
      length = area
   }
}

let rectarea = Rectangle(180.0)
print("area is: \(rectarea.length)")

let rearea = Rectangle(370.0)
print("area is: \(rearea.length)")

let recarea = Rectangle(110.0)
print("area is: \(recarea.length)")

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

area is: Optional(180.0)
area is: Optional(370.0)
area is: Optional(110.0)

Domyślne inicjatory

Domyślne inicjatory zapewniają nowe wystąpienie dla wszystkich zadeklarowanych właściwości klasy bazowej lub struktury z wartościami domyślnymi.

class defaultexample {
   var studname: String?
   var stmark = 98
   var pass = true
}
var result = defaultexample()

print("result is: \(result.studname)")
print("result is: \(result.stmark)")
print("result is: \(result.pass)")

Kiedy uruchomimy powyższy program za pomocą placu zabaw, otrzymamy następujący wynik. -

result is: nil
result is: 98
result is: true

Powyższy program jest zdefiniowany z nazwą klasy jako „przykład domyślny”. Trzy funkcje składowe są domyślnie inicjowane jako „nazwa studium?” aby przechowywać wartości „nil”, „stmark” jako 98 i „pass” jako wartość logiczną „true”. Podobnie wartości składowe w klasie mogą być inicjowane jako domyślne przed przetworzeniem typów składowych klasy.

Inicjatory składowe dla typów struktur

Jeśli użytkownik nie dostarczy niestandardowych inicjatorów, typy struktur w języku Swift 4 automatycznie otrzymają „inicjator składowy”. Jego główną funkcją jest inicjowanie nowych instancji struktury z domyślną inicjalizacją składową, a następnie nowe właściwości instancji są przekazywane do elementu inicjalizacji według nazwy.

struct Rectangle {
   var length = 100.0, breadth = 200.0
}
let area = Rectangle(length: 24.0, breadth: 32.0)

print("Area of rectangle is: \(area.length)")
print("Area of rectangle is: \(area.breadth)")

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

Area of rectangle is: 24.0
Area of rectangle is: 32.0

Struktury są domyślnie inicjowane dla ich funkcji członkostwa podczas inicjalizacji dla „length” jako „100.0” i „width” jako „200.0”. Ale wartości są nadpisywane podczas przetwarzania zmiennych długości i szerokości jako 24,0 i 32,0.

Delegowanie inicjatora dla typów wartości

Delegowanie inicjatora jest zdefiniowane jako wywoływanie inicjatorów z innych inicjatorów. Jego główną funkcją jest działanie jako możliwość ponownego użycia, aby uniknąć duplikowania kodu w wielu inicjatorach.

struct Stmark {
   var mark1 = 0.0, mark2 = 0.0
}
struct stdb {
   var m1 = 0.0, m2 = 0.0
}

struct block {
   var average = stdb()
   var result = Stmark()
   init() {}
   init(average: stdb, result: Stmark) {
      self.average = average
      self.result = result
   }

   init(avg: stdb, result: Stmark) {
      let tot = avg.m1 - (result.mark1 / 2)
      let tot1 = avg.m2 - (result.mark2 / 2)
      self.init(average: stdb(m1: tot, m2: tot1), result: result)
   }
}

let set1 = block()
print("student result is: \(set1.average.m1, set1.average.m2)
\(set1.result.mark1, set1.result.mark2)")

let set2 = block(average: stdb(m1: 2.0, m2: 2.0),
result: Stmark(mark1: 5.0, mark2: 5.0))
print("student result is: \(set2.average.m1, set2.average.m2)
\(set2.result.mark1, set2.result.mark2)")

let set3 = block(avg: stdb(m1: 4.0, m2: 4.0),
result: Stmark(mark1: 3.0, mark2: 3.0))
print("student result is: \(set3.average.m1, set3.average.m2)
\(set3.result.mark1, set3.result.mark2)")

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

(0.0,0.0) (0.0,0.0)
(2.0,2.0) 5.0,5.0)
(2.5,2.5) (3.0,3.0)

Reguły delegowania inicjatora

Typy wartości Typy klas
Dziedziczenie nie jest obsługiwane w przypadku typów wartości, takich jak struktury i wyliczenia. Odwoływanie się do innych inicjatorów odbywa się za pośrednictwem self.init Dziedziczenie jest obsługiwane. Sprawdza, czy wszystkie przechowywane wartości właściwości są zainicjowane

Dziedziczenie i inicjalizacja klas

Typy klas mają dwa rodzaje inicjatorów, aby sprawdzić, czy zdefiniowane właściwości przechowywane otrzymują wartość początkową, mianowicie wyznaczone inicjatory i wygodne inicjatory.

Wyznaczone inicjatory i wygodne inicjatory

Wyznaczony inicjator Wygodny inicjator
Uważane za podstawowe inicjalizacje dla klasy Uważany za wspomagający inicjalizację dla klasy
Wszystkie właściwości klasy są inicjowane i do dalszej inicjalizacji jest wywoływany odpowiedni inicjator nadklasy Wyznaczony inicjator jest wywoływany z wygodnym inicjatorem w celu utworzenia wystąpienia klasy dla określonego przypadku użycia lub typu wartości wejściowej
Co najmniej jeden wyznaczony inicjator jest zdefiniowany dla każdej klasy Nie ma potrzeby definiowania obowiązkowych wygodnych inicjatorów, gdy klasa nie wymaga inicjatorów.
Init (parametry) {instrukcje} wygoda init (parametry) {instrukcje}

Program dla wyznaczonych inicjatorów

class mainClass {
   var no1 : Int // local storage
   init(no1 : Int) {
      self.no1 = no1 // initialization
   }
}

class subClass : mainClass {
   var no2 : Int // new subclass storage
   init(no1 : Int, no2 : Int) {
      self.no2 = no2 // initialization
      super.init(no1:no1) // redirect to superclass
   }
}

let res = mainClass(no1: 10)
let print = subClass(no1: 10, no2: 20)

print("res is: \(res.no1)")
print("res is: \(print.no1)")
print("res is: \(print.no2)")

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

res is: 10
res is: 10
res is: 20

Program dla wygodnych inicjatorów

class mainClass {
   var no1 : Int // local storage
   init(no1 : Int) {
      self.no1 = no1 // initialization
   }
}

class subClass : mainClass {
   var no2 : Int
   init(no1 : Int, no2 : Int) {
      self.no2 = no2
      super.init(no1:no1)
   }
   // Requires only one parameter for convenient method
   override convenience init(no1: Int) {
      self.init(no1:no1, no2:0)
   }
}

let res = mainClass(no1: 20)
let print = subClass(no1: 30, no2: 50)

print("res is: \(res.no1)")
print("res is: \(print.no1)")
print("res is: \(print.no2)")

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

res is: 20
res is: 30
res is: 50

Dziedziczenie i zastępowanie inicjatora

Swift 4 domyślnie nie zezwala swoim podklasom na dziedziczenie inicjatorów nadklasy dla ich typów składowych. Dziedziczenie ma zastosowanie do inicjatorów klasy Super tylko w pewnym stopniu, co zostanie omówione w sekcji Automatyczne dziedziczenie inicjatorów.

Gdy użytkownik musi mieć zdefiniowane inicjatory w superklasie, podklasa z inicjatorami musi zostać zdefiniowana przez użytkownika jako implementacja niestandardowa. Gdy nadpisywanie ma być wykonywane przez podklasę, należy zadeklarować słowo kluczowe „override” superklasy.

class sides {
   var corners = 4
   var description: String {
      return "\(corners) sides"
   }
}

let rectangle = sides()
print("Rectangle: \(rectangle.description)")

class pentagon: sides {
   override init() {
      super.init()
      corners = 5
   }
}

let bicycle = pentagon()
print("Pentagon: \(bicycle.description)")

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

Rectangle: 4 sides
Pentagon: 5 sides

Wyznaczone i wygodne inicjatory w akcji

class Planet {
   var name: String
   init(name: String) {
      self.name = name
   }
   convenience init() {
      self.init(name: "[No Planets]")
   }
}

let plName = Planet(name: "Mercury")
print("Planet name is: \(plName.name)")

let noplName = Planet()
print("No Planets like that: \(noplName.name)")

class planets: Planet {
   var count: Int
   init(name: String, count: Int) {
      self.count = count
      super.init(name: name)
   }
   override convenience init(name: String) {
      self.init(name: name, count: 1)
   }
}

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

Planet name is: Mercury
No Planets like that: [No Planets]

Dostępny inicjalizator

Należy powiadomić użytkownika o błędach inicjatora podczas definiowania klasy, struktury lub wartości wyliczenia. Inicjalizacja zmiennych czasami kończy się niepowodzeniem z powodu -

  • Nieprawidłowe wartości parametrów.
  • Brak wymaganego źródła zewnętrznego.
  • Warunek uniemożliwiający pomyślną inicjalizację.

Aby wychwycić wyjątki rzucane przez metodę inicjalizacji, Swift 4 tworzy elastyczną inicjalizację zwaną „failable initializer”, aby powiadomić użytkownika, że ​​coś pozostaje niezauważone podczas inicjowania struktury, klasy lub elementów wyliczeniowych. Słowo kluczowe do przechwycenia dostępnego inicjatora to „init?”. Ponadto inicjatory dostępne i niedostępne nie mogą być definiowane z tymi samymi typami parametrów i nazwami.

struct studrecord {
   let stname: String
   init?(stname: String) {
      if stname.isEmpty {return nil }
      self.stname = stname
   }
}
let stmark = studrecord(stname: "Swing")

if let name = stmark {
   print("Student name is specified")
}
let blankname = studrecord(stname: "")

if blankname == nil {
   print("Student name is left blank")
}

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

Student name is specified
Student name is left blank

Dostępne inicjatory dla wyliczeń

Język Swift 4 zapewnia elastyczność umożliwiającą posiadanie dostępnych inicjatorów dla wyliczeń również w celu powiadamiania użytkownika, gdy członkowie wyliczenia nie mają inicjowania wartości.

enum functions {
   case a, b, c, d
   init?(funct: String) {
      switch funct {
      case "one":
         self = .a
      case "two":
         self = .b
      case "three":
         self = .c
      case "four":
         self = .d
      default:
         return nil
      }
   }
}
let result = functions(funct: "two")

if result != nil {
   print("With In Block Two")
}
let badresult = functions(funct: "five")

if badresult == nil {
   print("Block Does Not Exist")
}

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

With In Block Two
Block Does Not Exist

Dostępne inicjatory dla klas

Dostępny inicjator, gdy jest zadeklarowany z wyliczeniami i strukturami, ostrzega o niepowodzeniu inicjalizacji w dowolnej sytuacji w ramach jego implementacji. Jednak inicjator dostępny w klasach ostrzega o niepowodzeniu dopiero po ustawieniu przechowywanych właściwości na wartość początkową.

class studrecord {
   let studname: String!
   init?(studname: String) {
      self.studname = studname
      if studname.isEmpty { return nil }
   }
}

if let stname = studrecord(studname: "Failable Initializers") {
   print("Module is \(stname.studname)")
}

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

Module is Optional("Failable Initializers")

Zastępowanie dostępnego inicjatora

Podobnie jak w przypadku inicjalizacji, użytkownik ma również możliwość nadpisania dostępnego inicjatora nadklasy wewnątrz podklasy. Dostępna inicjalizacja superklasy może być również nadpisana w niedostępnym inicjalizatorze podklasy.

Inicjator podklasy nie może delegować uprawnień do inicjatora nadklasy podczas zastępowania dostępnego inicjatora nadklasy przez niedostępną inicjalizację podklasy.

Niedostępny inicjator nigdy nie może delegować do dostępnego inicjatora.

Program podany poniżej opisuje dostępne i niedostępne inicjatory.

class Planet {
   var name: String
   
   init(name: String) {
      self.name = name
   }
   convenience init() {
      self.init(name: "[No Planets]")
   }
}
let plName = Planet(name: "Mercury")
print("Planet name is: \(plName.name)")

let noplName = Planet()
print("No Planets like that: \(noplName.name)")
   
class planets: Planet {
   var count: Int
   
   init(name: String, count: Int) {
      self.count = count
      super.init(name: name)
   }
   override convenience init(name: String) {
      self.init(name: name, count: 1)
   }
}

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

Planet name is: Mercury
No Planets like that: [No Planets]

Init! Dostępny inicjalizator

Swift 4 zapewnia „init?” aby zdefiniować opcjonalny inicjator dostępny dla instancji. Aby zdefiniować niejawnie rozpakowaną opcjonalną instancję określonego typu „init!” jest specyficzne.

struct studrecord {
let stname: String

   init!(stname: String) {
      if stname.isEmpty {return nil }
      self.stname = stname
   }
}
let stmark = studrecord(stname: "Swing")

if let name = stmark {
   print("Student name is specified")
}

let blankname = studrecord(stname: "")

if blankname == nil {
   print("Student name is left blank")
}

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

Student name is specified
Student name is left blank

Wymagane inicjatory

Aby zadeklarować każdą podklasę słowa kluczowego „required” inicjalizacji, należy zdefiniować ją przed funkcją init ().

class classA {
   required init() {
      var a = 10
      print(a)
   }
}

class classB: classA {
   required init() {
      var b = 30
      print(b)
   }
}

let res = classA()
let print = classB()

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

10
30
10

Zanim instancja klasy będzie musiała zostać zwolniona, należy wywołać „deinitializer”, aby zwolnić miejsce w pamięci. Słowo kluczowe „deinit” służy do zwalniania przestrzeni pamięci zajmowanej przez zasoby systemowe. Deinicjalizacja jest dostępna tylko dla typów klas.

Deinicjalizacja w celu zwolnienia miejsca w pamięci

Swift 4 automatycznie zwalnia Twoje instancje, gdy nie są już potrzebne, aby zwolnić zasoby. Swift 4 obsługuje zarządzanie pamięcią instancji poprzez automatyczne zliczanie referencji (ARC), zgodnie z opisem w sekcji Automatyczne liczenie referencji. Zazwyczaj nie ma potrzeby ręcznego czyszczenia, gdy Twoje instancje są zwalniane. Jednak podczas pracy z własnymi zasobami może być konieczne samodzielne wykonanie dodatkowych czynności porządkowych. Na przykład, jeśli utworzysz klasę niestandardową w celu otwarcia pliku i zapisania w nim danych, może być konieczne zamknięcie pliku przed zwolnieniem instancji klasy.

var counter = 0; // for reference counting
class baseclass {
   init() {
      counter++;
   }
   deinit {
      counter--;
   }
}
var print: baseclass? = baseclass()

print(counter)
print = nil
print(counter)

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

1
0

Gdy instrukcja print = nil zostanie pominięta, wartości licznika pozostają takie same, ponieważ nie jest deinicjalizowany.

var counter = 0; // for reference counting

class baseclass {
   init() {
      counter++;
   }
   deinit {
      counter--;
   }
}
var print: baseclass? = baseclass()
print(counter)
print(counter)

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

1
1

Funkcje zarządzania pamięcią i jej użycie są obsługiwane w języku Swift 4 poprzez automatyczne zliczanie referencji (ARC). ARC służy do inicjowania i deinicjalizacji zasobów systemowych, zwalniając tym samym przestrzenie pamięci używane przez instancje klas, gdy instancje nie są już potrzebne. ARC śledzi informacje o relacjach między naszymi instancjami kodu, aby efektywnie zarządzać zasobami pamięci.

Funkcje ARC

  • ARC przydziela porcję pamięci do przechowywania informacji za każdym razem, gdy nowa instancja klasy jest tworzona przez init ().

  • Informacje o typie instancji i jej wartościach są przechowywane w pamięci.

  • Gdy instancja klasy nie jest już potrzebna, automatycznie zwalnia przestrzeń pamięci przez deinit () do dalszego przechowywania i pobierania instancji klasy.

  • ARC śledzi aktualnie odwołujące się właściwości instancji klas, stałe i zmienne, dzięki czemu funkcja deinit () jest stosowana tylko do tych nieużywanych instancji.

  • ARC utrzymuje „silne odniesienie” do tych właściwości instancji klasy, stałych i zmiennych, aby ograniczyć cofanie alokacji, gdy instancja klasy jest aktualnie używana.

Program ARC

class StudDetails {
   var stname: String!
   var mark: Int!
   
   init(stname: String, mark: Int) {
      self.stname = stname
      self.mark = mark
   }
   deinit {
      print("Deinitialized \(self.stname)")
      print("Deinitialized \(self.mark)")
   }
}

let stname = "Swift 4"
let mark = 98

print(stname)
print(mark)

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

Swift 4
98

ARC Strong Reference Cycles Class Instances

class studmarks {
   let name: String
   var stud: student?
   
   init (name: String) {
      print("Initializing: \(name)")
      self.name = name
   }
   deinit {
      print("Deallocating: \(self.name)")
   }
}

class student {
   let name: String
   var strname: studmarks?
   
   init (name: String) {
      print("Initializing: \(name)")
      self.name = name
   }
   deinit {
      print("Deallocating: \(self.name)")
   }
}

var shiba: studmarks?
var mari: student?

shiba = studmarks(name: "Swift 4")
mari = student(name: "ARC")

shiba!.stud = mari
mari!.strname = shiba

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

Initializing: Swift 4
Initializing: ARC

Słabe i nieznane referencje ARC

Właściwości typu klasy mają dwa sposoby rozwiązywania silnych cykli odwołań -

  • Słabe odniesienia
  • Nieznane referencje

Te odwołania są używane, aby umożliwić jednej instancji odwoływanie się do innych instancji w cyklu referencyjnym. Wtedy instancje mogą odnosić się do każdego wystąpienia, zamiast dbać o silny cykl odniesienia. Gdy użytkownik wie, że jakaś instancja może zwrócić wartości „nil”, możemy wskazać na to, używając słabego odwołania. Gdy instancja zwróci coś, a nie zero, zadeklaruj to z odwołaniem, którego nie jesteś właścicielem.

Słaby program referencyjny

class module {
   let name: String
   init(name: String) { self.name = name }
   var sub: submodule?
   deinit { print("\(name) Is The Main Module") }
}

class submodule {
   let number: Int
   init(number: Int) { self.number = number }
   weak var topic: module?

   deinit { print("Sub Module with its topic number is \(number)") }
}

var toc: module?
var list: submodule?
toc = module(name: "ARC")
list = submodule(number: 4)
toc!.sub = list
list!.topic = toc

toc = nil
list = nil

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

ARC Is The Main Module
Sub Module with its topic number is 4

Nieznany program referencyjny

class student {
   let name: String
   var section: marks?
   init(name: String) {
      self.name = name
   }
   deinit { print("\(name)") }
}

class marks {
   let marks: Int
   unowned let stname: student
   
   init(marks: Int, stname: student) {
      self.marks = marks
      self.stname = stname
   }
   deinit { print("Marks Obtained by the student is \(marks)") }
}

var module: student?
module = student(name: "ARC")
module!.section = marks(marks: 98, stname: module!)
module = nil

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

ARC
Marks Obtained by the student is 98

Silne cykle referencyjne dla zamknięć

Kiedy przypiszemy zamknięcie do właściwości instancji klasy i do treści zamknięcia w celu przechwycenia określonej instancji, może wystąpić silny cykl odniesienia. Silne odniesienie do zamknięcia jest definiowane przez „self.someProperty” lub „self.someMethod ()”. Silne cykle referencyjne są używane jako typy referencyjne dla zamknięć.

class HTMLElement {
   let samplename: String
   let text: String?
   
   lazy var asHTML: () -> String = {
      if let text = self.text {
         return "<\(self.samplename)>\(text)</\(self.samplename)>"
      } else {
         return "<\(self.samplename) />"
      }
   }
   init(samplename: String, text: String? = nil) {
      self.samplename = samplename
      self.text = text
   }
   deinit {
      print("\(samplename) is being deinitialized")
   }
}

var paragraph: HTMLElement? = HTMLElement(samplename: "p", text: "Welcome to Closure SRC")
print(paragraph!.asHTML())

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

<p>Welcome to Closure SRC</p>

Słabe i nieznane referencje

Gdy zamknięcie i wystąpienie odnoszą się do siebie nawzajem, użytkownik może zdefiniować wychwycenie w zamknięciu jako odniesienie nieposiadane. Wtedy nie pozwoliłoby użytkownikowi na jednoczesne zwolnienie instancji. Kiedy instancja kiedyś zwróci wartość „zero”, zdefiniuj zamknięcie słabą instancją.

class HTMLElement {
   let module: String
   let text: String?
   
   lazy var asHTML: () -> String = {
      [unowned self] in
      if let text = self.text {
         return "<\(self.module)>\(text)</\(self.module)>"
      } else {
         return "<\(self.module) />"
      }
   }
   init(module: String, text: String? = nil) {
      self.module = module
      self.text = text
   }
   deinit {
      print("\(module) the deinit()")
   }
}

var paragraph: HTMLElement? = HTMLElement(module: "Inside", text: "ARC Weak References")
print(paragraph!.asHTML())
paragraph = nil

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

<Inside>ARC Weak References</Inside>
Inside the deinit()

Proces odpytywania, wywoływania właściwości, indeksów i metod na opcji, która może mieć wartość „zero”, jest definiowana jako opcjonalne tworzenie łańcuchów. Opcjonalne tworzenie łańcuchów zwraca dwie wartości -

  • jeśli opcja zawiera „wartość”, wywołanie powiązanej z nią właściwości, metod i indeksów dolnych zwraca wartości

  • jeśli opcjonalne zawiera wartość „nil”, wszystkie związane z nim właściwości, metody i indeksy dolne zwracają nil

Ponieważ wiele zapytań do metod, właściwości i indeksów jest zgrupowanych razem, awaria jednego łańcucha wpłynie na cały łańcuch i spowoduje uzyskanie wartości „zero”.

Opcjonalne tworzenie łańcuchów jako alternatywa dla wymuszonego rozpakowywania

Opcjonalne tworzenie łańcucha jest określone po opcjonalnej wartości ze znakiem „?” do wywołania właściwości, metody lub indeksu dolnego, gdy opcjonalna wartość zwraca pewne wartości.

Opcjonalne łączenie „?” Dostęp do metod, właściwości i indeksów Opcjonalne tworzenie łańcuchów „!” wymusić rozpakowywanie
? jest umieszczany po opcjonalnej wartości wywołania właściwości, metody lub indeksu dolnego ! jest umieszczany po opcjonalnej wartości w celu wywołania właściwości, metody lub indeksu dolnego w celu wymuszenia rozpakowania wartości
Zawodzi z wdziękiem, gdy opcja jest „zero” Wymuszone rozpakowywanie wyzwala błąd czasu wykonywania, gdy opcja ma wartość „zero”

Program do opcjonalnego łączenia w łańcuch z '!'

class ElectionPoll {
   var candidate: Pollbooth?
}

lass Pollbooth {
   var name = "MP"
}

let cand = ElectionPoll()
let candname = cand.candidate!.name

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

fatal error: unexpectedly found nil while unwrapping an Optional value
0 Swift 4 0x0000000103410b68
llvm::sys::PrintStackTrace(__sFILE*) + 40
1 Swift 4 0x0000000103411054 SignalHandler(int) + 452
2 libsystem_platform.dylib 0x00007fff9176af1a _sigtramp + 26
3 libsystem_platform.dylib 0x000000000000000b _sigtramp + 1854492939
4 libsystem_platform.dylib 0x00000001074a0214 _sigtramp + 1976783636
5 Swift 4 0x0000000102a85c39
llvm::JIT::runFunction(llvm::Function*, std::__1::vector > const&) + 329
6 Swift 4 0x0000000102d320b3
llvm::ExecutionEngine::runFunctionAsMain(llvm::Function*,
std::__1::vector<std::__1::basic_string, std::__1::allocator >,
std::__1::allocator<std::__1::basic_string, std::__1::allocator > > > const&,
char const* const*) + 1523
7 Swift 4 0x000000010296e6ba Swift 4::RunImmediately(Swift
4::CompilerInstance&, std::__1::vector<std::__1::basic_string,
std::__1::allocator >, std::__1::allocator<std::__1::basic_string,
std::__1::allocator > > > const&, Swift 4::IRGenOptions&, Swift 4::SILOptions
const&) + 1066
8 Swift 4 0x000000010275764b frontend_main(llvm::ArrayRef,
char const*, void*) + 5275
9 Swift 4 0x0000000102754a6d main + 1677
10 libdyld.dylib 0x00007fff8bb9e5c9 start + 1
11 libdyld.dylib 0x000000000000000c start + 1950751300
Stack dump:
0. Program arguments:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/
usr/bin/Swift 4 -frontend -interpret - -target x86_64-apple-darwin14.0.0 -
target-cpu core2 -sdk
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/
SDKs/MacOSX10.10.sdk -module-name main
/bin/sh: line 47: 15672 Done cat <<'SWIFT 4'
import Foundation
</std::__1::basic_string</std::__1::basic_string</std::__1::basic_string</std::
__1::basic_string

Powyższy program deklaruje „sondę wyborczą” jako nazwę klasy i zawiera „kandydata” jako funkcję członkostwa. Podklasa jest zadeklarowana jako „stanowisko ankietowe” i „nazwa” jako jej funkcja członkostwa, która jest inicjowana jako „poseł”. Wywołanie superklasy jest inicjowane przez utworzenie instancji „cand” z opcjonalnym „!”. Ponieważ wartości nie są zadeklarowane w swojej klasie bazowej, wartość „nil” jest przechowywana, co powoduje zwrócenie błędu krytycznego przez procedurę wymuszania rozpakowywania.

Program opcjonalnego łączenia łańcuchowego z „?”

class ElectionPoll {
   var candidate: Pollbooth?
}

class Pollbooth {
   var name = "MP"
}
let cand = ElectionPoll()

if let candname = cand.candidate?.name {
   print("Candidate name is \(candname)")
} else {
   print("Candidate name cannot be retreived")
}

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

Candidate name cannot be retreived

Powyższy program deklaruje „sondę wyborczą” jako nazwę klasy i zawiera „kandydata” jako funkcję członkostwa. Podklasa jest zadeklarowana jako „stanowisko ankietowe” i „nazwa” jako jej funkcja członkostwa, która jest inicjowana jako „poseł”. Wywołanie superklasy jest inicjowane przez utworzenie instancji „cand” z opcjonalnym „?”. Ponieważ wartości nie są zadeklarowane w swojej klasie bazowej, wartość „nil” jest przechowywana i drukowana w konsoli przez blok obsługi else.

Definiowanie klas modeli dla opcjonalnych właściwości łączenia i uzyskiwania dostępu

Język Swift 4 zapewnia również koncepcję opcjonalnego łączenia łańcuchowego, aby zadeklarować więcej niż jedną podklasę jako klasy modelowe. Koncepcja ta będzie bardzo przydatna do definiowania złożonych modeli i uzyskiwania dostępu do właściwości, metod i pod-właściwości indeksów dolnych.

class rectangle {
   var print: circle?
}

class circle {
   var area = [radius]()
   var cprint: Int {
      return area.count
   }
   subscript(i: Int) -> radius {
      get {
         return area[i]
      }
      set {
         area[i] = newValue
      }
   }
   func circleprint() {
      print("The number of rooms is \(cprint)")
   }
   var rectarea: circumference?
}

class radius {
   let radiusname: String
   init(radiusname: String) { self.radiusname = radiusname }
}

class circumference {
   var circumName: String?
   var circumNumber: String?
   var street: String?

   func buildingIdentifier() -> String? {
      if circumName != nil {
         return circumName
      } else if circumNumber != nil {
         return circumNumber
      } else {
         return nil
      }
   }
}

let rectname = rectangle()
if let rectarea = rectname.print?.cprint {
   print("Area of rectangle is \(rectarea)")
} else {
   print("Rectangle Area is not specified")
}

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

Rectangle Area is not specified

Wywoływanie metod poprzez opcjonalne łączenie łańcuchowe

class rectangle {
   var print: circle?
}

class circle {
   var area = [radius]()
   var cprint: Int {
      return area.count
   }
   subscript(i: Int) -> radius {
      get {
         return area[i]
      }
      set {
         area[i] = newValue
      }
   }

   func circleprint() {
      print("Area of Circle is: \(cprint)")
   }
   var rectarea: circumference?
}

class radius {
   let radiusname: String
   init(radiusname: String) { self.radiusname = radiusname }
}

class circumference {
   var circumName: String?
   var circumNumber: String?
   var circumarea: String?
   
   func buildingIdentifier() -> String? {
      if circumName != nil {
         return circumName
      } else if circumNumber != nil {
         return circumNumber
      } else {
         return nil
      }
   }
}

let circname = rectangle()

if circname.print?.circleprint() != nil {
   print("Area of circle is specified)")
} else {
   print("Area of circle is not specified")
}

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

Area of circle is not specified

Funkcja circleprint () zadeklarowana w podklasie circle () jest wywoływana przez utworzenie instancji o nazwie „Circname”. Funkcja zwróci wartość, jeśli zawiera jakąś wartość, w przeciwnym razie zwróci jakiś komunikat drukowania zdefiniowany przez użytkownika, sprawdzając instrukcję „if circname.print? .Circleprint ()! = Nil”.

Dostęp do subskrypcji poprzez opcjonalne tworzenie łańcuchów

Opcjonalne tworzenie łańcucha służy do ustawiania i pobierania wartości indeksu dolnego w celu sprawdzenia, czy wywołanie tego indeksu zwraca wartość. '?' jest umieszczany przed nawiasami klamrowymi, aby uzyskać dostęp do opcjonalnej wartości w danym indeksie dolnym.

Program 1

class rectangle {
   var print: circle?
}

class circle {
   var area = [radius]()
   var cprint: Int {
      return area.count
   }
   subscript(i: Int) -> radius {
      get {
         return area[i]
      }
      set {
         area[i] = newValue
      }
   }
   func circleprint() {
      print("The number of rooms is \(cprint)")
   }
   var rectarea: circumference?
}

class radius {
   let radiusname: String
   init(radiusname: String) { self.radiusname =  radiusname }
}

class circumference {
   var circumName: String?
   var circumNumber: String?
   var circumarea: String?
   
   func buildingIdentifier() -> String? {
      if circumName != nil {
         return circumName
      } else if circumNumber != nil {
         return circumNumber
      } else {
         return nil
      }
   }
}

let circname = rectangle()

if let radiusName = circname.print?[0].radiusname {
   print("The first room name is \(radiusName).")
} else {
   print("Radius is not specified.")
}

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

Radius is not specified.

W powyższym programie wartości instancji dla funkcji członkostwa „radiusName” nie są określone. Dlatego wywołanie funkcji zwróci tylko inną część, podczas gdy aby zwrócić wartości, musimy zdefiniować wartości dla konkretnej funkcji przynależności.

Program 2

class rectangle {
   var print: circle?
}

class circle {
   var area = [radius]()
   var cprint: Int {
      return area.count
   }
   subscript(i: Int) -> radius {
      get {
         return area[i]
      }
      set {
         area[i] = newValue
      }
   }
   func circleprint() {
      print("The number of rooms is \(cprint)")
   }
   var rectarea: circumference?
}

class radius {
   let radiusname: String
   init(radiusname: String) { self.radiusname = radiusname }
}

class circumference {
   var circumName: String?
   var circumNumber: String?
   var circumarea: String?
   
   func buildingIdentifier() -> String? {
      if circumName != nil {
         return circumName
      } else if circumNumber != nil {
         return circumNumber
      } else {
         return nil
      }
   }
}

let circname = rectangle()
circname.print?[0] = radius(radiusname: "Diameter")
let printing = circle()

printing.area.append(radius(radiusname: "Units"))
printing.area.append(radius(radiusname: "Meter"))
circname.print = printing

if let radiusName = circname.print?[0].radiusname {
   print("Radius is measured in \(radiusName).")
} else {
   print("Radius is not specified.")
}

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

Radius is measured in Units.

W powyższym programie określono wartości instancji funkcji członkostwa „radiusName”. Dlatego wywołanie funkcji w programie będzie teraz zwracać wartości.

Dostęp do indeksów dolnych typu opcjonalnego

class rectangle {
   var print: circle?
}

class circle {
   var area = [radius]()
   var cprint: Int {
      return area.count
   }

   subscript(i: Int) -> radius {
      get {
         return area[i]
      }
      set {
         area[i] = newValue
      }
   }
   func circleprint() {
      print("The number of rooms is \(cprint)")
   }
   var rectarea: circumference?
}

class radius {
   let radiusname: String
   init(radiusname: String) { self.radiusname = radiusname }
}

class circumference {
   var circumName: String?
   var circumNumber: String?
   var circumarea: String?
   
   func buildingIdentifier() -> String? {
      if circumName != nil {
         return circumName
      } else if circumNumber != nil {
         return circumNumber
      } else {
         return nil
      }
   }
}

let circname = rectangle()
circname.print?[0] = radius(radiusname: "Diameter")

let printing = circle()
printing.area.append(radius(radiusname: "Units"))
printing.area.append(radius(radiusname: "Meter"))
circname.print = printing

var area = ["Radius": [35, 45, 78, 101], "Circle": [90, 45, 56]]
area["Radius"]?[1] = 78
area["Circle"]?[1]--

print(area["Radius"]?[0])
print(area["Radius"]?[1])
print(area["Radius"]?[2])
print(area["Radius"]?[3])

print(area["Circle"]?[0])
print(area["Circle"]?[1])
print(area["Circle"]?[2])

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

Optional(35)
Optional(78)
Optional(78)
Optional(101)
Optional(90)
Optional(44)
Optional(56)

Dostęp do opcjonalnych wartości indeksów dolnych można uzyskać, odwołując się do ich wartości w indeksie dolnym. Dostęp do niego można uzyskać jako indeks dolny [0], indeks dolny [1] itd. Domyślne wartości indeksu dolnego dla „promienia” są najpierw przypisywane jako [35, 45, 78, 101] i dla „Circle” [90, 45, 56]] . Następnie wartości indeksu dolnego są zmieniane jako Promień [0] na 78 i Okrąg [1] na 45.

Łączenie wielu poziomów łańcuchów

Wiele podklas może być również połączonych z ich metodami, właściwościami i indeksami superklas przez opcjonalne tworzenie łańcuchów.

Można połączyć wiele łańcuchów opcjonalnych -

Jeśli pobieranie typu nie jest opcjonalne, opcjonalne tworzenie łańcucha zwróci opcjonalną wartość. Na przykład, jeśli String przez opcjonalne łańcuchowanie zwróci String? Wartość

class rectangle {
   var print: circle?
}

class circle {
   var area = [radius]()
   var cprint: Int {
      return area.count
   }
   subscript(i: Int) -> radius {
      get {
         return area[i]
      }
      set {
         area[i] = newValue
      }
   }
   func circleprint() {
      print("The number of rooms is \(cprint)")
   }
   var rectarea: circumference?
}

class radius {
   let radiusname: String
   init(radiusname: String) { self.radiusname = radiusname }
}

class circumference {
   var circumName: String?
   var circumNumber: String?
   var circumarea: String?

   func buildingIdentifier() -> String? {
      if circumName != nil {
         return circumName
      } else if circumNumber != nil {
         return circumNumber
      } else {
         return nil
      }
   }
}

let circname = rectangle()

if let radiusName = circname.print?[0].radiusname {
   print("The first room name is \(radiusName).")
} else {
   print("Radius is not specified.")
}

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

Radius is not specified.

W powyższym programie nie określono wartości instancji funkcji członkostwa „radiusName”. W związku z tym wywołanie funkcji zwróci tylko inną część, podczas gdy aby zwrócić wartości, musimy zdefiniować wartości dla konkretnej funkcji przynależności.

Jeśli typ pobierania jest już opcjonalny, opcjonalne tworzenie łańcucha również zwróci wartość opcjonalną. Na przykład, jeśli String? Czy jest dostępny przez opcjonalne łańcuchowanie, zwróci String? Wartość..

class rectangle {
   var print: circle?
}

class circle {
   var area = [radius]()
   var cprint: Int {
      return area.count
   }
   subscript(i: Int) -> radius {
      get {
         return area[i]
      }
      set {
         area[i] = newValue
      }
   }
   func circleprint() {
      print("The number of rooms is \(cprint)")
   }
   var rectarea: circumference?
}

class radius {
   let radiusname: String
   init(radiusname: String) { self.radiusname = radiusname }
}

class circumference {
   var circumName: String?
   var circumNumber: String?
   var circumarea: String?
   
   func buildingIdentifier() -> String? {
      if circumName != nil {
         return circumName
      } else if circumNumber != nil {
         return circumNumber
      } else {
         return nil
      }
   }
}

let circname = rectangle()
circname.print?[0] = radius(radiusname: "Diameter")
let printing = circle()

printing.area.append(radius(radiusname: "Units"))
printing.area.append(radius(radiusname: "Meter"))
circname.print = printing

if let radiusName = circname.print?[0].radiusname {
   print("Radius is measured in \(radiusName).")
} else {
   print("Radius is not specified.")
}

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

Radius is measured in Units.

W powyższym programie określono wartości instancji funkcji członkostwa „radiusName”. W związku z tym wywołanie programu do funkcji będzie teraz zwracać wartości.

Tworzenie łańcuchów metod z opcjonalnymi wartościami zwracanymi

Opcjonalne tworzenie łańcuchów jest również używane do uzyskiwania dostępu do metod zdefiniowanych podklas.

class rectangle {
   var print: circle?
}

class circle {
   var area = [radius]()
   var cprint: Int {
      return area.count
   }
   subscript(i: Int) -> radius {
      get {
         return area[i]
      }
      set {
         area[i] = newValue
      }
   }
   func circleprint() {
      print("Area of Circle is: \(cprint)")
   }
   var rectarea: circumference?
}

class radius {
   let radiusname: String
   init(radiusname: String) { self.radiusname = radiusname }
}

class circumference {
   var circumName: String?
   var circumNumber: String?
   var circumarea: String?
   
   func buildingIdentifier() -> String? {
      if circumName != nil {
         return circumName
      } else if circumNumber != nil {
         return circumNumber
      } else {
         return nil
      }
   }
}

let circname = rectangle()

if circname.print?.circleprint() != nil {
   print("Area of circle is specified)")
} else {
   print("Area of circle is not specified")
}

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

Area of circle is not specified

Aby sprawdzić typ instancji, w języku Swift 4 pojawia się „Casting Type”. Służy do sprawdzania, czy typ instancji należy do określonej nadklasy lub podklasy, czy też jest zdefiniowany we własnej hierarchii.

Rzutowanie typu Swift 4 zapewnia dwa operatory „is” do sprawdzania typu wartości i „as” oraz do rzutowania wartości typu na inny typ. Rzutowanie typów sprawdza również, czy typ wystąpienia jest zgodny z określonym standardem zgodności protokołu.

Definiowanie hierarchii klas

Rzutowanie typu służy do sprawdzania typu wystąpień w celu ustalenia, czy należy on do określonego typu klasy. Sprawdza również hierarchię klas i jej podklas, aby sprawdzić i rzutować te wystąpienia, aby utworzyć tę samą hierarchię.

class Subjects {
   var physics: String
   init(physics: String) {
      self.physics = physics
   }
}

class Chemistry: Subjects {
   var equations: String
   init(physics: String, equations: String) {
      self.equations = equations
      super.init(physics: physics)
   }
}

class Maths: Subjects {
   var formulae: String
   init(physics: String, formulae: String) {
      self.formulae = formulae
      super.init(physics: physics)
   }
}

let sa = [ Chemistry(physics: "solid physics", equations: "Hertz"),
   Maths(physics: "Fluid Dynamics", formulae: "Giga Hertz")]

let samplechem = Chemistry(physics: "solid physics", equations: "Hertz")
print("Instance physics is: \(samplechem.physics)")
print("Instance equation is: \(samplechem.equations)")

let samplemaths = Maths(physics: "Fluid Dynamics", formulae: "Giga Hertz")
print("Instance physics is: \(samplemaths.physics)")
print("Instance formulae is: \(samplemaths.formulae)")

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

Instance physics is: solid physics
Instance equation is: Hertz
Instance physics is: Fluid Dynamics
Instance formulae is: Giga Hertz

Sprawdzanie typów

Do sprawdzania typów służy operator „is”. Operator sprawdzania typu „is” sprawdza, czy instancja należy do określonego typu podklasy i zwraca wartość „true”, jeśli należy do tej instancji, w przeciwnym razie zwróci wartość „false”.

class Subjects {
   var physics: String
   init(physics: String) {
      self.physics = physics
   }
}

class Chemistry: Subjects {
   var equations: String
   init(physics: String, equations: String) {
      self.equations = equations
      super.init(physics: physics)
   }
}

class Maths: Subjects {
   var formulae: String
   init(physics: String, formulae: String) {
      self.formulae = formulae
      super.init(physics: physics)
   }
}

let sa = [
   Chemistry(physics: "solid physics", equations: "Hertz"),
   Maths(physics: "Fluid Dynamics", formulae: "Giga Hertz"),
   Chemistry(physics: "Thermo physics", equations: "Decibels"),
   Maths(physics: "Astro Physics", formulae: "MegaHertz"),
   Maths(physics: "Differential Equations", formulae: "Cosine Series")]

let samplechem = Chemistry(physics: "solid physics", equations: "Hertz")
print("Instance physics is: \(samplechem.physics)")
print("Instance equation is: \(samplechem.equations)")

let samplemaths = Maths(physics: "Fluid Dynamics", formulae: "Giga Hertz")
print("Instance physics is: \(samplemaths.physics)")
print("Instance formulae is: \(samplemaths.formulae)")

var chemCount = 0
var mathsCount = 0
for item in sa {
   if item is Chemistry {
      ++chemCount
   } else if item is Maths {
      ++mathsCount
   }
}

print("Subjects in chemistry contains \(chemCount) topics and maths contains \(mathsCount) topics")

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

Instance physics is: solid physics
Instance equation is: Hertz
Instance physics is: Fluid Dynamics
Instance formulae is: Giga Hertz
Subjects in chemistry contains 2 topics and maths contains 3 topics

Downcasting

Obniżenie typu podklasy można przeprowadzić za pomocą dwóch operatorów (as? I as!). „As?” zwraca opcjonalną wartość, gdy wartość zwraca nil. Służy do sprawdzania pomyślnego obniżenia.

'tak jak!' zwraca wymuszone rozpakowanie, jak omówiono w opcjonalnym łańcuchu, gdy downcasting zwraca wartość nil. Służy do wyzwalania błędu wykonania w przypadku awarii downcast

class Subjects {
   var physics: String
   init(physics: String) {
      self.physics = physics
   }
}

class Chemistry: Subjects {
   var equations: String
   init(physics: String, equations: String) {
      self.equations = equations
      super.init(physics: physics)
   }
}

class Maths: Subjects {
   var formulae: String
   init(physics: String, formulae: String) {
      self.formulae = formulae
      super.init(physics: physics)
   }
}

let sa = [
   Chemistry(physics: "solid physics", equations: "Hertz"),
   Maths(physics: "Fluid Dynamics", formulae: "Giga Hertz"),
   Chemistry(physics: "Thermo physics", equations: "Decibels"),
   Maths(physics: "Astro Physics", formulae: "MegaHertz"),
   Maths(physics: "Differential Equations", formulae: "Cosine Series")]

let samplechem = Chemistry(physics: "solid physics", equations: "Hertz")
print("Instance physics is: \(samplechem.physics)")
print("Instance equation is: \(samplechem.equations)")

let samplemaths = Maths(physics: "Fluid Dynamics", formulae: "Giga Hertz")
print("Instance physics is: \(samplemaths.physics)")
print("Instance formulae is: \(samplemaths.formulae)")

var chemCount = 0
var mathsCount = 0

for item in sa {
   if let print = item as? Chemistry {
      print("Chemistry topics are: '\(print.physics)', \(print.equations)")
   } else if let example = item as? Maths {
      print("Maths topics are: '\(example.physics)', \(example.formulae)")
   }
}

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

Instance physics is: solid physics
Instance equation is: Hertz
Instance physics is: Fluid Dynamics
Instance formulae is: Giga Hertz
Chemistry topics are: 'solid physics', Hertz
Maths topics are: 'Fluid Dynamics', Giga Hertz
Chemistry topics are: 'Thermo physics', Decibels
Maths topics are: 'Astro Physics', MegaHertz
Maths topics are: 'Differential Equations', Cosine Series

Typowanie: dowolny i dowolny przedmiot

Słowo kluczowe „Any” służy do reprezentowania instancji należącej do dowolnego typu, w tym typów funkcji.

class Subjects {
   var physics: String
   init(physics: String) {
      self.physics = physics
   }
}

class Chemistry: Subjects {
   var equations: String
   init(physics: String, equations: String) {
      self.equations = equations
      super.init(physics: physics)
   }
}

class Maths: Subjects {
   var formulae: String
   init(physics: String, formulae: String) {
      self.formulae = formulae
      super.init(physics: physics)
   }
}

let sa = [
   Chemistry(physics: "solid physics", equations: "Hertz"),
   Maths(physics: "Fluid Dynamics", formulae: "Giga Hertz"),
   Chemistry(physics: "Thermo physics", equations: "Decibels"),
   Maths(physics: "Astro Physics", formulae: "MegaHertz"),
   Maths(physics: "Differential Equations", formulae: "Cosine Series")]

let samplechem = Chemistry(physics: "solid physics", equations: "Hertz")
print("Instance physics is: \(samplechem.physics)")
print("Instance equation is: \(samplechem.equations)")

let samplemaths = Maths(physics: "Fluid Dynamics", formulae: "Giga Hertz")
print("Instance physics is: \(samplemaths.physics)")
print("Instance formulae is: \(samplemaths.formulae)")

var chemCount = 0
var mathsCount = 0

for item in sa {
   if let print = item as? Chemistry {
      print("Chemistry topics are: '\(print.physics)', \(print.equations)")
   } else if let example = item as? Maths {
      print("Maths topics are: '\(example.physics)', \(example.formulae)")
   }
}

var exampleany = [Any]()

exampleany.append(12)
exampleany.append(3.14159)
exampleany.append("Example for Any")
exampleany.append(Chemistry(physics: "solid physics", equations: "Hertz"))

for print in exampleany {
   switch print {
      case let someInt as Int:
         print("Integer value is \(someInt)")
      case let someDouble as Double where someDouble > 0:
         print("Pi value is \(someDouble)")
      case let someString as String:
         print("\(someString)")
      case let phy as Chemistry:   
         print("Topics '\(phy.physics)', \(phy.equations)")
      default:
         print("None")
   }
}

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

Instance physics is: solid physics
Instance equation is: Hertz
Instance physics is: Fluid Dynamics
Instance formulae is: Giga Hertz
Chemistry topics are: 'solid physics', Hertz
Maths topics are: 'Fluid Dynamics', Giga Hertz
Chemistry topics are: 'Thermo physics', Decibels
Maths topics are: 'Astro Physics', MegaHertz
Maths topics are: 'Differential Equations', Cosine Series
Integer value is 12
Pi value is 3.14159
Example for Any
Topics 'solid physics', Hertz

AnyObject

Do reprezentowania instancji dowolnego typu klasy używane jest słowo kluczowe „AnyObject”.

class Subjects {
   var physics: String
   init(physics: String) {
      self.physics = physics
   }
}

class Chemistry: Subjects {
   var equations: String
   init(physics: String, equations: String) {
      self.equations = equations
      super.init(physics: physics)
   }
}

class Maths: Subjects {
   var formulae: String
   init(physics: String, formulae: String) {
      self.formulae = formulae
      super.init(physics: physics)
   }
}

let saprint: [AnyObject] = [Chemistry(physics: "solid physics", equations: "Hertz"),
   Maths(physics: "Fluid Dynamics", formulae: "Giga Hertz"),
   Chemistry(physics: "Thermo physics", equations: "Decibels"),
   Maths(physics: "Astro Physics", formulae: "MegaHertz"),
   Maths(physics: "Differential Equations", formulae: "Cosine Series")]

let samplechem = Chemistry(physics: "solid physics", equations: "Hertz")
print("Instance physics is: \(samplechem.physics)")
print("Instance equation is: \(samplechem.equations)")

let samplemaths = Maths(physics: "Fluid Dynamics", formulae: "Giga Hertz")
print("Instance physics is: \(samplemaths.physics)")
print("Instance formulae is: \(samplemaths.formulae)")

var chemCount = 0
var mathsCount = 0

for item in saprint {
   if let print = item as? Chemistry {
      print("Chemistry topics are: '\(print.physics)', \(print.equations)")
   } else if let example = item as? Maths {
      print("Maths topics are: '\(example.physics)', \(example.formulae)")
   }
}

var exampleany = [Any]()
exampleany.append(12)
exampleany.append(3.14159)
exampleany.append("Example for Any")
exampleany.append(Chemistry(physics: "solid physics", equations: "Hertz"))

for print in exampleany {
   switch print {
      case let someInt as Int:
         print("Integer value is \(someInt)")
      case let someDouble as Double where someDouble > 0:
         print("Pi value is \(someDouble)")
      case let someString as String:
         print("\(someString)")
      case let phy as Chemistry:
         print("Topics '\(phy.physics)', \(phy.equations)")
      default:
         print("None")
   }
}

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

Instance physics is: solid physics
Instance equation is: Hertz
Instance physics is: Fluid Dynamics
Instance formulae is: Giga Hertz
Chemistry topics are: 'solid physics', Hertz
Maths topics are: 'Fluid Dynamics', Giga Hertz
Chemistry topics are: 'Thermo physics', Decibels
Maths topics are: 'Astro Physics', MegaHertz
Maths topics are: 'Differential Equations', Cosine Series
Integer value is 12
Pi value is 3.14159
Example for Any
Topics 'solid physics', Hertz

Funkcjonalność istniejącej klasy, struktury lub typu wyliczenia można dodać za pomocą rozszerzeń. Funkcjonalność typu można dodać za pomocą rozszerzeń, ale zastąpienie funkcji nie jest możliwe w przypadku rozszerzeń.

Swift Extension Functionalities -

  • Dodawanie obliczonych właściwości i obliczonych właściwości typu
  • Definiowanie metod instancji i typów.
  • Udostępnianie nowych inicjatorów.
  • Definiowanie indeksów
  • Definiowanie i używanie nowych typów zagnieżdżonych
  • Dostosowanie istniejącego typu do protokołu

Rozszerzenia są deklarowane ze słowem kluczowym „rozszerzenie”

Składnia

extension SomeType {
   // new functionality can be added here
}

Istniejący typ można również dodać z rozszerzeniami, aby stał się standardem protokołu, a jego składnia jest podobna do klas lub struktur.

extension SomeType: SomeProtocol, AnotherProtocol {
   // protocol requirements is described here
}

Obliczone właściwości

Obliczone właściwości „instancji” i „typu” można również rozszerzyć za pomocą rozszerzeń.

extension Int {
   var add: Int {return self + 100 }
   var sub: Int { return self - 10 }
   var mul: Int { return self * 10 }
   var div: Int { return self / 5 }
}

let addition = 3.add
print("Addition is \(addition)")

let subtraction = 120.sub
print("Subtraction is \(subtraction)")

let multiplication = 39.mul
print("Multiplication is \(multiplication)")

let division = 55.div
print("Division is \(division)")

let mix = 30.add + 34.sub
print("Mixed Type is \(mix)")

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

Addition is 103
Subtraction is 110
Multiplication is 390
Division is 11
Mixed Type is 154

Inicjatory

Swift 4 zapewnia elastyczność dodawania nowych inicjatorów do istniejącego typu za pomocą rozszerzeń. Użytkownik może dodawać własne typy niestandardowe, aby rozszerzyć typy już zdefiniowane, a także dodatkowe opcje inicjalizacji. Rozszerzenia obsługują tylko init (). Funkcja deinit () nie jest obsługiwana przez rozszerzenia.

struct sum {
   var num1 = 100, num2 = 200
}

struct diff {
   var no1 = 200, no2 = 100
}

struct mult {
   var a = sum()
   var b = diff()
}

let calc = mult()
print ("Inside mult block \(calc.a.num1, calc.a.num2)")
print("Inside mult block \(calc.b.no1, calc.b.no2)")

let memcalc = mult(a: sum(num1: 300, num2: 500),b: diff(no1: 300, no2: 100))
print("Inside mult block \(memcalc.a.num1, memcalc.a.num2)")
print("Inside mult block \(memcalc.b.no1, memcalc.b.no2)")

extension mult {
   init(x: sum, y: diff) {
      let X = x.num1 + x.num2
      let Y = y.no1 + y.no2
   }
}

let a = sum(num1: 100, num2: 200)
print("Inside Sum Block:\( a.num1, a.num2)")

let b = diff(no1: 200, no2: 100)
print("Inside Diff Block: \(b.no1, b.no2)")

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

Inside mult block (100, 200)
Inside mult block (200, 100)
Inside mult block (300, 500)
Inside mult block (300, 100)
Inside Sum Block:(100, 200)
Inside Diff Block: (200, 100)

Metody

Nowe metody instancji i metody typów można dodać dalej do podklasy za pomocą rozszerzeń.

extension Int {
   func topics(summation: () -> ()) {
      for _ in 0..<self {
         summation()
      }
   }
}

4.topics(summation: {
   print("Inside Extensions Block")
})

3.topics(summation: {
   print("Inside Type Casting Block")
})

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

Inside Extensions Block
Inside Extensions Block
Inside Extensions Block
Inside Extensions Block
Inside Type Casting Block
Inside Type Casting Block
Inside Type Casting Block

Funkcja topics () przyjmuje argument typu '(sumowanie: () → ())', aby wskazać, że funkcja nie przyjmuje żadnych argumentów i nie zwróci żadnych wartości. Aby wywołać tę funkcję wiele razy, inicjowany jest blok for i wywoływana jest metoda z topic ().

Metody mutacji instancji

Metody instancji można również mutować, gdy są zadeklarowane jako rozszerzenia.

Struktury i metody wyliczania, które modyfikują self lub jego właściwości, muszą oznaczać metodę instancji jako mutującą, podobnie jak mutowanie metod z oryginalnej implementacji.

extension Double {
   mutating func square() {
      let pi = 3.1415
      self = pi * self * self
   }
}

var Trial1 = 3.3
Trial1.square()
print("Area of circle is: \(Trial1)")

var Trial2 = 5.8
Trial2.square()
print("Area of circle is: \(Trial2)")

var Trial3 = 120.3
Trial3.square()
print("Area of circle is: \(Trial3)")

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

Area of circle is: 34.210935
Area of circle is: 105.68006
Area of circle is: 45464.070735

Indeksy

Dodanie nowych indeksów do już zadeklarowanych instancji jest również możliwe dzięki rozszerzeniom.

extension Int {
   subscript(var multtable: Int) -> Int {
      var no1 = 1
      while multtable > 0 {
         no1 *= 10
         --multtable
      }
      return (self / no1) % 10
   }
}

print(12[0])
print(7869[1])
print(786543[2])

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

2
6
5

Zagnieżdżone typy

Zagnieżdżone typy dla instancji klas, struktur i wyliczeń można również rozszerzyć za pomocą rozszerzeń.

extension Int {
   enum calc {
      case add
      case sub
      case mult
      case div
      case anything
   }
   var print: calc {
      switch self {
         case 0:
            return .add
         case 1:
            return .sub
         case 2:
            return .mult
         case 3:
            return .div
         default:
            return .anything
      }
   }
}

func result(numb: [Int]) {
   for i in numb {
      switch i.print {
         case .add:
            print(" 10 ")
         case .sub:
            print(" 20 ")
         case .mult:
            print(" 30 ")
         case .div:
            print(" 40 ")
         default:
            print(" 50 ")
      }
   }
}
result(numb: [0, 1, 2, 3, 4, 7])

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

10
20
30
40
50
50

Protokoły zapewniają plan metod, właściwości i innych funkcji wymagań. Jest po prostu opisywany jako szkielet metod lub właściwości, a nie implementacja. Implementację metod i właściwości można ponadto przeprowadzić poprzez zdefiniowanie klas, funkcji i wyliczeń. Zgodność protokołu definiuje się jako metody lub właściwości spełniające wymagania protokołu.

Składnia

Protokoły mają również podobną składnię, jak w przypadku klas, struktur i wyliczeń -

protocol SomeProtocol {
   // protocol definition 
}

Protokoły są deklarowane po nazwie klasy, struktury lub typu wyliczenia. Możliwe są również deklaracje jednego i wielu protokołów. Jeśli zdefiniowano wiele protokołów, należy je oddzielić przecinkami.

struct SomeStructure: Protocol1, Protocol2 {
   // structure definition 
}

Gdy trzeba zdefiniować protokół dla superklasy, po nazwie protokołu należy umieścić przecinek po nazwie superklasy.

class SomeClass: SomeSuperclass, Protocol1, Protocol2 {
   // class definition 
}

Wymagania dotyczące właściwości i metod

Protokół służy do określania określonej właściwości typu klasy lub właściwości instancji. Po prostu określa sam typ lub właściwość instancji, zamiast określać, czy jest to właściwość przechowywana czy obliczana. Służy również do określenia, czy właściwość jest „gettable”, czy „setable”.

Wymagania dotyczące właściwości są deklarowane przez słowo kluczowe „var” jako zmienne właściwości. {get set} służy do deklarowania gettable i ustawialnych właściwości po ich deklaracji typu. Gettable jest wymienione we właściwości {get} po ich deklaracji typu.

protocol classa {
   var marks: Int { get set }
   var result: Bool { get }
   
   func attendance() -> String
   func markssecured() -> String
}

protocol classb: classa {
   var present: Bool { get set }
   var subject: String { get set }
   var stname: String { get set }
}

class classc: classb {
   var marks = 96
   let result = true
   var present = false
   var subject = "Swift 4 Protocols"
   var stname = "Protocols"

   func attendance() -> String {
      return "The \(stname) has secured 99% attendance"
   }
   func markssecured() -> String {
      return "\(stname) has scored \(marks)"
   }
}

let studdet = classc()
studdet.stname = "Swift 4"
studdet.marks = 98
studdet.markssecured()

print(studdet.marks)
print(studdet.result)
print(studdet.present)
print(studdet.subject)
print(studdet.stname)

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

98
true
false
Swift 4 Protocols
Swift 4

Wymagania dotyczące metody mutacji

protocol daysofaweek {
   mutating func print()
}

enum days: daysofaweek {
   case sun, mon, tue, wed, thurs, fri, sat 
   mutating func print() {
      switch self {
         case sun:
            self = sun
            print("Sunday")
         case mon:
            self = mon
            print("Monday")
         case tue:
            self = tue
            print("Tuesday")
         case wed:
            self = wed
            print("Wednesday")
         case mon:
            self = thurs
            print("Thursday")
         case tue:
            self = fri
            print("Friday")
         case sat:
            self = sat
            print("Saturday")
         default:
            print("NO Such Day")
      }
   }
}

var res = days.wed
res.print()

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

Wednesday

Wymagania inicjatora

Swing umożliwia użytkownikowi inicjowanie protokołów, aby były zgodne z typem, podobnie jak w przypadku normalnych inicjatorów.

Składnia

protocol SomeProtocol {
   init(someParameter: Int)
}

Na przykład

protocol tcpprotocol {
   init(aprot: Int)
}

Implementacje klas wymagań inicjatora protokołu

Wyznaczony lub wygodny inicjator umożliwia użytkownikowi zainicjowanie protokołu w celu dostosowania go do jego standardu przez zarezerwowane słowo kluczowe „wymagane”.

class SomeClass: SomeProtocol {
   required init(someParameter: Int) {
      // initializer implementation statements
   }
}

protocol tcpprotocol {
   init(aprot: Int)
}

class tcpClass: tcpprotocol {
   required init(aprot: Int) {
   }
}

Zgodność z protokołem jest zapewniana we wszystkich podklasach w przypadku jawnej lub dziedziczonej implementacji przez modyfikator „wymagany”.

Gdy podklasa przesłania swoje wymaganie inicjalizacji superklasy, jest określana przez słowo kluczowe modyfikujące „override”.

protocol tcpprotocol {
   init(no1: Int)
}

class mainClass {
   var no1: Int        // local storage
   init(no1: Int) {
      self.no1 = no1  // initialization
   }
}

class subClass: mainClass, tcpprotocol {
   var no2: Int
   init(no1: Int, no2 : Int) {
      self.no2 = no2
      super.init(no1:no1)
   }
   // Requires only one parameter for convenient method
   required override convenience init(no1: Int) {
      self.init(no1:no1, no2:0)
   }
}

let res = mainClass(no1: 20)
let print = subClass(no1: 30, no2: 50)

print("res is: \(res.no1)")
print("res is: \(print.no1)")
print("res is: \(print.no2)")

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

res is: 20
res is: 30
res is: 50

Protokoły jako typy

Zamiast implementować funkcjonalności w protokole, są używane jako typy dla funkcji, klas, metod itp.

Dostęp do protokołów można uzyskać jako typy w -

  • Funkcja, metoda lub inicjalizacja jako parametr lub typ zwracany

  • Stała, zmienna lub właściwość

  • Tablice, słowniki lub inne pojemniki jako elementy

protocol Generator {
   typealias members
   func next() -> members?
}

var items = [10,20,30].generate()
while let x = items.next() {
   print(x)
}

for lists in map([1,2,3], {i in i*5}) {
   print(lists)
}

print([100,200,300])
print(map([1,2,3], {i in i*10}))

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

10
20
30
5
10
15
[100, 200, 300]
[10, 20, 30]

Dodawanie zgodności protokołu z rozszerzeniem

Istniejący typ może zostać zaadoptowany i dostosowany do nowego protokołu poprzez użycie rozszerzeń. Nowe właściwości, metody i indeksy mogą być dodawane do istniejących typów za pomocą rozszerzeń.

protocol AgeClasificationProtocol {
   var age: Int { get }
   func agetype() -> String
}
class Person {
   let firstname: String
   let lastname: String
   var age: Int
   
   init(firstname: String, lastname: String) {
      self.firstname = firstname
      self.lastname = lastname
      self.age = 10
   }
}

extension Person : AgeClasificationProtocol {
   func fullname() -> String {
      var c: String
      c = firstname + " " + lastname
      return c
   }
   func agetype() -> String {
      switch age {
         case 0...2:
            return "Baby"
         case 2...12:
            return "Child"
         case 13...19:
            return "Teenager"
         case let x where x > 65:
            return "Elderly"
         default:
            return "Normal"
      }
   }
}

Dziedziczenie protokołów

Swift 4 umożliwia protokołom dziedziczenie właściwości ze zdefiniowanych właściwości. Jest podobny do dziedziczenia klas, ale z możliwością wyszczególnienia wielu dziedziczonych protokołów oddzielonych przecinkami.

protocol classa {
   var no1: Int { get set }
   func calc(sum: Int)
}
protocol result {
   func print(target: classa)
}
class student2: result {
   func print(target: classa) {
      target.calc(sum: 1)
   }
}
class classb: result {
   func print(target: classa) {
      target.calc(sum: 5)
   }
}

class student: classa {
   var no1: Int = 10
   
   func calc(sum: Int) {
      no1 -= sum
      print("Student attempted \(sum) times to pass")
         
      if no1 <= 0 {
         print("Student is absent for exam")
      }
   }
}

class Player {
   var stmark: result!

   init(stmark: result) {
      self.stmark = stmark
   }
   func print(target: classa) {
      stmark.print(target: target)
   }
}

var marks = Player(stmark: student2())
var marksec = student()

marks.print(target: marksec)
marks.print(target: marksec)
marks.print(target: marksec)
marks.stmark = classb()
marks.print(target: marksec)
marks.print(target: marksec)
marks.print(target: marksec)

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

Student attempted 1 times to pass
Student attempted 1 times to pass
Student attempted 1 times to pass
Student attempted 5 times to pass
Student attempted 5 times to pass
Student is absent for exam
Student attempted 5 times to pass
Student is absent for exam

Protokoły tylko klasy

Gdy protokoły są zdefiniowane, a użytkownik chce zdefiniować protokół z klasami, należy go dodać, definiując najpierw klasę, a następnie listę dziedziczenia protokołów.

protocol tcpprotocol {
   init(no1: Int)
}
class mainClass {
   var no1: Int        // local storage
   init(no1: Int) {
      self.no1 = no1  // initialization
   }
}
class subClass: mainClass, tcpprotocol {
   var no2: Int
   init(no1: Int, no2 : Int) {
      self.no2 = no2
      super.init(no1:no1)
   }
   
   // Requires only one parameter for convenient method
   required override convenience init(no1: Int) {
      self.init(no1:no1, no2:0)
   }
}

let res = mainClass(no1: 20)
let print = subClass(no1: 30, no2: 50)

print("res is: \(res.no1)")
print("res is: \(print.no1)")
print("res is: \(print.no2)")

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

res is: 20
res is: 30
res is: 50

Skład protokołu

Swift 4 umożliwia jednoczesne wywoływanie wielu protokołów za pomocą kompozycji protokołów.

Składnia

protocol<SomeProtocol, AnotherProtocol>

Przykład

protocol stname {
   var name: String { get }
}
protocol stage {
   var age: Int { get }
}
struct Person: stname, stage {
   var name: String
   var age: Int
}
func print(celebrator: stname & stage) {
   print("\(celebrator.name) is \(celebrator.age) years old")
}
let studname = Person(name: "Priya", age: 21)
print(studname)

let stud = Person(name: "Rehan", age: 29)
print(stud)

let student = Person(name: "Roshan", age: 19)
print(student)

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

Person(name: "Priya", age: 21)
Person(name: "Rehan", age: 29)
Person(name: "Roshan", age: 19)

Sprawdzanie zgodności protokołu

Zgodność protokołu jest testowana za pomocą operatorów „is” i „as”, podobnie jak w przypadku rzutowania typu.

  • Operator is zwraca wartość true, jeśli instancja jest zgodna ze standardem protokołu i zwraca wartość false, jeśli się nie powiedzie.

  • Plik as? wersja operatora downcast zwraca opcjonalną wartość typu protokołu, a ta wartość jest równa nil, jeśli instancja nie jest zgodna z tym protokołem.

  • Wersja as operatora downcast wymusza downcast do typu protokołu i wyzwala błąd w czasie wykonywania, jeśli downcast nie powiedzie się.

import Foundation

@objc protocol rectangle {
   var area: Double { get }
}
@objc class Circle: rectangle {
   let pi = 3.1415927
   var radius: Double
   var area: Double { return pi * radius * radius }
   init(radius: Double) { self.radius = radius }
}
@objc class result: rectangle {
   var area: Double
   init(area: Double) { self.area = area }
}
class sides {
   var rectsides: Int
   init(rectsides: Int) { self.rectsides = rectsides }
}
let objects: [AnyObject] = [Circle(radius: 2.0),result(area:198),sides(rectsides: 4)]

for object in objects {
   if let objectWithArea = object as? rectangle {
      print("Area is \(objectWithArea.area)")
   } else {
      print("Rectangle area is not defined")
   }
}

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

Area is 12.5663708
Area is 198.0
Rectangle area is not defined

Język Swift 4 zapewnia „ogólne” funkcje do pisania elastycznych funkcji i typów wielokrotnego użytku. Typy generyczne są używane w celu uniknięcia powielania i zapewnienia abstrakcji. Standardowe biblioteki Swift 4 są zbudowane przy użyciu kodu generycznego. Typy „Arrays” i „Dictionary” w języku Swift 4s należą do kolekcji ogólnych. Za pomocą tablic i słowników tablice są definiowane tak, aby zawierały wartości „Int” i „String” lub dowolne inne typy.

func exchange(a: inout Int, b: inout Int) {
   let temp = a
   a = b
   b = temp
}

var numb1 = 100
var numb2 = 200

print("Before Swapping values are: \(numb1) and \(numb2)")
exchange(a: &numb1, b: &numb2)
print("After Swapping values are: \(numb1) and \(numb2)")

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

Before Swapping values are: 100 and 200
After Swapping values are: 200 and 100

Funkcje ogólne: parametry typu

Funkcje ogólne mogą służyć do uzyskiwania dostępu do dowolnego typu danych, takiego jak „Int” lub „String”.

func exchange<T>(a: inout T, b: inout T) {
   let temp = a
   a = b
   b = temp
}
var numb1 = 100
var numb2 = 200

print("Before Swapping Int values are: \(numb1) and \(numb2)")
exchange(a: &numb1, b: &numb2)
print("After Swapping Int values are: \(numb1) and \(numb2)")

var str1 = "Generics"
var str2 = "Functions"

print("Before Swapping String values are: \(str1) and \(str2)")
exchange(a: &str1, b: &str2)
print("After Swapping String values are: \(str1) and \(str2)")

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

Before Swapping Int values are: 100 and 200
After Swapping Int values are: 200 and 100
Before Swapping String values are: Generics and Functions
After Swapping String values are: Functions and Generics

Funkcja exchange () służy do zamiany wartości, co jest opisane w powyższym programie, a <T> jest używany jako parametr typu. Po raz pierwszy wywoływana jest funkcja exchange () w celu zwrócenia wartości „Int”, a drugie wywołanie funkcji exchange () zwróci wartości „String”. W nawiasach ostrych można umieścić wiele typów parametrów, oddzielonych przecinkami.

Parametry typu są nazywane jak zdefiniowane przez użytkownika, aby poznać przeznaczenie parametru typu, który przechowuje. Swift 4 udostępnia <T> jako nazwę parametru typu ogólnego. Jednak parametry typu, takie jak tablice i słowniki, można również nazwać jako klucz, wartość, aby zidentyfikować, że należą do typu „Słownik”.

struct TOS<T> {
   var items = [T]()
   mutating func push(item: T) {
      items.append(item)
   }
   mutating func pop() -> T {
      return items.removeLast()
   }
}

var tos = TOS<String>()
tos.push(item: "Swift 4")
print(tos.items)

tos.push(item: "Generics")
print(tos.items)

tos.push(item: "Type Parameters")
print(tos.items)

tos.push(item: "Naming Type Parameters")
print(tos.items)

let deletetos = tos.pop()

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

[Swift 4]
[Swift 4, Generics]
[Swift 4, Generics, Type Parameters]
[Swift 4, Generics, Type Parameters, Naming Type Parameters]

Rozszerzanie typu ogólnego

Rozszerzenie właściwości stosu w celu poznania górnej części elementu jest zawarte w słowie kluczowym „rozszerzenie”.

struct TOS<T> {
   var items = [T]()
   mutating func push(item: T) {
      items.append(item)
   }
   mutating func pop() -> T {
      return items.removeLast()
   }
}
var tos = TOS<String>()
tos.push(item: "Swift 4")
print(tos.items)

tos.push(item: "Generics")
print(tos.items)

tos.push(item: "Type Parameters")
print(tos.items)

tos.push(item: "Naming Type Parameters")
print(tos.items)

extension TOS {
   var first: T? {
      return items.isEmpty ? nil : items[items.count - 1]
   }
}
if let first = tos.first {
   print("The top item on the stack is \(first).")
}

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

["Swift 4"]
["Swift 4", "Generics"]
["Swift 4", "Generics", "Type Parameters"]
["Swift 4", "Generics", "Type Parameters", "Naming Type Parameters"]
The top item on the stack is Naming Type Parameters.

Ograniczenia typu

Język Swift 4 umożliwia „ograniczeniom typu” określenie, czy parametr typu dziedziczy z określonej klasy, czy też zapewnienie standardu zgodności protokołu.

func exchange<T>(a: inout T, b: inout T) {
   let temp = a
   a = b
   b = temp
}
var numb1 = 100
var numb2 = 200

print("Before Swapping Int values are: \(numb1) and \(numb2)")
exchange(a: &numb1, b: &numb2)
print("After Swapping Int values are: \(numb1) and \(numb2)")

var str1 = "Generics"
var str2 = "Functions"

print("Before Swapping String values are: \(str1) and \(str2)")
exchange(a: &str1, b: &str2)
print("After Swapping String values are: \(str1) and \(str2)")

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

Before Swapping Int values are: 100 and 200
After Swapping Int values are: 200 and 100
Before Swapping String values are: Generics and Functions
After Swapping String values are: Functions and Generics

Powiązane typy

Swift 4 umożliwia zadeklarowanie powiązanych typów w definicji protokołu za pomocą słowa kluczowego „typ skojarzony”.

protocol Container {
   associatedtype ItemType
   mutating func append(item: ItemType)
   var count: Int { get }
   subscript(i: Int) -> ItemType { get }
}
struct TOS<T>: Container {
   // original Stack<T> implementation
   var items = [T]()
   mutating func push(item: T) {
      items.append(item)
   }
   mutating func pop() -> T {
      return items.removeLast()
   }
   
   // conformance to the Container protocol
   mutating func append(item: T) {
      self.push(item: item)
   }
   var count: Int {
      return items.count
   }
   subscript(i: Int) -> T {
      return items[i]
   }
}
var tos = TOS<String>()
tos.push(item: "Swift 4")
print(tos.items)

tos.push(item: "Generics")
print(tos.items)

tos.push(item: "Type Parameters")
print(tos.items)

tos.push(item: "Naming Type Parameters")
print(tos.items)

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

[Swift 4]
[Swift 4, Generics]
[Swift 4, Generics, Type Parameters]
[Swift 4, Generics, Type Parameters, Naming Type Parameters]

Gdzie klauzule

Ograniczenia typu umożliwiają użytkownikowi definiowanie wymagań dotyczących parametrów typu skojarzonych z funkcją lub typem ogólnym. Do definiowania wymagań dla powiązanych typów klauzule „gdzie” są zadeklarowane jako część listy parametrów typu. Słowo kluczowe `` gdzie '' jest umieszczane bezpośrednio po liście parametrów typu, po których następują ograniczenia powiązanych typów, relacje równości między typami i powiązane typy.

protocol Container {
   associatedtype ItemType
   mutating func append(item: ItemType)
   var count: Int { get }
   subscript(i: Int) -> ItemType { get }
}
struct Stack<T>: Container {
   // original Stack<T> implementation
   var items = [T]()
   mutating func push(item: T) {
      items.append(item)
   }
   mutating func pop() -> T {
      return items.removeLast()
   }

   // conformance to the Container protocol
   mutating func append(item: T) {
      self.push(item: item)
   }
   var count: Int {
      return items.count
   }
   subscript(i: Int) -> T {
      return items[i]
   }
}
func allItemsMatch<
C1: Container, C2: Container
where C1.ItemType == C2.ItemType, C1.ItemType: Equatable>
(someContainer: C1, anotherContainer: C2) -> Bool {
   // check that both containers contain the same number of items
   if someContainer.count != anotherContainer.count {
      return false
   }
   
   // check each pair of items to see if they are equivalent
   for i in 0..<someContainer.count {
      if someContainer[i] != anotherContainer[i] {
         return false
      }
   }
   // all items match, so return true
   return true
}  
var tos = Stack<String>()

tos.push(item: "Swift 4")
print(tos.items)

tos.push(item: "Generics")
print(tos.items)

tos.push(item: "Where Clause")
print(tos.items)

var eos = ["Swift 4", "Generics", "Where Clause"]
print(eos)

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

[Swift 4]
[Swift 4, Generics]
[Swift 4, Generics, Where Clause]
[Swift 4, Generics, Where Clause]

Ograniczenie dostępu do bloków kodu, modułów i abstrakcji odbywa się poprzez kontrolę dostępu. Dostęp do klas, struktur i wyliczeń można uzyskać zgodnie z ich właściwościami, metodami, inicjatorami i indeksami za pomocą mechanizmów kontroli dostępu. Stałe, zmienne i funkcje w protokole są ograniczone i mają dostęp globalny i lokalny poprzez kontrolę dostępu. Kontrola dostępu zastosowana do właściwości, typów i funkcji może być określana jako „jednostki”.

Model kontroli dostępu oparty jest na modułach i plikach źródłowych.

Moduł jest zdefiniowany jako pojedyncza jednostka dystrybucji kodu i można go zaimportować za pomocą słowa kluczowego „import”. Plik źródłowy jest definiowany jako pojedynczy plik kodu źródłowego z modułem umożliwiającym dostęp do wielu typów i funkcji.

Język Swift 4 zapewnia trzy różne poziomy dostępu. Dostęp do nich jest publiczny, wewnętrzny i prywatny.

S.Nr Poziomy dostępu i definicja
1

Public

Umożliwia przetwarzanie jednostek w dowolnym pliku źródłowym z ich modułu definiującego, pliku źródłowego z innego modułu, który importuje moduł definiujący.

2

Internal

Umożliwia używanie jednostek w dowolnym pliku źródłowym z ich modułu definiującego, ale nie w żadnym pliku źródłowym poza tym modułem.

3

Private

Ogranicza użycie jednostki do jej własnego definiującego pliku źródłowego. Dostęp prywatny odgrywa rolę w ukryciu szczegółów implementacji określonej funkcjonalności kodu.

Składnia

public class SomePublicClass {}
internal class SomeInternalClass {}
private class SomePrivateClass {}

public var somePublicVariable = 0
internal let someInternalConstant = 0
private func somePrivateFunction() {}

Kontrola dostępu dla typów funkcji

Niektóre funkcje mogą mieć argumenty zadeklarowane wewnątrz funkcji bez zwracanych wartości. Poniższy program deklaruje a i b jako argumenty funkcji sum (). Wewnątrz samej funkcji wartości argumentów a i b są przekazywane przez wywołanie funkcji sum (), a jej wartości są drukowane, co eliminuje zwracane wartości. Aby ustawić zwracany typ funkcji jako prywatny, zadeklaruj ogólny poziom dostępu funkcji z prywatnym modyfikatorem.

private func sum(a: Int, b: Int) {
   let a = a + b
   let b = a - b
   print(a, b)
}

sum(a: 20, b: 10)
sum(a: 40, b: 10)
sum(a: 24, b: 6)

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

30 20
50 40
30 24

Kontrola dostępu dla typów wyliczeniowych

public enum Student {
   case Name(String)
   case Mark(Int,Int,Int)
}
var studDetails = Student.Name("Swift 4")
var studMarks = Student.Mark(98,97,95)

switch studMarks {
   case .Name(let studName):
      print("Student name is: \(studName).")
   case .Mark(let Mark1, let Mark2, let Mark3):
      print("Student Marks are: \(Mark1),\(Mark2),\(Mark3).")
   
}

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

Student Marks are: 98,97,95

Wyliczanie w języku Swift 4 automatycznie otrzymuje ten sam poziom dostępu dla poszczególnych przypadków wyliczenia. Rozważmy na przykład dostęp do nazwisk studentów i ocen zabezpieczonych w trzech przedmiotach wyliczenie nazwa jest zadeklarowana jako student, a członkowie obecni w klasie enum to nazwa należąca do typu string, znaki są reprezentowane jako mark1, mark2 i mark3 typu danych Integer. Aby uzyskać dostęp do nazwiska ucznia lub ocen, które otrzymali. Teraz obudowa przełącznika wydrukuje nazwisko ucznia, jeśli ten blok przypadku zostanie wykonany, w przeciwnym razie wydrukuje znaki zabezpieczone przez ucznia. Jeśli oba warunki zawiodą, zostanie wykonany domyślny blok.

Kontrola dostępu dla podklas

Swift 4 umożliwia użytkownikowi tworzenie podklas dowolnej klasy, do której można uzyskać dostęp w bieżącym kontekście dostępu. Podklasa nie może mieć wyższego poziomu dostępu niż jej nadklasa. Użytkownikowi nie wolno pisać publicznej podklasy wewnętrznej nadklasy.

public class cricket {
   internal func printIt() {
      print("Welcome to Swift 4 Super Class")
   }
}

internal class tennis: cricket {
   override internal func printIt() {
      print("Welcome to Swift 4 Sub Class")
   }
}

let cricinstance = cricket()
cricinstance.printIt()

let tennisinstance = tennis()
tennisinstance.printIt()

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

Welcome to Swift Super Class
Welcome to Swift Sub Class

Kontrola dostępu do stałych, zmiennych, właściwości i indeksów

Stała, zmienna lub właściwość Swift 4 nie może być zdefiniowana jako publiczna niż jej typ. Nie można pisać własności publicznej o typie prywatnym. Podobnie, indeks dolny nie może być bardziej publiczny niż jego indeks lub typ zwracany.

Gdy stała, zmienna, właściwość lub indeks dolny używają typu prywatnego, stała, zmienna, właściwość lub indeks dolny również muszą być oznaczone jako prywatne -

private var privateInstance = SomePrivateClass()

Getters i Setters

Metody pobierające i ustawiające dla stałych, zmiennych, właściwości i indeksów dolnych automatycznie otrzymują ten sam poziom dostępu, co stała, zmienna, właściwość lub indeks dolny, do których należą.

class Samplepgm {
   var counter: Int = 0{
      willSet(newTotal) {
         print("Total Counter is: \(newTotal)")
      }
      didSet {
         if counter > oldValue {
            print("Newly Added Counter \(counter - oldValue)")
         }
      }
   }
}

let NewCounter = Samplepgm()
NewCounter.counter = 100
NewCounter.counter = 800

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

Total Counter is: 100
Newly Added Counter 100
Total Counter is: 800
Newly Added Counter 700

Kontrola dostępu dla inicjatorów i domyślnych inicjatorów

Niestandardowym inicjatorom można przypisać poziom dostępu mniejszy lub równy typowi, który inicjują. Wymagany inicjator musi mieć ten sam poziom dostępu, co klasa, do której należy. Typy parametrów inicjatora nie mogą być bardziej prywatne niż własny poziom dostępu inicjatora.

Aby zadeklarować każdą podklasę słowa kluczowego „required” inicjalizacji, należy zdefiniować ją przed funkcją init ().

class classA {
   required init() {
      let a = 10
      print(a)
   }
}
class classB: classA {
   required init() {
      let b = 30
      print(b)
   }
}
let res = classA()
let print = classB()

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

10
30
10

Domyślny inicjator ma ten sam poziom dostępu, co typ, który inicjuje, chyba że ten typ jest zdefiniowany jako publiczny. Gdy domyślna inicjalizacja jest zdefiniowana jako publiczna, jest traktowana jako wewnętrzna. Gdy użytkownik potrzebuje, aby typ publiczny był inicjalizowany za pomocą inicjatora bez argumentów w innym module, należy jawnie podać publiczny inicjator bez argumentów jako część definicji typu.

Kontrola dostępu do protokołów

Kiedy definiujemy nowy protokół w celu dziedziczenia funkcjonalności z istniejącego protokołu, oba muszą mieć zadeklarowane te same poziomy dostępu, aby dziedziczyć swoje właściwości. Kontrola dostępu Swift 4 nie pozwoli użytkownikom na zdefiniowanie protokołu „publicznego”, który dziedziczy po protokole „wewnętrznym”.

public protocol tcpprotocol {
   init(no1: Int)
}
public class mainClass {
   var no1: Int      // local storage
   init(no1: Int) {
      self.no1 = no1 // initialization
   }
}
class subClass: mainClass, tcpprotocol {
   var no2: Int
   init(no1: Int, no2 : Int) {
      self.no2 = no2
      super.init(no1:no1)
   }
   
   // Requires only one parameter for convenient method
   required override convenience init(no1: Int) {
      self.init(no1:no1, no2:0)
   }
}

let res = mainClass(no1: 20)
let print = subClass(no1: 30, no2: 50)

print("res is: \(res.no1)")
print("res is: \(print.no1)")
print("res is: \(print.no2)")

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

res is: 20
res is: 30
res is: 50

Kontrola dostępu do rozszerzeń

Swift 4 nie pozwala użytkownikom na zapewnienie jawnego modyfikatora poziomu dostępu dla rozszerzenia, gdy użytkownik używa tego rozszerzenia w celu dodania zgodności z protokołem. Domyślny poziom dostępu dla każdej implementacji wymagań protokołu w ramach rozszerzenia ma własny poziom dostępu do protokołu.

Kontrola dostępu dla typów generycznych

Generics pozwalają użytkownikowi określić minimalne poziomy dostępu, aby uzyskać dostęp do ograniczeń typu w parametrach typu.

public struct TOS<T> {
   var items = [T]()
   mutating func push(item: T) {
      items.append(item)
   }
   mutating func pop() -> T {
      return items.removeLast()
   }
}

var tos = TOS<String>()
tos.push(item: "Swift 4")
print(tos.items)

tos.push(item: "Generics")
print(tos.items)

tos.push(item: "Type Parameters")
print(tos.items)

tos.push(item: "Naming Type Parameters")
print(tos.items)
let deletetos = tos.pop()

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

[Swift 4]
[Swift 4, Generics]
[Swift 4, Generics, Type Parameters]
[Swift 4, Generics, Type Parameters, Naming Type Parameters]

Kontrola dostępu dla aliasów typów

Użytkownik może zdefiniować aliasy typów, aby traktować różne typy kontroli dostępu. Użytkownik może zdefiniować ten sam poziom dostępu lub różne poziomy dostępu. Gdy alias typu jest „prywatny”, skojarzone z nim elementy członkowskie można zadeklarować jako „prywatne, wewnętrzne typu publicznego”. Gdy alias typu jest publiczny, członkowie nie mogą być aliasami jako nazwą „wewnętrzną” ani „prywatną”

Wszystkie zdefiniowane aliasy typów są traktowane jako odrębne typy na potrzeby kontroli dostępu. Alias ​​typu może mieć poziom dostępu mniejszy lub równy poziomowi dostępu typu, do którego jest przypisany. Na przykład alias typu prywatnego może aliasować typ prywatny, wewnętrzny lub publiczny, ale alias typu publicznego nie może aliasować typu wewnętrznego ani prywatnego.

public protocol Container {
   associatedtype ItemType
   mutating func append(item: ItemType)
   var count: Int { get }
   subscript(i: Int) -> ItemType { get }
}
struct Stack<T>: Container {
   // original Stack<T> implementation
   var items = [T]()
   mutating func push(item: T) {
      items.append(item)
   }
   mutating func pop() -> T {
      return items.removeLast()
   }
   
   // conformance to the Container protocol
   mutating func append(item: T) {
      self.push(item: item)
   }
   var count: Int {
      return items.count
   }
   subscript(i: Int) -> T {
      return items[i]
   }
}
func allItemsMatch<
   C1: Container, C2: Container
   where C1.ItemType == C2.ItemType, C1.ItemType: Equatable>
   (someContainer: C1, anotherContainer: C2) -> Bool {
   
   // check that both containers contain the same number of items
   if someContainer.count != anotherContainer.count {
      return false
   }
   
   // check each pair of items to see if they are equivalent
   for i in 0..<someContainer.count {
      if someContainer[i] != anotherContainer[i] {
         return false
      }
   }
   // all items match, so return true
   return true
}
var tos = Stack<String>()
tos.push(item: "Swift 4")
print(tos.items)

tos.push(item: "Generics")
print(tos.items)

tos.push(item: "Where Clause")
print(tos.items)

var eos = ["Swift 4", "Generics", "Where Clause"]
print(eos)

Po uruchomieniu powyższego programu przy użyciu placu zabaw otrzymujemy następujący wynik -

[Swift 4]
[Swift 4, Generics]
[Swift 4, Generics, Where Clause]
[Swift 4, Generics, Where Clause]

Szybkie kodowanie i dekodowanie

Swift 4 wprowadza nowy Codable Protokół, który umożliwia serializację i de-serializację niestandardowych typów danych bez pisania specjalnego kodu - i bez martwienia się o utratę typów wartości.

struct Language: Codable {
   var name: String
   var version: Int
}
let swift = Language(name: "Swift", version: 4)
let java = Language(name: "java", version: 8)
let R = Language(name: "R", version: 3

Zauważ, że Langauage jest zgodny z protokołem Codable. Teraz przekonwertujemy go na reprezentację danych Json za pomocą jednej prostej linii.

let encoder = JSONEncoder()
if let encoded = try? encoder.encode(java) {
   //Perform some operations on this value.
}

Swift automatycznie zakoduje wszystkie wartości w Twoim typie danych.

Możesz dekodować dane za pomocą funkcji dekodera, takiej jak

let decoder = JSONDecoder()
if let decoded = try? decoder.decode(Language.self, from: encoded) {
   //Perform some operations on this value.
}

Zarówno JSONEncoder, jak i jego odpowiednik PropertyListEncoder z listą właściwości mają wiele opcji dostosowywania sposobu ich działania.