source

스위프트에서 willSet과 doSet의 목적은 무엇입니까?

lovecheck 2023. 4. 27. 22:32
반응형

스위프트에서 willSet과 doSet의 목적은 무엇입니까?

Swift의 속성 선언 구문은 C#과 매우 유사합니다.

var foo: Int {
    get { return getFoo() }
    set { setFoo(newValue) }
}

하지만, 그것은 또한 가지고 있습니다.willSet그리고.didSet 불려요.이것들은 각각 세터가 호출되기 전과 후에 호출됩니다.세터 안에 동일한 코드가 있을 수 있다는 것을 고려하면, 그들의 목적은 무엇입니까?

중요한 것은 속성이 방금 변경되었음을 다른 개체에 알리기 위해 자동 저장 및 일부 동작이 있는 속성이 필요한 경우가 있다는 것입니다.당신이 가진 모든 것이get/set값을 유지하려면 다른 필드가 필요합니다.와 함께willSet그리고.didSet다른 필드 없이 값이 수정될 때 작업을 수행할 수 있습니다.예를 들어, 이 예에서는 다음과 같습니다.

class Foo {
    var myProperty: Int = 0 {
        didSet {
            print("The value of myProperty changed from \(oldValue) to \(myProperty)")
        }
    }
}

myProperty수정할 때마다 이전 값과 새 값을 인쇄합니다.단지 게터와 세터만 있으면, 나는 대신 이것이 필요할 것입니다.

class Foo {
    var myPropertyValue: Int = 0
    var myProperty: Int {
        get { return myPropertyValue }
        set {
            print("The value of myProperty changed from \(myPropertyValue) to \(newValue)")
            myPropertyValue = newValue
        }
    }
}

그렇게willSet그리고.didSet필드 리스트에서 노이즈가 적은 두 라인의 경제를 나타냅니다.

set 및 get는 계산된 속성에 대한 것으로 알고 있습니다(저장된 속성에서 백업하지 않음).

이름 지정 규칙이 변경되었음을 염두에 두고 목표-C에서 온 경우.Swift에서 iVar 또는 인스턴스 변수는 저장된 속성으로 명명됩니다.

예 1(읽기 전용 속성) - 경고 포함:

var test : Int {
    get {
        return test
    }
}

이 경우 재귀 함수 호출(게터 호출 자체)이 발생하므로 경고가 발생합니다.이 경우 경고는 "자체 getter 내에서 'test'를 수정하려고 합니다."입니다.

예 2.조건부 읽기/쓰기 - 경고 포함

var test : Int {
    get {
        return test
    }
    set (aNewValue) {
        //I've contrived some condition on which this property can be set
        //(prevents same value being set)
        if (aNewValue != test) {
            test = aNewValue
        }
    }
}

유사한 문제 - 재귀적으로 세터를 호출하기 때문에 이 작업을 수행할 수 없습니다.또한 이 코드는 초기화할 저장된 속성이 없으므로 초기화자가 없다고 불평하지 않습니다.

예 3. 계산된 속성 읽기/쓰기 - 백업 저장소 포함

Here is a pattern that allows conditional setting of an actual stored property
//True model data
var _test : Int = 0

var test : Int {
    get {
        return _test
    }
    set (aNewValue) {
        //I've contrived some condition on which this property can be set
        if (aNewValue != test) {
            _test = aNewValue
        }
    }
}

참고 실제 데이터는 _test라고 합니다(데이터 또는 데이터 조합일 수 있지만). _test는 실제로 인스턴스 변수이기 때문에 초기 값을 제공해야 합니다(또는 init 메서드를 사용해야 함).

예 4.의지 및 실행 세트 사용

//True model data
var _test : Int = 0 {

    //First this
    willSet {
        println("Old value is \(_test), new value is \(newValue)")
    }
    
    //value is set

    //Finaly this
    didSet {
        println("Old value is \(oldValue), new value is \(_test)")
    }
}

var test : Int {
    get {
        return _test
    }
    set (aNewValue) {
        //I've contrived some condition on which this property can be set
        if (aNewValue != test) {
            _test = aNewValue
        }
    }
}

여기서는 실제 저장된 속성의 변경을 가로채는 willSet 및 didSet을 볼 수 있습니다.알림 전송, 동기화 등에 유용합니다.(아래 예 참조)

예 5.콘크리트 예제 - View 컨트롤러 컨테이너

//Underlying instance variable (would ideally be private)
var _childVC : UIViewController? {
    willSet {
        //REMOVE OLD VC
        println("Property will set")
        if (_childVC != nil) {
            _childVC!.willMoveToParentViewController(nil)
            self.setOverrideTraitCollection(nil, forChildViewController: _childVC)
            _childVC!.view.removeFromSuperview()
            _childVC!.removeFromParentViewController()
        }
        if (newValue) {
            self.addChildViewController(newValue)
        }
        
    }

    //I can't see a way to 'stop' the value being set to the same controller - hence the computed property

    didSet {
        //ADD NEW VC
        println("Property did set")
        if (_childVC) {
//                var views  = NSDictionaryOfVariableBindings(self.view)    .. NOT YET SUPPORTED (NSDictionary bridging not yet available)
            
            //Add subviews + constraints
            _childVC!.view.setTranslatesAutoresizingMaskIntoConstraints(false)       //For now - until I add my own constraints
            self.view.addSubview(_childVC!.view)
            let views = ["view" : _childVC!.view] as NSMutableDictionary
            let layoutOpts = NSLayoutFormatOptions(0)
            let lc1 : AnyObject[] = NSLayoutConstraint.constraintsWithVisualFormat("|[view]|",  options: layoutOpts, metrics: NSDictionary(), views: views)
            let lc2 : AnyObject[] = NSLayoutConstraint.constraintsWithVisualFormat("V:|[view]|", options: layoutOpts, metrics: NSDictionary(), views: views)
            self.view.addConstraints(lc1)
            self.view.addConstraints(lc2)
            
            //Forward messages to child
            _childVC!.didMoveToParentViewController(self)
        }
    }
}


//Computed property - this is the property that must be used to prevent setting the same value twice
//unless there is another way of doing this?
var childVC : UIViewController? {
    get {
        return _childVC
    }
    set(suggestedVC) {
        if (suggestedVC != _childVC) {
            _childVC = suggestedVC
        }
    }
}

계산된 속성과 저장된 속성을 모두 사용합니다.계산된 속성을 사용하여 동일한 값을 두 번 설정하지 않도록 했습니다(나쁜 일이 발생하지 않도록!);willSet 및 didSet을 사용하여 알림을 ViewController로 전달했습니다(UIViewController 설명서 및 viewController 컨테이너에 대한 정보 참조).

혹시 제가 실수한 곳이 있으면 수정해주세요!

은 또한 있다니습수도를 할 수 .didSet변수를 다른 값으로 설정합니다.이렇게 하면 속성 안내서에 명시된 대로 관찰자가 다시 호출되지 않습니다.예를 들어 다음과 같이 값을 제한하려는 경우 유용합니다.

let minValue = 1

var value = 1 {
    didSet {
        if value < minValue {
            value = minValue
        }
    }
}

value = -10 // value is minValue now.

이를 Property Observer라고 합니다.

자산 관찰자는 자산 가치의 변화를 관찰하고 대응합니다.새 값이 속성의 현재 값과 동일하더라도 속성 값이 설정될 때마다 속성 감시자가 호출됩니다.

발췌: Apple Inc."스위프트 프로그래밍 언어" 아이북스.https://itun.es/ca/jEUH0.l

UI 요소로 데이터 바인딩하거나 속성 변경, 동기화 프로세스 트리거, 백그라운드 처리 등의 부작용을 유발하는 등 기존에 KBO로 수행하던 작업을 허용하기 위한 것이라고 생각합니다.

메모

willSet그리고.didSet이 설정되어 .

잘 작성된 기존의 많은 답변들이 질문을 잘 다루지만, 제가 다룰 가치가 있다고 믿는 추가 사항을 좀 더 자세히 언급하겠습니다.


willSet그리고.didSet속성 관찰자를 사용하여 대리자를 호출할 수 있습니다. 예를 들어, 사용자 상호 작용에 의해서만 업데이트되는 클래스 속성에 대해서는 개체 초기화 시 대리자를 호출하지 않을 수 있습니다.

승인된 답변에 대해 Klaas가 투표한 의견을 인용하겠습니다.

willSet 및 didSet 관찰자는 속성을 처음 초기화할 때 호출되지 않습니다.속성 값이 초기화 컨텍스트를 벗어나 설정된 경우에만 호출됩니다.

이것은 예를 들어, 그것이 의미하는 것처럼 꽤 깔끔합니다.didSet속성은 사용자 지정 클래스에 대한 대리자 콜백 및 함수를 위한 시작 지점의 좋은 선택입니다.

지정 개체에 . 키 속성은 " " " " " " " " " " " 입니다.value 등급 관리에서의 의 됩니다.UIView:

// CustomUserControl.swift
protocol CustomUserControlDelegate {
    func didChangeValue(value: Int)
    // func didChangeValue(newValue: Int, oldValue: Int)
    // func didChangeValue(customUserControl: CustomUserControl)
    // ... other more sophisticated delegate functions
}

class CustomUserControl: UIView {

    // Properties
    // ...
    private var value = 0 {
        didSet {
            // Possibly do something ...

            // Call delegate.
            delegate?.didChangeValue(value)
            // delegate?.didChangeValue(value, oldValue: oldValue)
            // delegate?.didChangeValue(self)
        }
    }

    var delegate: CustomUserControlDelegate?

    // Initialization
    required init?(...) { 
        // Initialise something ...

        // E.g. 'value = 1' would not call didSet at this point
    }

    // ... some methods/actions associated with your user control.
}

뷰 대리자 함수를 의 주요 사항을 할 수 .CustomViewController당신이 고유한 대리인 기능을 사용하는 것과 매우 유사합니다.UITextFieldDelegate위해서UITextField 객체):textFieldDidEndEditing(...)).

에서는 간한예의경우, 다위콜사용니합을백의 대리 합니다.didSet 속성의value 중 업데이트를 :

// ViewController.swift
Import UIKit
// ...

class ViewController: UIViewController, CustomUserControlDelegate {

    // Properties
    // ...
    @IBOutlet weak var customUserControl: CustomUserControl!

    override func viewDidLoad() {
        super.viewDidLoad()
        // ...

        // Custom user control, handle through delegate callbacks.
        customUserControl = self
    }

    // ...

    // CustomUserControlDelegate
    func didChangeValue(value: Int) {
        // do some stuff with 'value' ...
    }

    // func didChangeValue(newValue: Int, oldValue: Int) {
        // do some stuff with new as well as old 'value' ...
        // custom transitions? :)
    //}

    //func didChangeValue(customUserControl: CustomUserControl) {
    //    // Do more advanced stuff ...
    //}
}

자, 그.value일반적으로 이 화 었 일 되 상 서 업 는 에 하 주 않 하 십 의 록 시 도 지 오 트 이 데 황 러 한 지 으 만 로 적 반 ▁property ▁the ▁has ▁not ▁careful ▁be ulated ▁in :valuecustomUserControl(여기서: 관련 대여함범있는개체에위는서기의수자리여▁in▁object▁(:(개체는here:있서▁the▁function기didChangeValue()되지 않으면 재귀가 가 표시되지 않으면 무한 재귀가 발생합니다.

willSet 및 didSet은 속성에 새 값이 할당될 때마다 속성에 대한 관찰자를 설정합니다.새 값이 현재 값과 동일한 경우에도 마찬가지입니다.

그리고 참고로willSet는 매개 이와 할 수 매개 변수 이름이 필요합니다.didSet하지 않다.

속성 값이 업데이트된 후에 didSet 관찰자가 호출됩니다.이전 값과 비교됩니다.총 단계 수가 증가한 경우 새 단계를 수행한 횟수를 나타내는 메시지가 인쇄됩니다.didSet 관찰자는 이전 값에 대한 사용자 지정 매개 변수 이름을 제공하지 않으며 대신 oldValue의 기본 이름이 사용됩니다.

게터와 세터는 때때로 너무 무거워서 적절한 값 변화를 관찰할 수 없습니다.보통 이것은 추가적인 임시 변수 처리와 추가적인 점검이 필요하며, 수백 개의 게터와 세터를 쓴다면 그러한 작은 노동도 피하고 싶을 것입니다.이 물건들은 상황을 위한 것입니다.

당만기의수서업에신본,▁in),서.willSet그리고.didSet당신이 대신에 접근하는 계산된 속성(즉, get-methods 및 set-methods)을 정의할 수 있기 때문에 상당히 중복적입니다._propertyVariable원하는 사전사후 처리를 수행합니다.

그러나 속성이 이미 정의된 클래스를 재정의하는 경우willSet그리고.didSet유용하고 중복되지 않습니다!

한가지는didSet아웃렛을 사용하여 추가 구성을 추가할 때 유용합니다.

@IBOutlet weak var loginOrSignupButton: UIButton! {
  didSet {
        let title = NSLocalizedString("signup_required_button")
        loginOrSignupButton.setTitle(title, for: .normal)
        loginOrSignupButton.setTitle(title, for: .highlighted)
  }

나는 C#을 모르지만, 약간의 추측으로 나는 무엇을 이해한다고 생각합니다.

foo : int {
    get { return getFoo(); }
    set { setFoo(newValue); }
}

스위프트에서 은 그니다입니다. 스위프트에서 가지고 있는 것과 매우 비슷해 보이지만 같지는 않습니다. 스위프트에서 당신은 가지고 있지 않습니다.getFoo그리고.setFoo이는 귀사의 가치에 맞는 기본 스토리지가 없다는 것을 의미합니다.

Swift는 속성을 저장하고 계산했습니다.

에는 계된속다같습다가 .get 그고아마도를 가질 도 있습니다.set(쓰기 가능한 경우).그러나 실제로 데이터를 저장해야 하는 경우 getter와 setter의 코드는 다른 속성에서 수행해야 합니다.백업 저장소가 없습니다.

반면에 저장된 속성에는 백업 저장소가 있습니다.하지만 그것은 가지고 있지 않습니다.get그리고.set에 대에그것은신그가 있습니다.willSet그리고.didSet변수 변화를 관찰하고 부작용을 유발하거나 저장된 값을 수정하는 데 사용할 수 있습니다.당신은 가지고 있지 않습니다.willSet그리고.didSet속성의 . 된 속성의 에는 산된속성경우, 그계속경코사드우용수를않다습니필있요지하때할문에기성계의의산된리고▁in▁code▁for▁for▁the다니습▁use않▁proper▁because▁themties▁canties,▁proper▁you▁do▁computed▁computed▁and▁need의 코드를 사용할 수 있기 때문입니다.set변경을 제어합니다.

언급URL : https://stackoverflow.com/questions/24006234/what-is-the-purpose-of-willset-and-didset-in-swift

반응형