Hızlı Bir Tur

Swift.org'daki orijinal A Swift Tour'dan değişikliklerle uyarlanmıştır. Orijinal içerik Apple Inc. tarafından yazılmıştır . Creative Commons Atıf 4.0 Uluslararası (CC BY 4.0) Lisansı kapsamında lisanslanmıştır.
TensorFlow.org'da görüntüleyin Google Colab'da çalıştırın Kaynağı GitHub'da görüntüle

Gelenek, yeni bir dildeki ilk programın "Merhaba dünya!" kelimelerini yazdırması gerektiğini öne sürüyor. ekranda. Swift'de bu tek satırda yapılabilir:

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

C veya Objective-C'de kod yazdıysanız, bu sözdizimi size tanıdık gelecektir; Swift'de bu kod satırı tam bir programdır. Giriş/çıkış veya dize işleme gibi işlevler için ayrı bir kitaplık içe aktarmanıza gerek yoktur. Global kapsamda yazılan kod, programın giriş noktası olarak kullanıldığından, main() işlevine ihtiyacınız yoktur. Ayrıca her ifadenin sonuna noktalı virgül yazmanıza gerek yoktur.

Bu tur, çeşitli programlama görevlerini nasıl gerçekleştireceğinizi göstererek size Swift'de kod yazmaya başlamanız için yeterli bilgi sağlar. Bir şeyi anlamadıysanız endişelenmeyin; bu turda tanıtılan her şey, bu kitabın geri kalanında ayrıntılı olarak açıklanmaktadır.

Basit Değerler

Bir sabit oluşturmak için let , değişken oluşturmak için ise var kullanın. Bir sabitin değerinin derleme zamanında bilinmesine gerek yoktur, ancak ona tam olarak bir kez değer atamanız gerekir. Bu, bir kez belirlediğiniz ancak birçok yerde kullandığınız bir değeri adlandırmak için sabitleri kullanabileceğiniz anlamına gelir.

var myVariable = 42
myVariable = 50
let myConstant = 42

Bir sabit veya değişken, kendisine atamak istediğiniz değerle aynı türde olmalıdır. Ancak türü her zaman açıkça yazmanız gerekmez. Bir sabit veya değişken oluşturduğunuzda bir değer sağlamak, derleyicinin onun türünü çıkarmasına olanak tanır. Yukarıdaki örnekte derleyici, myVariable başlangıç ​​değeri bir tam sayı olduğu için bir tam sayı olduğu sonucunu çıkarır.

Başlangıç ​​değeri yeterli bilgi sağlamıyorsa (veya başlangıç ​​değeri yoksa), değişkenden sonra iki nokta üst üste işaretiyle ayırarak yazarak türü belirtin. Not: Kayan noktalı sayılar için Float yerine Double kullanmak size daha fazla hassasiyet sağlar ve Swift'deki varsayılan kayan nokta türüdür.

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.

Değerler hiçbir zaman örtülü olarak başka bir türe dönüştürülmez. Bir değeri farklı bir türe dönüştürmeniz gerekiyorsa açıkça istenen türün bir örneğini oluşturun.

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

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

Değerleri dizelere dahil etmenin daha da basit bir yolu var: Değeri parantez içine yazın ve parantezlerin önüne ters eğik çizgi (``) yazın. Örneğin:

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

let oranges = 5
print("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.

Birden fazla satır kaplayan dizeler için üç adet çift tırnak işareti ( """ ) kullanın. Her tırnaklı satırın başlangıcındaki girinti, kapanış tırnak işaretlerinin girintisiyle eşleştiği sürece kaldırılır. Örneğin:

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.

Parantezleri ( [] ) kullanarak diziler ve sözlükler oluşturun ve dizini veya anahtarı parantez içine yazarak bunların öğelerine erişin. Son öğeden sonra virgül konulabilir.

var shoppingList = ["catfish", "water", "tulips", "blue paint"]
shoppingList[1] = "bottle of water"

var occupations = [
    "Malcolm": "Captain",
    "Kaylee": "Mechanic",
]
occupations["Jayne"] = "Public Relations"
print(occupations)
["Jayne": "Public Relations", "Kaylee": "Mechanic", "Malcolm": "Captain"]

Siz öğe ekledikçe diziler otomatik olarak büyür.

shoppingList.append("blue paint")
print(shoppingList)
["catfish", "bottle of water", "tulips", "blue paint", "blue paint"]

Boş bir dizi veya sözlük oluşturmak için başlatıcı sözdizimini kullanın.

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

Tür bilgisi çıkarılabiliyorsa, boş bir diziyi [] olarak ve boş bir sözlüğü [:] olarak yazabilirsiniz; örneğin, bir değişken için yeni bir değer ayarladığınızda veya bir işleve bir argüman ilettiğinizde.

shoppingList = []
occupations = [:]

Kontrol Akışı

Koşul ifadeleri oluşturmak için if ve switch kullanın ve döngüler oluşturmak için for - in , for , while ve repeat - while kullanın. Koşul veya döngü değişkeninin etrafındaki parantezler isteğe bağlıdır. Vücudun etrafında diş telleri gereklidir.

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

Bir if ifadesinde, koşul bir Boolean ifadesi olmalıdır; bu if score { ... } gibi kodun bir hata olduğu, sıfırla örtülü bir karşılaştırma olmadığı anlamına gelir.

Eksik olabilecek değerlerle çalışmak için if ve let birlikte kullanabilirsiniz. Bu değerler isteğe bağlı olarak temsil edilir. İsteğe bağlı bir değer, bir değerin eksik olduğunu belirtmek için bir değer içerir veya nil içerir. Değeri isteğe bağlı olarak işaretlemek için değer türünden sonra bir soru işareti ( ? ) yazın.

var optionalString: String? = "Hello"
print(optionalString == nil)
false

var optionalName: String? = "John Appleseed"
var greeting = "Hello!"
if let name = optionalName {
    greeting = "Hello, \(name)"
}
print(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`.

İsteğe bağlı değer nil ise koşul false olur ve parantez içindeki kod atlanır. Aksi takdirde, isteğe bağlı değer açılır ve let sonra sabite atanır; bu, paketlenmemiş değerin kod bloğu içinde kullanılabilir olmasını sağlar.

İsteğe bağlı değerleri işlemenin başka bir yolu da ?? operatör. İsteğe bağlı değer eksikse bunun yerine varsayılan değer kullanılır.

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

Anahtarlar her türlü veriyi ve çok çeşitli karşılaştırma işlemlerini destekler; tamsayılar ve eşitlik testleriyle sınırlı değildirler.

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?

Bir modelin o kısmıyla eşleşen değeri bir sabite atamak için bir modelde let nasıl kullanılabileceğine dikkat edin.

Eşleşen switch durumu içindeki kodu çalıştırdıktan sonra program switch ifadesinden çıkar. Yürütme bir sonraki vakaya devam etmez, dolayısıyla her vakanın kodunun sonundaki anahtardan açıkça ayrılmaya gerek yoktur.

Her anahtar/değer çifti için kullanılacak bir ad çifti sağlayarak sözlükteki öğeler üzerinde yineleme yapmak için for - in kullanırsınız. Sözlükler sırasız bir koleksiyon olduğundan anahtarları ve değerleri rastgele bir sırayla yinelenir.

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
        }
    }
}
print(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.

Bir koşul değişene kadar bir kod bloğunu tekrarlamak için while kullanın. Döngünün koşulu bunun yerine döngünün sonunda olabilir ve döngünün en az bir kez çalıştırılmasını sağlar.

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

print(n)
128

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

print(m)
128

Bir dizini bir döngü içinde tutabilirsiniz; ya bir dizi dizin oluşturmak için ..< kullanarak ya da açık bir başlatma, koşul ve artış yazarak. Bu iki döngü aynı şeyi yapar:

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

print(total)
6

Üst değerini atlayan bir aralık oluşturmak için ..< kullanın ve her iki değeri de içeren bir aralık oluşturmak için ... kullanın.

İşlevler ve Kapanışlar

Bir işlevi bildirmek için func kullanın. Adını parantez içindeki bağımsız değişkenlerin listesiyle takip ederek bir işlevi çağırın. Parametre adlarını ve türlerini işlevin dönüş türünden ayırmak için -> kullanın.

func greet(name: String, day: String) -> String {
    return "Hello \(name), today is \(day)."
}
print(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.

Varsayılan olarak işlevler, parametre adlarını bağımsız değişkenleri için etiket olarak kullanır. Parametre adından önce özel bir bağımsız değişken etiketi yazın veya bağımsız değişken etiketi kullanmamak için _ yazın.

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

Bileşik bir değer oluşturmak için (örneğin, bir işlevden birden fazla değer döndürmek için) bir tanımlama grubu kullanın. Bir demetin öğelerine isimle veya numarayla başvurulabilir.

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

Fonksiyonlar iç içe yerleştirilebilir. İç içe geçmiş işlevler, dış işlevde bildirilen değişkenlere erişebilir. Uzun veya karmaşık bir işlevdeki kodu düzenlemek için iç içe geçmiş işlevleri kullanabilirsiniz.

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

Fonksiyonlar birinci sınıf tiptedir. Bu, bir fonksiyonun başka bir fonksiyonu değer olarak döndürebileceği anlamına gelir.

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

Bir fonksiyon başka bir fonksiyonu argümanlarından biri olarak alabilir.

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]
print(hasAnyMatches(list: numbers, condition: lessThanTen))
true

Fonksiyonlar aslında kapanışların özel bir durumudur: daha sonra çağrılabilecek kod blokları. Bir kapatmadaki kod, kapatma yürütüldüğünde farklı bir kapsamda olsa bile, kapatmanın oluşturulduğu kapsamda mevcut olan değişkenler ve işlevler gibi şeylere erişime sahiptir; bunun bir örneğini zaten iç içe geçmiş işlevlerde gördünüz. Kodu parantezlerle ( {} ) çevreleyerek isimsiz bir kapanış yazabilirsiniz. Bağımsız değişkenleri ve dönüş türünü gövdeden ayırmak için in kullanın.

let mappedNumbers = numbers.map({ (number: Int) -> Int in
    let result = 3 * number
    return result
})
print(mappedNumbers)
[60, 57, 21, 36]

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

Kapanışları daha kısa ve öz bir şekilde yazmak için çeşitli seçenekleriniz vardır. Bir temsilcinin geri çağrılması gibi bir kapanışın türü zaten biliniyorsa, parametrelerinin türünü, dönüş türünü veya her ikisini birden atlayabilirsiniz. Tek deyim kapanışları örtülü olarak tek deyimlerinin değerini döndürür.

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

Parametrelere ad yerine numaraya göre başvurabilirsiniz; bu yaklaşım özellikle çok kısa kapanışlarda kullanışlıdır. Bir işleve son argüman olarak iletilen kapatma, parantezlerin hemen ardından görünebilir. Bir işlevin tek argümanı kapanış olduğunda parantezleri tamamen atlayabilirsiniz.

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

Nesneler ve Sınıflar

Bir sınıf oluşturmak için class ve ardından sınıfın adını kullanın. Bir sınıftaki özellik bildirimi, bir sınıf bağlamında olması dışında, sabit veya değişken bildirimiyle aynı şekilde yazılır. Aynı şekilde yöntem ve işlev bildirimleri de aynı şekilde yazılır.

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.

Sınıf adından sonra parantez koyarak bir sınıfın örneğini oluşturun. Örneğin özelliklerine ve yöntemlerine erişmek için nokta sözdizimini kullanın.

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

Shape sınıfının bu sürümünde önemli bir şey eksik: bir örnek oluşturulduğunda sınıfı ayarlayacak bir başlatıcı. Bir tane oluşturmak için init kullanın.

class NamedShape {
    var numberOfSides: Int = 0
    var name: String

    init(name: String) {
        self.name = name
    }

    func simpleDescription() -> String {
        return "A shape with \(numberOfSides) sides."
    }
}

name özelliğini, başlatıcıya kadar name argümanından ayırmak için self nasıl kullanıldığına dikkat edin. Sınıfın bir örneğini oluşturduğunuzda, başlatıcıya yönelik argümanlar bir işlev çağrısı gibi iletilir. Her özelliğin, bildiriminde ( numberOfSides ile olduğu gibi) veya başlatıcıda ( name ile olduğu gibi) atanan bir değere ihtiyacı vardır.

Nesnenin konumu kaldırılmadan önce bir miktar temizlik yapmanız gerekiyorsa, bir başlatıcı oluşturucu oluşturmak için deinit kullanın.

Alt sınıflar, üst sınıf adlarını sınıf adlarından sonra iki nokta üst üste işaretiyle ayırarak içerir. Sınıfların herhangi bir standart kök sınıfı alt sınıfa almasına gerek yoktur, dolayısıyla gerektiğinde bir üst sınıfı dahil edebilir veya çıkartabilirsiniz.

Üst sınıfın uygulamasını geçersiz kılan bir alt sınıftaki yöntemler override ile işaretlenir; override olmadan bir yöntemin kazara geçersiz kılınması, derleyici tarafından bir hata olarak algılanır. Derleyici aynı zamanda üst sınıftaki herhangi bir yöntemi geçersiz kılmayan override özellikli yöntemleri de algılar.

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")
print(test.area())
print(test.simpleDescription())
27.040000000000003
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.

Saklanan basit özelliklere ek olarak, özelliklerin bir alıcısı ve ayarlayıcısı olabilir.

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

perimeter ayarlayıcısında, yeni değerin örtülü adı newValue . set sonra parantez içinde açık bir ad verebilirsiniz.

EquilateralTriangle sınıfının başlatıcısının üç farklı adıma sahip olduğuna dikkat edin:

  1. Alt sınıfın bildirdiği özelliklerin değerini ayarlama.

  2. Süper sınıfın başlatıcısının çağrılması.

  3. Üst sınıf tarafından tanımlanan özelliklerin değerini değiştirme. Yöntemleri, alıcıları veya ayarlayıcıları kullanan herhangi bir ek kurulum çalışması da bu noktada yapılabilir.

Özelliği hesaplamanız gerekmiyor ancak yine de yeni bir değer ayarlamadan önce ve sonra çalıştırılan kodu sağlamanız gerekiyorsa willSet ve didSet kullanın. Sağladığınız kod, bir başlatıcı dışında değer değiştiğinde çalıştırılır. Örneğin aşağıdaki sınıf, üçgeninin kenar uzunluğunun her zaman karenin kenar uzunluğuyla aynı olmasını sağlar.

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

İsteğe bağlı değerlerle çalışırken ? yazabilirsiniz ? yöntemler, özellikler ve abone olma gibi işlemlerden önce. Değer önce ? nil mı, sonrasındaki her şey ? göz ardı edilir ve ifadenin tamamının değeri nil . Aksi takdirde, isteğe bağlı değer açılır ve ? sarılmamış değere göre hareket eder. Her iki durumda da ifadenin tamamının değeri isteğe bağlı bir değerdir.

let optionalSquare: Square? = Square(sideLength: 2.5, name: "optional square")
print(optionalSquare?.sideLength)
Optional(2.5)

Numaralandırmalar ve Yapılar

Bir numaralandırma oluşturmak için enum kullanın. Sınıflar ve diğer tüm adlandırılmış türler gibi, numaralandırmalar da kendileriyle ilişkilendirilmiş yöntemlere sahip olabilir.

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.

Swift, varsayılan olarak ham değerleri sıfırdan başlayıp her seferinde birer birer artarak atar, ancak değerleri açıkça belirterek bu davranışı değiştirebilirsiniz. Yukarıdaki örnekte Ace'e açıkça 1 ham değeri verilmiştir ve geri kalan ham değerler sırayla atanmıştır. Ayrıca bir numaralandırmanın ham türü olarak dizeleri veya kayan noktalı sayıları da kullanabilirsiniz. Bir numaralandırma vakasının ham değerine erişmek için rawValue özelliğini kullanın.

Ham değerden bir numaralandırma örneği oluşturmak için init?(rawValue:) başlatıcısını kullanın. Ham değerle eşleşen numaralandırma durumunu veya eşleşen bir Rank yoksa nil değerini döndürür.

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

Bir numaralandırmanın durum değerleri, ham değerlerini yazmanın başka bir yolu değil, gerçek değerlerdir. Aslında anlamlı bir ham değerin olmadığı durumlarda bir değer sağlamanıza gerek yoktur.

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.

Yukarıda numaralandırmanın Hearts durumuna iki şekilde değinildiğine dikkat edin: hearts sabitine bir değer atarken, sabitin açık bir türü belirtilmediğinden Suit.Hearts numaralandırma durumu tam adıyla anılır. Anahtarın içinde, numaralandırma durumu kısaltılmış şekliyle anılır .Hearts Kalpler çünkü self değeri zaten bir takım elbise olarak bilinmektedir. Değerin türü zaten bilindiğinde kısaltılmış formu kullanabilirsiniz.

Bir numaralandırmanın ham değerleri varsa, bu değerler bildirimin bir parçası olarak belirlenir; bu, belirli bir numaralandırma durumunun her örneğinin her zaman aynı ham değere sahip olduğu anlamına gelir. Numaralandırma durumları için başka bir seçenek de durumla ilişkili değerlere sahip olmaktır; bu değerler örneği oluşturduğunuzda belirlenir ve bir numaralandırma durumunun her örneği için farklı olabilirler. İlişkili değerlerin, numaralandırma durumu örneğinin depolanan özellikleri gibi davrandığını düşünebilirsiniz.

Örneğin, bir sunucudan gün doğumu ve gün batımı saatlerinin istendiği durumu düşünün. Sunucu ya istenen bilgilerle yanıt verir ya da neyin yanlış gittiğinin açıklamasıyla yanıt verir.

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.

Değeri anahtar durumlarıyla eşleştirmenin bir parçası olarak, gün doğumu ve gün batımı zamanlarının ServerResponse değerinden nasıl çıkarıldığına dikkat edin.

Bir yapı oluşturmak için struct kullanın. Yapılar, yöntemler ve başlatıcılar da dahil olmak üzere sınıflarla aynı davranışların çoğunu destekler. Yapılar ve sınıflar arasındaki en önemli farklardan biri, yapıların kodunuzda aktarılırken her zaman kopyalanması, ancak sınıfların referans yoluyla aktarılmasıdır.

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.

Protokoller ve Uzantılar

Bir protokol bildirmek için protocol kullanın.

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

Sınıflar, numaralandırmalar ve yapıların tümü protokolleri benimseyebilir.

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()
print(b.adjust())
print(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?

Yapıyı değiştiren bir yöntemi işaretlemek için SimpleStructure bildiriminde mutating anahtar sözcüğünün kullanıldığına dikkat edin. SimpleClass bildirimi, mutasyona uğrayan olarak işaretlenmiş yöntemlere ihtiyaç duymaz çünkü bir sınıftaki yöntemler her zaman sınıfı değiştirebilir.

Yeni yöntemler ve hesaplanan özellikler gibi mevcut bir türe işlevsellik eklemek için extension kullanın. Başka bir yerde bildirilen bir türe, hatta bir kitaplıktan veya çerçeveden içe aktardığınız bir türe protokol uyumluluğu eklemek için bir uzantı kullanabilirsiniz.

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

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

Tıpkı diğer adlandırılmış türler gibi bir protokol adı kullanabilirsiniz; örneğin, farklı türlere sahip ancak tümü tek bir protokole uyan nesnelerden oluşan bir koleksiyon oluşturmak için. Türü protokol türü olan değerlerle çalıştığınızda protokol tanımının dışındaki yöntemler kullanılamaz.

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

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

protocolValue değişkeninin çalışma zamanı türü SimpleClass olsa da, derleyici onu verilen ExampleProtocol türü olarak ele alır. Bu, sınıfın protokol uyumluluğunun yanı sıra uyguladığı yöntemlere veya özelliklere yanlışlıkla erişemeyeceğiniz anlamına gelir.

Hata İşleme

Error protokolünü benimseyen herhangi bir türü kullanarak hataları temsil edersiniz.

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

Bir hata atmak için throw , hata oluşturabilecek bir işlevi işaretlemek için throws kullanın. Bir fonksiyona hata atarsanız, fonksiyon hemen geri döner ve fonksiyonu çağıran kod hatayı işler.

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

Hataları işlemenin birkaç yolu vardır. Bunun bir yolu do-catch kullanmaktır. do bloğunun içinde hata verebilecek kodun önüne try yazarak işaretlersiniz. catch bloğunun içinde, farklı bir ad vermediğiniz sürece hataya otomatik olarak ad error verilir.

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.

Belirli hataları işleyen birden fazla catch bloğu sağlayabilirsiniz. Tıpkı bir anahtardaki büyük/ case sonra yaptığınız gibi, catch sonra da bir desen yazarsınız.

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?

Hataları ele almanın başka bir yolu da try? kullanmaktır. Sonucu isteğe bağlı olarak dönüştürmek için. İşlev bir hata atarsa, söz konusu hata atılır ve sonuç nil olur. Aksi takdirde sonuç, işlevin döndürdüğü değeri içeren isteğe bağlı bir sonuç olur.

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

İşlev geri dönmeden hemen önce, işlevdeki diğer tüm kodlardan sonra yürütülen bir kod bloğunu yazmak için defer kullanın. Kod, fonksiyonun hata atıp atmadığına bakılmaksızın yürütülür. Farklı zamanlarda çalıştırılmaları gerekse bile, kurulum ve temizleme kodlarını yan yana yazmak için defer kullanabilirsiniz.

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
}
print(fridgeContains("banana"))
print(fridgeIsOpen)
false
false

Jenerikler

Genel bir işlev veya tür oluşturmak için açılı parantezlerin içine bir ad yazın.

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

İşlev ve yöntemlerin yanı sıra sınıflar, numaralandırmalar ve yapıların genel formlarını oluşturabilirsiniz.

// 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)

Gereksinimlerin bir listesini belirtmek için tür adından sonra where kullanın (örneğin, türün bir protokolü uygulamasını, iki türün aynı olmasını gerektirmek veya bir sınıfın belirli bir üst sınıfa sahip olmasını gerektirmek için).

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
}
print(anyCommonElements([1, 2, 3], [3]))
true

<T: Equatable> yazmak <T> ... where T: Equatable .