스위프트에서 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 :value
의 customUserControl
(여기서: 관련 대여함범있는개체에위는서기의수자리여▁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
'source' 카테고리의 다른 글
ASP에서 divs를 위한 코드 뒤에 있는 파일에서 CSS 스타일을 어떻게 수정합니까?NET? (0) | 2023.04.27 |
---|---|
ASP.NET 번들최소화 비활성화 방법 (0) | 2023.04.27 |
WPF의 양호한 수치 UpDown 등가물? (0) | 2023.04.27 |
PUT의 Azure BLOB 스토리지 문서에서 "404 리소스를 찾을 수 없음" (0) | 2023.04.27 |
WPF ListView의 헤더를 숨기려면 어떻게 해야 합니까? (0) | 2023.04.27 |