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.