Halaman ini diterjemahkan oleh Cloud Translation API.
Switch to English

Tur Swift

Diadaptasi dari A Swift Tour yang asli di Swift.org dengan modifikasi. Konten asli dibuat oleh Apple Inc. Dilisensikan di bawah Lisensi Creative Commons Attribution 4.0 International (CC BY 4.0) .
Lihat di TensorFlow.org Jalankan di Google Colab Lihat sumber di GitHub

Tradisi menunjukkan bahwa program pertama dalam bahasa baru harus mencetak kata-kata "Halo, dunia!" di layar. Di Swift, ini bisa dilakukan dalam satu baris:

 print("Hello, world!")
 
Hello, world!

Jika Anda memiliki kode tertulis dalam C atau Objective-C, sintaks ini terlihat familier bagi Anda — di Swift, baris kode ini adalah program lengkap. Anda tidak perlu mengimpor pustaka terpisah untuk fungsi seperti input / output atau penanganan string. Kode yang ditulis pada lingkup global digunakan sebagai titik masuk untuk program, sehingga Anda tidak memerlukan fungsi main() . Anda juga tidak perlu menulis titik koma di akhir setiap pernyataan.

Tur ini memberi Anda informasi yang cukup untuk mulai menulis kode dalam Swift dengan menunjukkan kepada Anda cara menyelesaikan berbagai tugas pemrograman. Jangan khawatir jika Anda tidak memahami sesuatu — semua yang diperkenalkan dalam tur ini dijelaskan secara rinci di bagian lain buku ini.

Nilai Sederhana

Gunakan let untuk membuat konstanta dan var untuk membuat variabel. Nilai konstanta tidak perlu diketahui pada waktu kompilasi, tetapi Anda harus memberinya nilai tepat sekali. Ini berarti Anda dapat menggunakan konstanta untuk menyebutkan nilai yang Anda tentukan sekali tetapi gunakan di banyak tempat.

 var myVariable = 42
myVariable = 50
let myConstant = 42
 

Konstanta atau variabel harus memiliki tipe yang sama dengan nilai yang ingin Anda tetapkan padanya. Namun, Anda tidak selalu harus menulis jenisnya secara eksplisit. Memberikan nilai ketika Anda membuat konstanta atau variabel memungkinkan kompiler menyimpulkan tipenya. Dalam contoh di atas, kompiler menyimpulkan bahwa myVariable adalah integer karena nilai awalnya adalah integer.

Jika nilai awal tidak memberikan informasi yang cukup (atau jika tidak ada nilai awal), tentukan jenisnya dengan menuliskannya setelah variabel, dipisahkan dengan tanda titik dua. Catatan: menggunakan Double alih-alih Float untuk angka floating point memberi Anda lebih presisi, dan merupakan tipe floating point default di Swift.

 let implicitInteger = 70
let implicitDouble = 70.0
let explicitDouble: Double = 70
 
 // Experiment:
// Create a constant with an explicit type of `Float` and a value of 4.
 

Nilai tidak pernah secara implisit dikonversi ke tipe lain. Jika Anda perlu mengonversi nilai ke tipe yang berbeda, buat instance dari tipe yang diinginkan secara eksplisit.

 let label = "The width is "
let width = 94
label + String(width)
 
"The width is 94"

 // Experiment:
// Try removing the conversion to `String` from the last line. What error do you get?
 

Ada cara yang bahkan lebih sederhana untuk memasukkan nilai dalam string: Tulis nilai dalam tanda kurung, dan tulis garis miring terbalik (``) sebelum tanda kurung. Sebagai contoh:

 let apples = 3
"I have \(apples) apples."
 
"I have 3 apples."

 let oranges = 5
"I have \(apples + oranges) pieces of fruit."
 
"I have 8 pieces of fruit."

 // Experiment:
// Use `\()` to include a floating-point calculation in a string and to include someone's name in a
// greeting.
 

Gunakan tiga tanda kutip ganda ( """ ) untuk string yang mengambil banyak baris. Lekukan pada awal setiap baris yang dikutip dihapus, asalkan cocok dengan lekukan dari tanda kutip penutup. Misalnya:

 let quotation = """
    Even though there's whitespace to the left,
    the actual lines aren't indented.
        Except for this line.
    Double quotes (") can appear without being escaped.

    I still have \(apples + oranges) pieces of fruit.
    """
print(quotation)
 
Even though there's whitespace to the left,
the actual lines aren't indented.
    Except for this line.
Double quotes (") can appear without being escaped.

I still have 8 pieces of fruit.

Buat array dan kamus menggunakan tanda kurung ( [] ), dan akses elemen mereka dengan menulis indeks atau kunci dalam tanda kurung. Koma diizinkan setelah elemen terakhir.

 var shoppingList = ["catfish", "water", "tulips", "blue paint"]
shoppingList[1] = "bottle of water"
 
var occupations = [
    "Malcolm": "Captain",
    "Kaylee": "Mechanic",
]
occupations["Jayne"] = "Public Relations"
occupations
 
▿ 3 elements
  ▿ 0 : 2 elements

    - key : "Malcolm"
    - value : "Captain"
  ▿ 1 : 2 elements
    - key : "Jayne"
    - value : "Public Relations"
  ▿ 2 : 2 elements
    - key : "Kaylee"
    - value : "Mechanic"

Array tumbuh secara otomatis saat Anda menambahkan elemen.

 shoppingList.append("blue paint")
shoppingList
 
▿ 5 elements

  - 0 : "catfish"
  - 1 : "bottle of water"
  - 2 : "tulips"
  - 3 : "blue paint"
  - 4 : "blue paint"

Untuk membuat array atau kamus kosong, gunakan sintaksis initializer.

 let emptyArray = [String]()
let emptyDictionary = [String: Float]()
 

Jika informasi jenis dapat disimpulkan, Anda dapat menulis array kosong sebagai [] dan kamus kosong sebagai [:] - misalnya, ketika Anda menetapkan nilai baru untuk variabel atau meneruskan argumen ke fungsi.

 shoppingList = []
occupations = [:]
 

Aliran Kontrol

Gunakan if dan switch untuk membuat kondisional, dan gunakan for - in , for , while , dan repeat - while untuk membuat loop. Tanda kurung di sekitar variabel kondisi atau loop adalah opsional. Diperlukan kawat gigi di sekitar tubuh.

 let individualScores = [75, 43, 103, 87, 12]
var teamScore = 0
for score in individualScores {
    if score > 50 {
        teamScore += 3
    } else {
        teamScore += 1
    }
}
teamScore
 
11

Dalam pernyataan if , conditional harus berupa ekspresi Boolean — ini berarti kode seperti if score { ... } adalah kesalahan, bukan perbandingan implisit dengan nol.

Anda bisa menggunakan if dan let bersama-sama bekerja dengan nilai-nilai yang mungkin hilang. Nilai-nilai ini direpresentasikan sebagai opsional. Nilai opsional mengandung nilai atau mengandung nil untuk menunjukkan bahwa nilai hilang. Tulis tanda tanya ( ? ) Setelah jenis nilai untuk menandai nilai sebagai opsional.

 var optionalString: String? = "Hello"
optionalString == nil
 
false

 var optionalName: String? = "John Appleseed"
var greeting = "Hello!"
if let name = optionalName {
    greeting = "Hello, \(name)"
}
greeting
 
"Hello, John Appleseed"

 // Experiment:
// Change `optionalName` to `nil`. What greeting do you get?
// Add an `else` clause that sets a different greeting if `optionalName` is `nil`.
 

Jika nilai opsional nil , kondisional false dan kode dalam kurung dilewati. Jika tidak, nilai opsional tidak terbuka dan ditetapkan ke konstanta setelah let , yang membuat nilai tidak terbuka tersedia di dalam blok kode.

Cara lain untuk menangani nilai opsional adalah dengan memberikan nilai default menggunakan ?? operator. Jika nilai opsional hilang, nilai standar yang digunakan sebagai gantinya.

 let nickName: String? = nil
let fullName: String = "John Appleseed"
"Hi \(nickName ?? fullName)"
 
"Hi John Appleseed"

Switch mendukung segala jenis data dan beragam operasi perbandingan — semuanya tidak terbatas pada bilangan bulat dan pengujian untuk kesetaraan.

 let vegetable = "red pepper"
switch vegetable {
case "celery":
    print("Add some raisins and make ants on a log.")
case "cucumber", "watercress":
    print("That would make a good tea sandwich.")
case let x where x.hasSuffix("pepper"):
    print("Is it a spicy \(x)?")
default:
    print("Everything tastes good in soup.")
}
 
Is it a spicy red pepper?

 // Experiment:
// Try removing the default case. What error do you get?
 

Perhatikan bagaimana let dapat digunakan dalam suatu pola untuk menetapkan nilai yang cocok dengan bagian suatu pola ke konstanta.

Setelah mengeksekusi kode di dalam sakelar yang cocok, program keluar dari pernyataan sakelar. Eksekusi tidak berlanjut ke kasus berikutnya, jadi tidak perlu untuk secara eksplisit keluar dari sakelar di akhir setiap kode kasus.

Anda menggunakan for - in untuk beralih pada item dalam kamus dengan memberikan sepasang nama untuk digunakan untuk setiap pasangan nilai kunci. Kamus adalah kumpulan yang tidak berurutan, sehingga kunci dan nilainya diulang dalam urutan yang sewenang-wenang.

 let interestingNumbers = [
    "Prime": [2, 3, 5, 7, 11, 13],
    "Fibonacci": [1, 1, 2, 3, 5, 8],
    "Square": [1, 4, 9, 16, 25],
]
var largest = 0
for (kind, numbers) in interestingNumbers {
    for number in numbers {
        if number > largest {
            largest = number
        }
    }
}
largest
 
25

 // Experiment:
// Add another variable to keep track of which kind of number was the largest, as well as what that
// largest number was.
 

Gunakan while untuk mengulangi blok kode sampai suatu kondisi berubah. Kondisi loop dapat di akhir sebagai gantinya, memastikan bahwa loop dijalankan setidaknya sekali.

 var n = 2
while n < 100 {
    n = n * 2
}

n
 
128

 var m = 2
repeat {
    m = m * 2
} while m < 100

m
 
128

Anda dapat menyimpan indeks dalam satu lingkaran — baik dengan menggunakan ..< untuk membuat rentang indeks atau dengan menulis inisialisasi eksplisit, kondisi, dan kenaikan. Dua loop ini melakukan hal yang sama:

 var total = 0
for i in 0..<4 {
    total += i
}

total
 
6

Gunakan ..< untuk membuat rentang yang menghilangkan nilai atasnya, dan gunakan ... untuk membuat rentang yang menyertakan kedua nilai.

Fungsi dan Penutupan

Gunakan func untuk mendeklarasikan suatu fungsi. Panggil fungsi dengan mengikuti namanya dengan daftar argumen dalam tanda kurung. Gunakan -> untuk memisahkan nama dan tipe parameter dari tipe pengembalian fungsi.

 func greet(name: String, day: String) -> String {
    return "Hello \(name), today is \(day)."
}
greet(name: "Bob", day: "Tuesday")
 
"Hello Bob, today is Tuesday."

 // Experiment:
// Remove the `day` parameter. Add a parameter to include today’s lunch special in the greeting.
 

Secara default, fungsi menggunakan nama parameter mereka sebagai label untuk argumen mereka. Tulis label argumen khusus sebelum nama parameter, atau tulis _ untuk tidak menggunakan label argumen.

 func greet(_ person: String, on day: String) -> String {
    return "Hello \(person), today is \(day)."
}
greet("John", on: "Wednesday")
 
"Hello John, today is Wednesday."

Gunakan tupel untuk membuat nilai majemuk — misalnya, untuk mengembalikan beberapa nilai dari suatu fungsi. Unsur-unsur tupel dapat disebut dengan nama atau nomor.

 func calculateStatistics(scores: [Int]) -> (min: Int, max: Int, sum: Int) {
    var min = scores[0]
    var max = scores[0]
    var sum = 0
    
    for score in scores {
        if score > max {
            max = score
        } else if score < min {
            min = score
        }
        sum += score
    }
    
    return (min, max, sum)
}
let statistics = calculateStatistics(scores: [5, 3, 100, 3, 9])
print(statistics.sum)
print(statistics.2)
 
120
120

Fungsi dapat disarangkan. Fungsi bersarang memiliki akses ke variabel yang dideklarasikan di fungsi luar. Anda dapat menggunakan fungsi bersarang untuk mengatur kode dalam fungsi yang panjang atau kompleks.

 func returnFifteen() -> Int {
    var y = 10
    func add() {
        y += 5
    }
    add()
    return y
}
returnFifteen()
 
15

Fungsi adalah tipe kelas satu. Ini berarti bahwa suatu fungsi dapat mengembalikan fungsi lain sebagai nilainya.

 func makeIncrementer() -> ((Int) -> Int) {
    func addOne(number: Int) -> Int {
        return 1 + number
    }
    return addOne
}
var increment = makeIncrementer()
increment(7)
 
8

Suatu fungsi dapat mengambil fungsi lain sebagai salah satu argumennya.

 func hasAnyMatches(list: [Int], condition: (Int) -> Bool) -> Bool {
    for item in list {
        if condition(item) {
            return true
        }
    }
    return false
}
func lessThanTen(number: Int) -> Bool {
    return number < 10
}
var numbers = [20, 19, 7, 12]
hasAnyMatches(list: numbers, condition: lessThanTen)
 
true

Fungsi sebenarnya adalah kasus khusus penutupan: blok kode yang dapat dipanggil nanti. Kode dalam penutupan memiliki akses ke hal-hal seperti variabel dan fungsi yang tersedia di ruang lingkup di mana penutupan dibuat, bahkan jika penutupan itu dalam ruang lingkup yang berbeda ketika dijalankan — Anda melihat contoh ini sudah dengan fungsi bersarang. Anda dapat menulis penutupan tanpa nama dengan kode di sekelilingnya dengan kurung kurawal ( {} ). Gunakan in untuk memisahkan argumen dan jenis kembali dari tubuh.

 numbers.map({ (number: Int) -> Int in
    let result = 3 * number
    return result
})
 
▿ 4 elements

  - 0 : 60
  - 1 : 57
  - 2 : 21
  - 3 : 36

 // Experiment:
// Rewrite the closure to return zero for all odd numbers.
 

Anda memiliki beberapa opsi untuk menulis penutupan lebih ringkas. Ketika tipe penutupan sudah diketahui, seperti panggilan balik untuk delegasi, Anda dapat menghilangkan jenis parameternya, jenis pengembaliannya, atau keduanya. Pernyataan tunggal ditutup secara implisit mengembalikan nilai pernyataan mereka satu-satunya.

 let mappedNumbers = numbers.map({ number in 3 * number })
print(mappedNumbers)
 
[60, 57, 21, 36]

Anda bisa merujuk ke parameter dengan angka alih-alih dengan nama — pendekatan ini sangat berguna dalam penutupan yang sangat singkat. Penutupan dilewatkan sebagai argumen terakhir ke suatu fungsi dapat muncul segera setelah tanda kurung. Saat penutupan adalah satu-satunya argumen untuk suatu fungsi, Anda bisa menghilangkan tanda kurung seluruhnya.

 let sortedNumbers = numbers.sorted { $0 > $1 }
print(sortedNumbers)
 
[20, 19, 12, 7]

Obyek dan Kelas

Gunakan class diikuti dengan nama kelas untuk membuat kelas. Deklarasi properti di kelas ditulis dengan cara yang sama dengan deklarasi konstan atau variabel, kecuali bahwa itu dalam konteks kelas. Demikian juga, deklarasi metode dan fungsi ditulis dengan cara yang sama.

 class Shape {
    var numberOfSides = 0
    func simpleDescription() -> String {
        return "A shape with \(numberOfSides) sides."
    }
}
 
 // Experiment:
// Add a constant property with `let`, and add another method that takes an argument.
 

Buat instance kelas dengan menempatkan tanda kurung setelah nama kelas. Gunakan sintaksis titik untuk mengakses properti dan metode instance.

 var shape = Shape()
shape.numberOfSides = 7
var shapeDescription = shape.simpleDescription()
 

Versi kelas Shape ini kehilangan sesuatu yang penting: penginisialisasi untuk mengatur kelas saat instance dibuat. Gunakan init untuk membuatnya.

 class NamedShape {
    var numberOfSides: Int = 0
    var name: String
    
    init(name: String) {
        self.name = name
    }
    
    func simpleDescription() -> String {
        return "A shape with \(numberOfSides) sides."
    }
}
 

Perhatikan bagaimana self digunakan untuk membedakan properti name dari argumen name ke penginisialisasi. Argumen ke penginisialisasi disahkan seperti panggilan fungsi ketika Anda membuat turunan dari kelas. Setiap properti membutuhkan nilai yang ditetapkan — baik dalam deklarasi (seperti dengan numberOfSides ) atau dalam penginisialisasi (seperti dengan name ).

Gunakan deinit untuk membuat deinitializer jika Anda perlu melakukan pembersihan sebelum objek tersebut dialokasikan.

Subclass termasuk nama superclass mereka setelah nama kelas mereka, dipisahkan oleh tanda titik dua. Tidak ada persyaratan untuk kelas untuk subkelas kelas root standar, sehingga Anda dapat memasukkan atau menghilangkan superclass sesuai kebutuhan.

Metode pada subkelas yang menimpa implementasi superclass ditandai dengan override —mengganti metode secara tidak sengaja, tanpa override , terdeteksi oleh kompiler sebagai kesalahan. Compiler juga mendeteksi metode dengan override yang sebenarnya tidak menimpa metode apa pun di superclass.

 class Square: NamedShape {
    var sideLength: Double
    
    init(sideLength: Double, name: String) {
        self.sideLength = sideLength
        super.init(name: name)
        numberOfSides = 4
    }
    
    func area() -> Double {
        return sideLength * sideLength
    }
    
    override func simpleDescription() -> String {
        return "A square with sides of length \(sideLength)."
    }
}
let test = Square(sideLength: 5.2, name: "my test square")
test.area()
test.simpleDescription()
 
"A square with sides of length 5.2."

 // Experiment:
// - Make another subclass of `NamedShape` called `Circle` that takes a radius and a name as
//   arguments to its initializer.
// - Implement an `area()` and a `simpleDescription()` method on the `Circle` class.
 

Selain properti sederhana yang disimpan, properti dapat memiliki pengambil dan penyetel.

 class EquilateralTriangle: NamedShape {
    var sideLength: Double = 0.0
    
    init(sideLength: Double, name: String) {
        self.sideLength = sideLength
        super.init(name: name)
        numberOfSides = 3
    }
    
    var perimeter: Double {
        get {
            return 3.0 * sideLength
        }
        set {
            sideLength = newValue / 3.0
        }
    }
    
    override func simpleDescription() -> String {
        return "An equilateral triangle with sides of length \(sideLength)."
    }
}
var triangle = EquilateralTriangle(sideLength: 3.1, name: "a triangle")
print(triangle.perimeter)
triangle.perimeter = 9.9
print(triangle.sideLength)
 
9.3
3.3000000000000003

Dalam setter untuk perimeter , nilai baru memiliki nama implisit newValue . Anda dapat memberikan nama eksplisit dalam tanda kurung setelah set .

Perhatikan bahwa penginisialisasi untuk kelas EquilateralTriangle memiliki tiga langkah berbeda:

  1. Menyetel nilai properti yang dinyatakan oleh subclass.

  2. Memanggil initializer superclass.

  3. Mengubah nilai properti yang ditentukan oleh superclass. Pekerjaan pengaturan tambahan apa pun yang menggunakan metode, getter, atau setter juga dapat dilakukan pada saat ini.

Jika Anda tidak perlu menghitung properti tetapi masih perlu memberikan kode yang dijalankan sebelum dan setelah menetapkan nilai baru, gunakan willSet dan didSet . Kode yang Anda berikan dijalankan setiap saat nilainya berubah di luar penginisialisasi. Misalnya, kelas di bawah memastikan bahwa panjang sisi segitiga selalu sama dengan panjang sisi kuadratnya.

 class TriangleAndSquare {
    var triangle: EquilateralTriangle {
        willSet {
            square.sideLength = newValue.sideLength
        }
    }
    var square: Square {
        willSet {
            triangle.sideLength = newValue.sideLength
        }
    }
    init(size: Double, name: String) {
        square = Square(sideLength: size, name: name)
        triangle = EquilateralTriangle(sideLength: size, name: name)
    }
}
var triangleAndSquare = TriangleAndSquare(size: 10, name: "another test shape")
print(triangleAndSquare.square.sideLength)
print(triangleAndSquare.triangle.sideLength)
triangleAndSquare.square = Square(sideLength: 50, name: "larger square")
print(triangleAndSquare.triangle.sideLength)
 
10.0
10.0
50.0

Ketika bekerja dengan nilai-nilai opsional, Anda dapat menulis ? sebelum operasi seperti metode, properti, dan berlangganan. Jika nilainya sebelum ? adalah nil , semuanya setelah ? diabaikan dan nilai keseluruhan ekspresi adalah nil . Jika tidak, nilai opsional tidak terbuka, dan semuanya setelah ? bertindak berdasarkan nilai yang tidak terbuka. Dalam kedua kasus, nilai keseluruhan ekspresi adalah nilai opsional.

 let optionalSquare: Square? = Square(sideLength: 2.5, name: "optional square")
optionalSquare?.sideLength
 
▿ Optional<Double>

  - some : 2.5

Enumerasi dan Struktur

Gunakan enum untuk membuat enumerasi. Seperti kelas dan semua jenis nama lainnya, enumerasi dapat memiliki metode yang terkait dengannya.

 enum Rank: Int {
    case ace = 1
    case two, three, four, five, six, seven, eight, nine, ten
    case jack, queen, king

    func simpleDescription() -> String {
        switch self {
        case .ace:
            return "ace"
        case .jack:
            return "jack"
        case .queen:
            return "queen"
        case .king:
            return "king"
        default:
            return String(self.rawValue)
        }
    }
}
let ace = Rank.ace
print(ace)
let aceRawValue = ace.rawValue
print(aceRawValue)
 
ace
1

 // Experiment:
// Write a function that compares two `Rank` values by comparing their raw values.
 

Secara default, Swift menetapkan nilai mentah mulai dari nol dan bertambah satu setiap kali, tetapi Anda dapat mengubah perilaku ini dengan secara eksplisit menentukan nilai. Pada contoh di atas, Ace secara eksplisit diberi nilai mentah 1 , dan nilai mentah lainnya ditetapkan secara berurutan. Anda juga bisa menggunakan angka string atau floating-point sebagai tipe mentah enumerasi. Gunakan properti rawValue untuk mengakses nilai mentah kasus enumerasi.

Gunakan init?(rawValue:) untuk membuat instance enumerasi dari nilai mentah. Ini mengembalikan salah satu kasus enumerasi yang cocok dengan nilai mentah atau nil jika tidak ada Rank cocok.

 if let convertedRank = Rank(rawValue: 3) {
    let threeDescription = convertedRank.simpleDescription()
}
 

Nilai case dari enumerasi adalah nilai aktual, bukan hanya cara lain untuk menulis nilai mentah mereka. Bahkan, dalam kasus di mana tidak ada nilai mentah yang berarti, Anda tidak harus menyediakannya.

 enum Suit {
    case spades, hearts, diamonds, clubs

    func simpleDescription() -> String {
        switch self {
        case .spades:
            return "spades"
        case .hearts:
            return "hearts"
        case .diamonds:
            return "diamonds"
        case .clubs:
            return "clubs"
        }
    }
}
let hearts = Suit.hearts
let heartsDescription = hearts.simpleDescription()
 
 // Experiment:
// Add a `color()` method to `Suit` that returns "black" for spades and clubs, and returns "red" for
// hearts and diamonds.
 

Perhatikan dua cara bahwa kasus Hearts of the enumeration disebut di atas: Ketika memberikan nilai ke konstanta hearts , the enumeration case Suit.Hearts disebut dengan nama lengkapnya karena konstanta tidak memiliki jenis eksplisit yang ditentukan. Di dalam sakelar, kotak pencacah disebut dengan bentuk yang disingkat. .Hearts karena nilai self sudah dikenal sebagai jas. Anda dapat menggunakan formulir yang disingkat kapan pun jenis nilainya sudah diketahui.

Jika enumerasi memiliki nilai mentah, nilai-nilai tersebut ditentukan sebagai bagian dari deklarasi, yang berarti setiap instance dari kasus enumerasi tertentu selalu memiliki nilai mentah yang sama. Pilihan lain untuk kasus pencacahan adalah untuk memiliki nilai yang terkait dengan kasus tersebut — nilai-nilai ini ditentukan ketika Anda membuat instance, dan mereka dapat berbeda untuk setiap instance dari kasus enumerasi. Anda dapat menganggap nilai terkait sebagai berperilaku seperti properti tersimpan dari instance case enumeration.

Misalnya, perhatikan kasus meminta waktu matahari terbit dan terbenam dari server. Server merespons dengan informasi yang diminta, atau merespons dengan deskripsi tentang apa yang salah.

 enum ServerResponse {
    case result(String, String)
    case failure(String)
}

let success = ServerResponse.result("6:00 am", "8:09 pm")
let failure = ServerResponse.failure("Out of cheese.")

switch success {
case let .result(sunrise, sunset):
    print("Sunrise is at \(sunrise) and sunset is at \(sunset).")
case let .failure(message):
    print("Failure...  \(message)")
}
 
Sunrise is at 6:00 am and sunset is at 8:09 pm.

 // Experiment:
// Add a third case to `ServerResponse` and to the switch.
 

Perhatikan bagaimana waktu matahari terbit dan terbenam diekstraksi dari nilai ServerResponse sebagai bagian dari pencocokan nilai terhadap kasus sakelar.

Gunakan struct untuk membuat struktur. Struktur mendukung banyak perilaku yang sama seperti kelas, termasuk metode dan inisialisasi. Salah satu perbedaan paling penting antara struktur dan kelas adalah bahwa struktur selalu disalin ketika mereka diedarkan dalam kode Anda, tetapi kelas dilewati oleh referensi.

 struct Card {
    var rank: Rank
    var suit: Suit
    func simpleDescription() -> String {
        return "The \(rank.simpleDescription()) of \(suit.simpleDescription())"
    }
}
let threeOfSpades = Card(rank: .three, suit: .spades)
let threeOfSpadesDescription = threeOfSpades.simpleDescription()
 
 // Experiment:
// Write a function that returns an array containing a full deck of cards, with one card of each
// combination of rank and suit.
 

Protokol dan Ekstensi

Gunakan protocol untuk mendeklarasikan protokol.

 protocol ExampleProtocol {
    var simpleDescription: String { get }
    mutating func adjust()
}
 

Kelas, enumerasi, dan struct semua bisa mengadopsi protokol.

 class SimpleClass: ExampleProtocol {
    var simpleDescription: String = "A very simple class."
    var anotherProperty: Int = 69105
    func adjust() {
        simpleDescription += "  Now 100% adjusted."
    }
}
var a = SimpleClass()
a.adjust()
let aDescription = a.simpleDescription
 
struct SimpleStructure: ExampleProtocol {
    var simpleDescription: String = "A simple structure"
    mutating func adjust() {
        simpleDescription += " (adjusted)"
    }
}
var b = SimpleStructure()
b.adjust()
b.simpleDescription
 
"A simple structure (adjusted)"

 // Experiment:
// Add another requirement to `ExampleProtocol`.
// What changes do you need to make to `SimpleClass` and `SimpleStructure` so that they still
// conform to the protocol?
 

Perhatikan penggunaan kata kunci yang mutating dalam deklarasi SimpleStructure untuk menandai metode yang memodifikasi struktur. Deklarasi SimpleClass tidak memerlukan metode apa pun yang ditandai bermutasi karena metode pada suatu kelas selalu dapat memodifikasi kelas.

Gunakan extension untuk menambahkan fungsionalitas ke tipe yang ada, seperti metode baru dan properti yang dihitung. Anda bisa menggunakan ekstensi untuk menambahkan kesesuaian protokol ke jenis yang dideklarasikan di tempat lain, atau bahkan ke jenis yang Anda impor dari perpustakaan atau kerangka kerja.

 extension Int: ExampleProtocol {
    public var simpleDescription: String {
        return "The number \(self)"
    }
    public mutating func adjust() {
        self += 42
    }
}
7.simpleDescription
 
"The number 7"

 // Experiment:
// Write an extension for the `Double` type that adds an `absoluteValue` property.
 

Anda dapat menggunakan nama protokol sama seperti jenis bernama lainnya — misalnya, untuk membuat kumpulan objek yang memiliki tipe berbeda tetapi semuanya sesuai dengan satu protokol. Saat Anda bekerja dengan nilai yang tipenya merupakan tipe protokol, metode di luar definisi protokol tidak tersedia.

 let protocolValue: ExampleProtocol = a
protocolValue.simpleDescription
 
"A very simple class.  Now 100% adjusted."

 // Uncomment to see the error.
// protocolValue.anotherProperty
 

Meskipun variabel protocolValue memiliki tipe runtime dari SimpleClass , kompiler memperlakukannya sebagai tipe yang diberikan dari ExampleProtocol . Ini berarti bahwa Anda tidak dapat secara tidak sengaja mengakses metode atau properti yang diterapkan kelas sebagai tambahan atas kesesuaian protokolnya.

Penanganan Kesalahan

Anda mewakili kesalahan menggunakan jenis apa pun yang mengadopsi protokol Error .

 enum PrinterError: Error {
    case outOfPaper
    case noToner
    case onFire
}
 

Gunakan throw untuk melempar kesalahan dan throws untuk menandai fungsi yang bisa melempar kesalahan. Jika Anda melemparkan kesalahan dalam suatu fungsi, fungsi kembali segera dan kode yang disebut fungsi menangani kesalahan.

 func send(job: Int, toPrinter printerName: String) throws -> String {
    if printerName == "Never Has Toner" {
        throw PrinterError.noToner
    }
    return "Job sent"
}
 

Ada beberapa cara untuk menangani kesalahan. Salah satu caranya adalah menggunakan do-catch . Di dalam blok do , Anda menandai kode yang dapat melempar kesalahan dengan menulis coba di depannya. Di dalam blok catch , kesalahan secara otomatis diberi error nama kecuali Anda memberinya nama yang berbeda.

 do {
    let printerResponse = try send(job: 1040, toPrinter: "Bi Sheng")
    print(printerResponse)
} catch {
    print(error)
}
 
Job sent

 // Experiment:
// Change the printer name to `"Never Has Toner"`, so that the `send(job:toPrinter:)` function
// throws an error.
 

Anda dapat memberikan beberapa blok catch yang menangani kesalahan tertentu. Anda menulis pola setelah catch sama seperti yang Anda lakukan setelah case dalam switch.

 do {
    let printerResponse = try send(job: 1440, toPrinter: "Gutenberg")
    print(printerResponse)
} catch PrinterError.onFire {
    print("I'll just put this over here, with the rest of the fire.")
} catch let printerError as PrinterError {
    print("Printer error: \(printerError).")
} catch {
    print(error)
}
 
Job sent

 // Experiment:
// Add code to throw an error inside the `do` block.
// What kind of error do you need to throw so that the error is handled by the first `catch` block?
// What about the second and third blocks?
 

Cara lain untuk menangani kesalahan adalah menggunakan try? untuk mengubah hasilnya menjadi opsional. Jika fungsi melempar kesalahan, kesalahan spesifik dibuang dan hasilnya nil . Jika tidak, hasilnya adalah opsional yang berisi nilai yang dikembalikan fungsi.

 let printerSuccess = try? send(job: 1884, toPrinter: "Mergenthaler")
let printerFailure = try? send(job: 1885, toPrinter: "Never Has Toner")
 

Gunakan defer untuk menulis blok kode yang dieksekusi setelah semua kode lain dalam fungsi, tepat sebelum fungsi kembali. Kode dieksekusi terlepas dari apakah fungsi melempar kesalahan. Anda dapat menggunakan defer untuk menulis kode pengaturan dan pembersihan di samping satu sama lain, meskipun mereka harus dijalankan pada waktu yang berbeda.

 var fridgeIsOpen = false
let fridgeContent = ["milk", "eggs", "leftovers"]

func fridgeContains(_ food: String) -> Bool {
    fridgeIsOpen = true
    defer {
        fridgeIsOpen = false
    }

    let result = fridgeContent.contains(food)
    return result
}
fridgeContains("banana")
fridgeIsOpen
 
false

Generik

Tulis nama di dalam kurung sudut untuk membuat fungsi atau tipe umum.

 func makeArray<Item>(repeating item: Item, numberOfTimes: Int) -> [Item] {
    var result = [Item]()
    for _ in 0..<numberOfTimes {
        result.append(item)
    }
    return result
}
makeArray(repeating: "knock", numberOfTimes: 4)
 
▿ 4 elements

  - 0 : "knock"
  - 1 : "knock"
  - 2 : "knock"
  - 3 : "knock"

Anda dapat membuat bentuk umum fungsi dan metode, serta kelas, enumerasi, dan struktur.

 // Reimplement the Swift standard library's optional type
enum OptionalValue<Wrapped> {
    case none
    case some(Wrapped)
}
var possibleInteger: OptionalValue<Int> = .none
possibleInteger = .some(100)
print(possibleInteger)
 
some(100)

Gunakan di where setelah nama jenis untuk menentukan daftar persyaratan - misalnya, untuk meminta jenis untuk mengimplementasikan protokol, untuk memerlukan dua jenis yang sama, atau untuk meminta kelas memiliki superclass tertentu.

 func anyCommonElements<T: Sequence, U: Sequence>(_ lhs: T, _ rhs: U) -> Bool
    where T.Element: Equatable, T.Element == U.Element
{
    for lhsItem in lhs {
        for rhsItem in rhs {
            if lhsItem == rhsItem {
                return true
            }
        }
    }
    return false
}
anyCommonElements([1, 2, 3], [3])
 
true

Menulis <T: Equatable> sama dengan menulis <T> ... where T: Equatable .