Swift에서 클로저를 사용하여 클래스 간 데이터 결합
간단한 상황부터 시작하겠습니다. 우리에게는 부모와 자녀가 있습니다. 부모가 자녀의 성적을 받고 싶지 않다면 그냥 참조할 수 있습니다. 하지만 아이가 새 마크를 얻자 마자 새로운 마크를 알고 싶어하는 부모가 있다면 어떨까요?
class Parent {
var name: String
var child: Child?
init(_ name: String, child: Child? = nil) {
self.name = name
self.child = child
}
func getChildMarks() -> [Int]? {
return child?.marks
}
}
class Child {
var name: String
var marks: [Int]
init(_ name: String, marks: [Int] = [], parent: Parent? = nil) {
self.name = name
self.marks = marks
}
}
let child = Child("David", marks: [5, 5, 4])
let parent = Parent("Ms. Red", child: child)
print(parent.getChildMarks())
데이터를 바인딩해야 합니다. 우리 아이가 책임감 있는 아이이고 부모 자신에게 알리는 데 아무런 지장이 없다고 상상해 봅시다. 그러나 자식은 부모 개체에 대한 참조를 보유하지 않습니다. 따라서 가장 간단한 방법은 자식에게 부모에 대한 참조를 제공하는 것입니다. 그걸하자.
class Child {
var name: String
var marks: [Int]
weak var parent: Parent?
init(_ name: String, marks: [Int] = [], parent: Parent? = nil) {
self.name = name
self.marks = marks
}
}
let child = Child("David", marks: [5, 5, 4])
let parent = Parent("Ms. Red", child: child)
child.parent = parent
이제 자식은 부모에 대한 참조를 보유합니다. 부모 클래스에 대한 참조는 약해야 한다는 점에 주의하십시오. 그러면 상위 개체가 할당 해제될 경우 참조 주기가 방지됩니다. 이제 부모의 public 메서드를 만들 수 있습니다. 자식은 새 표시를 얻을 때마다 이 메서드를 호출합니다.
func childGotNewMark(_ mark: Int) {
print("Child got \(mark).")
}
그리고 자식이 새로운 마크를 얻을 때마다 마크 목록에 추가하고 부모 메서드를 호출하여 부모에게 알립니다.
func getMark(_ mark: Int) {
marks.append(mark)
parent?.childGotNewMark(mark)
}
이 방법에는 몇 가지 단점이 있습니다. childGotNewMark 메서드가 없는 부모에게 자식을 첨부하면 어떻게 될까요? 분명히 오류가 발생합니다.
error: value of type ‘Parent’ has no member ‘childGotNewMark’
이 문제를 해결하려면 어떻게 해야 합니까?
가장 일반적인 방법은 부모 메서드를 자식에게 변수로 제공하는 것입니다. 선택적 변수이므로 부모가 설정하거나 설정하지 않을 수 있습니다. 그래서 이 아이는 다른 부모들과 함께 일할 수 있을 것입니다. 이 솔루션을 살펴보겠습니다. 이 코드는 플레이그라운드에서 실행할 수 있습니다. 자세한 설명은 다음에 이어집니다.
class Parent {
var name: String
var child: Child?
init(_ name: String, child: Child? = nil) {
self.name = name
self.child = child
guard let child = child else {
return
}
child.onNewMarkReceived = { [weak self] mark in
self?.childGotNewMark(mark)
}
}
func getChildMarks() -> [Int]? {
return child?.marks
}
func childGotNewMark(_ mark: Int) {
print("Child got \(mark).")
}
}
class Child {
var name: String
var marks: [Int]
weak var parent: Parent?
var onNewMarkReceived: ((Int) -> Void)?
init(_ name: String, marks: [Int] = [], parent: Parent? = nil) {
self.name = name
self.marks = marks
}
func getMark(_ mark: Int) {
marks.append(mark)
onNewMarkReceived?(mark)
}
}
let child = Child("David", marks: [5, 5, 4])
let parent = Parent("Ms. Red", child: child)
child.parent = parent
child.getMark(5)
먼저 자식 클래스에 변수를 정의합니다.
var onNewMarkReceived: ((Int) -> Void)?
그게 무슨 뜻이야? 선택적 메서드인 onNewMarkReceived 변수를 만들었습니다. 입력 시 정수를 얻고 void를 반환합니다.
다음으로 아이가
parent?.childGotNewMark(mark)
대신 마크를 얻었을 때 이 메소드를 호출할 것입니다.onNewMarkReceived?(mark)
메서드 이름 뒤의 물음표는 변수의 메서드가 정의되지 않은 경우 아무 작업도 수행하지 않음을 의미합니다.
다음 단계에서는 부모의 초기화 코드에서 변수를 설정합니다. (정수 값으로) 표시를 취하고 아무 것도 반환하지 않는 클로저입니다.
init(_ name: String, child: Child? = nil) {
self.name = name
self.child = child
guard let child = child else {
return
}
child.onNewMarkReceived = { mark in
print("Child got \(mark)")
}
}
그러나 이 표시를 인쇄하는 대신 부모의 일부 메서드에 전달하려면 어떻게 해야 할까요? 이전에 생성한
func childGotNewMark(_ mark: Int)
를 호출해 보겠습니다.child.onNewMarkReceived = { [weak self] mark in
self?.childGotNewMark(mark)
}
여기서 무엇을 할까요? 첫째, 우리는 우리 자신을 연약한 것으로 설정합니다. 즉, 상위 개체에 대한 참조가 약합니다. 따라서 부모 객체가 메모리 할당을 해제하려고 하면 클로저가 보유하는 참조에 대해 걱정하지 않고 할 수 있습니다.
다음으로 부모 내부의 메서드를 참조합니다. 클로저에는 self가 필요합니다. 클로저가 self라고 불리는 순간 이미 할당 해제될 수 있으므로 self 뒤에 물음표가 필요합니다.
그래서 우리는 대리자 패턴을 사용하지 않고 자식 클래스에서 부모로 데이터 바인딩을 만들었습니다. 그것은 우리가 onNewMarkReceived 메소드를 정의하는 것을 자제할 수 있는 다른 부모들과 함께 일할 수 있게 해줍니다. 또한 부모가 할당 해제되는 상황에 대해 관대합니다.
Reference
이 문제에 관하여(Swift에서 클로저를 사용하여 클래스 간 데이터 결합), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/sbotichelli/binding-data-between-classes-with-closures-in-swift-1mfm텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)