Swift Programlama: Saklanan mülkte alıcı / ayarlayıcı


102

Swift'de depolanan özellik ayarlayıcısının üzerine nasıl yazabilirim?

Obj-C'de, onun ayarlayıcısının üzerine yazabilirim, ancak Swift, depolanan mülk için kullanılan alıcı / ayarlayıcılardan memnun görünmüyor.

Adında Cardbir özelliği olan bir sınıfım olduğunu varsayalım rank. İstemcinin ona geçersiz bir değer vermesini istemiyorum, bu nedenle amaç-C'de setRankek kontrol yapmak için üzerine yazabilirim . Ancak willSetSwift'de yardımcı görünmüyor çünkü newValuesabittir ve atamanın bir anlamı yoktur rankçünkü ayarlayıcı bir döngü içinde çağrılacaktır.


Bunu yapmanın bir yolunu buldunuz mu? Bu tür bir işleve ihtiyacım var ...
— Mihai Fratu

Buldum.
— Cevabıma bak

Ya didGet veya analog?
— fnc12

Yanıtlar:


107

Tamam. Swift buldum üzerinde Elmalar belgelerine aracılığıyla Okuma bu :

Kendi didSet gözlemcisi içindeki bir özelliğe bir değer atarsanız, atadığınız yeni değer, az önce ayarlanmış olanın yerini alacaktır.

Yani tek yapmanız gereken şudur:

var rank: Int = 0 {
    didSet {
        // Say 1000 is not good for you and 999 is the maximum you want to be stored there
        if rank >= 1000  {
            rank = 999
        }
    }
}

Ya didGet veya analog?
— fnc12

Sorunuzu anladığımdan emin değilim. Daha açık olur musun lütfen?
— Mihai Fratu

Almadan önce biraz kod çalıştırmam gerekiyor. Bunu obj-c'de yapabildim ama bunu Swift'de nasıl yapacağımı göremiyorum. Gördüğüm tek şey iki özelliği kullanmak: biri genel, diğeri özel, genel kodumu çağırıyor ve özel mülkün değerini döndürüyor. Bu yüzden didGet'i sordum
— fnc12

Yalnızca hesaplanan bir mülk için alıcıya sahip olabilirsiniz. Örneğinvar rankTimesTwo: Int { get { return rank * 2 } }
— Mihai Fratu

2
Tıkır tıkır çalışıyor! Özelliği init () içinde ayarlarken çağrılmayacağına dikkat edin
— Christoph

35

Depolanan bir mülk için get/ değerini geçersiz kılamazsınız, setancak mülk gözlemcilerini willSet/ kullanabilirsiniz didSet:

var totalSteps: Int = 0 {
    willSet(newTotalSteps) {
        println("About to set totalSteps to \(newTotalSteps)")
    }
    didSet {
        if totalSteps > oldValue  {
            println("Added \(totalSteps - oldValue) steps")
        }
    }
}

Varsayılan parametre adları newValuefor willSetve oldValuefor şeklindedir didSetveya bunları kendi adınızı olarak verebilirsiniz willSet(newTotalSteps).


Bu çalışıyor. Ama sorunumu çözmüyor, belki de asıl sorumda yeterince net değildim.
— bohanl

Adında Cardbir özelliği olan bir sınıfım olduğunu varsayalım rank. Müşterinin ona herhangi bir değer vermesini istemiyorum, bu nedenle, amaç-C'de, üzerine yazabilirim, setRankböylece ek kontrol gerçekleştirir. Ancak willSetSwift'de yardımcı görünmüyor çünkü newValuesabittir ve atamanın bir anlamı yoktur rankçünkü ayarlayıcı bir döngü içinde çağrılacaktır.
— bohanl

2
Ne demek istediğinizden tam olarak emin değilim, ancak ayarlandıktan sonra didSetkontrol etmek için kullanamazdınız rankve doğrulama başarısız olursa, başka bir şeye sıfırlayın, örneğin oldValue?
— Joseph Mark

9

get ve set hesaplanan özellikler içindir (herhangi bir destek depoları yoktur). (Kanımca, 'var' anahtar kelimesi burada kafa karıştırıcıdır)

  • willSet ve didSet bir örnek değişkeni için çağrılır (herhangi bir değişikliği geçersiz kılmak için didSet kullanın)
  • set ve get tamamen hesaplanmış özellikler içindir

9

Özelliğin değerinin geçici olarak yanlış olması sorunu olan didSet'i kullanmak istemiyorsanız, bir hesaplanan özelliği etrafına sarmalısınız.

private var _foo:Int = 0
var foo:Int {
    get {
        return _foo
    }
    set {
        if(newValue > 999) {
            _foo = 999
        } else {
            _foo = newValue
        }
    }
}

Veya:

private var _foo:Int = 0
var foo:Int {
    get {
        return _foo
    }
    set {
        guard newValue <= 999 else {
            _foo = 999
            return
        }
        _foo = newValue
    }
}

İki değişken kullanmak mantıklı değil.
— Piyush

1
Bu sadece bir özellik (değişken) kullanıyor: foosadece hesaplanmış bir ifadesidir _foo, "var" anahtar kelimesinin sizi aldatmasına izin vermeyin! Bu, özel ad alanından erişilebilen iki giriş olduğu anlamına gelir, ancak bu, korumalı / genel ile hiçbir ilgisi yoktur foove her zaman geçerli değerini korur . Bu, esasen "görünüm" kalıbıdır. Bir süre geçersiz kalmasına ek olarak, yeniden yazma ile karşılaştığınız sorun didSet, didSetişleyiciye içeriden yeniden girdiğiniz için sonsuz bir döngü için önemli bir potansiyel olmasıdır didSet.
— Jim Driscoll

-8

Basitleştirilmiş Örnek:

class Shape {
    var sideLength: Double {
    get {
        return self.sideLength
    }
    set {
        // Implement the setter here.
        self.sideLength = newValue
    }
    }
}

Tam örnek

Check out perimeterbu örnekte.

Alıntı: Apple Inc. "The Swift Programming Language." iBooks. https://itun.es/us/jEUH0.l

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 triagle with sides of length \(sideLength)."
    }
}
var triangle = EquilateralTriangle(sideLength: 3.1, name: "a triangle")
triangle.perimeter
triangle.perimeter = 9.9
triangle.sideLength”

3
bu durumda, perimeteryine de hesaplanan bir özelliktir. Hesaplanan bir özellik eklemeden sideLength üzerine nasıl yazabilirim?
— bohanl

@bohanl getve kullanarak basitleştirilmiş bir örnek ekledimset
— Mike Rapadas

6
"Tam örneğiniz" depolanmış bir mülkü değil, hesaplanan bir mülkü gösterir ve "basitleştirilmiş örneğiniz" çalışmaz.
— Caleb

Düzeltilmiş durumdayım. Sanki Objective-C'deki @ özelliği (otomatik sentezlenmiş alıcılar + ayarlayıcılar) soyutlaması Swift'de soyutlanmış gibi. İroni ...
— Mike Rapadas

6
Siz "basitleştirilmiş örnek", kendi başına bir alıcı içinde bir alıcı çağırmaktır. Inf döngüsü ... çökme.
— jakenberg
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.