ㄷㅣㅆㅣ's Amusement

[swift] getter/setter, subscript, property wrapper에서 get/set의 상이한 동작 본문

Programming/iOS

[swift] getter/setter, subscript, property wrapper에서 get/set의 상이한 동작

ㄷㅣㅆㅣ 2020. 6. 18. 15:57

[swift] getter/setter, subscript, property wrapper에서 get/set의 상이한 동작



개발하다 보면 "당연히 이러하겠지"라고 생각했다가 낭패를 보는 경우가있다.

오늘도 낭패를 봤기 때문에 하나씩 정리해 나가기로 하였다.


- getter/setter, subscript, property wrapper에서의 get/set.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
1. get/set
struct Getset {
    private var _value = 0
    var value: Int {
        get {
            print("get")
            return _value
        }
        
        set {
            print("set")
            _value = newValue
        }
    }
}
var getset = Getset()
getset.value = 10
 
// ----------
// set
cs

당연히도 위의 코드의 결과는 set한번 찍히는 것이 전부다.


그런데 다음의 코드를 보자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
struct Getset {
    private var _value = [StringString]()
    var value: [StringString] {
        get {
            print("get")
            return _value
        }
        
        set {
            print("set")
            _value = newValue
        }
    }
}
var getset = Getset()
getset.value["dog"= "Marc"
 
// ----------
// get
// set
cs

이 코드는 get이 먼저 출력된 다음 set이 출력된다.

왜일까????


일단 접어두고, Property Wrapper로 Atomic을 다음과 같이 만들어보자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
@propertyWrapper
struct Atomic<Value> {
    private var value: Value
    private let queue = DispatchQueue(label: "atomic_queue")
 
    init(wrappedValue value: Value) {
        self.value = value
    }
 
    var wrappedValue: Value {
      get { return load() }
      set { store(value: newValue) }
    }
 
    func load() -> Value {
        return queue.sync { () -> Value in
            print("get")
            return value
        }
    }
 
    mutating func store(value: Value) {
        queue.sync {
            print("set")
            self.value = value
        }
    }
}
cs

그리고 Dictionary와 Int 에 적용해보면, getter/setter와 마찬가지로 dictionary는 get,set을 연달아 출력하고, Int는 set만이 출력된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class TestClass {
    @Atomic var animals = [StringString]()
    @Atomic var count = 0
    
    func test() {
        animals["dog"= "Marc"
        count = 10
    }
}
var testClass = TestClass()
testClass.test()
 
// ----------
// get
// set
// set
cs

작성된 @Atomic이 type에 영향을 받는다.

그런데 사실이러한 상황은 이미 인지하고 있었고 Atomic사용에 대한 회의감을 느끼고 있었기에 이것은 오늘의 낭패가 아니다.

놀라운 일은 이 다음부터다.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
struct Animals {
    private let queue = DispatchQueue(label: "animal_queue")
    private var animals = [StringString]()
    subscript(kind: String-> String? {
        get {
            print("get")
            return queue.sync {
                animals[kind]
            }
        }
        set {
            print("set")
            queue.sync {
                animals[kind] = newValue
            }
        }
    }
}
var animals = Animals()
animals["dog"= "marc"
 
// ----------
// set
cs

위의 코드에서는 set만이 출력된다.


형태가 같다고해서 동작이 같지는 않다

1 Comments
댓글쓰기 폼