Swift - 프로토콜 확장 - 속성 기본값
다음 프로토콜이 있다고 가정해 보겠습니다.
protocol Identifiable {
var id: Int {get}
var name: String {get}
}
그리고 다음 구조체가 있습니다.
struct A: Identifiable {
var id: Int
var name: String
}
struct B: Identifiable {
var id: Int
var name: String
}
보시다시피 구조체 A와 구조체 B의 식별 가능한 프로토콜을 '준수'해야 했습니다. 하지만 이 프로토콜을 준수해야 하는 구조체가 N개 더 있다고 상상해 보세요... '복사/붙여넣기'를 하고 싶지 않습니다. ' 적합성(var id: Int, var name: String)
그래서 프로토콜 확장을 만듭니다 .
extension Identifiable {
var id: Int {
return 0
}
var name: String {
return "default"
}
}
이제 이 확장을 사용하여 두 속성을 모두 구현하지 않고도 Identifiable 프로토콜을 준수하는 구조체를 만들 수 있습니다.
struct C: Identifiable {
}
이제 문제는 id 속성이나 name 속성에 값을 설정할 수 없다는 것입니다.
var c: C = C()
c.id = 12 // Cannot assign to property: 'id' is a get-only property
이것은 Identifiable 프로토콜에서 id와 name만 얻을 수 있기 때문에 발생합니다. 이제 id 및 name 속성을 {get set}으로 변경 하면 다음 오류가 발생합니다.
유형 'C'는 '식별 가능' 프로토콜을 준수하지 않습니다.
이 오류는 프로토콜 확장에 setter를 구현하지 않았기 때문에 발생합니다... 그래서 프로토콜 확장을 변경합니다.
extension Identifiable {
var id: Int {
get {
return 0
}
set {
}
}
var name: String {
get {
return "default"
}
set {
}
}
}
이제 오류는 사라지지만 새 값을 id 또는 name으로 설정하면 기본값(getter)이 설정됩니다. 물론, setter는 비어 있습니다.
내 질문은 : 어떤 코드 조각을 setter 안에 넣어야합니까? self.id = newValue를 추가 하면 충돌(재귀)하기 때문입니다.
미리 감사드립니다.
stored property
프로토콜 확장을 통해 유형 에 추가하려는 것 같습니다 . 그러나 확장을 사용하면 저장 속성을 추가할 수 없기 때문에 불가능합니다.
몇 가지 대안을 제시할 수 있습니다.
서브클래싱(객체 지향 프로그래밍)
가장 쉬운 방법(아마도 이미 상상한 대로)은 구조체 대신 클래스를 사용하는 것입니다.
class IdentifiableBase {
var id = 0
var name = "default"
}
class A: IdentifiableBase { }
let a = A()
a.name = "test"
print(a.name) // test
단점: 이 경우 A 클래스는 다음에서 상속해야 하고
IdentifiableBase
Swift에는 다중 상속이 없기 때문에 이것이 A 클래스가 상속할 수 있는 유일한 클래스가 됩니다.
컴포넌트(프로토콜 지향 프로그래밍)
이 기술은 게임 개발에서 꽤 유명합니다.
struct IdentifiableComponent {
var id = 0
var name = "default"
}
protocol HasIdentifiableComponent {
var identifiableComponent: IdentifiableComponent { get set }
}
protocol Identifiable: HasIdentifiableComponent { }
extension Identifiable {
var id: Int {
get { return identifiableComponent.id }
set { identifiableComponent.id = newValue }
}
var name: String {
get { return identifiableComponent.name }
set { identifiableComponent.name = newValue }
}
}
이제 유형을 Identifiable
단순히 쓰기에 적합 하게 만들 수 있습니다.
struct A: Identifiable {
var identifiableComponent = IdentifiableComponent()
}
시험
var a = A()
a.identifiableComponent.name = "test"
print(a.identifiableComponent.name) // test
프로토콜 및 프로토콜 확장은 매우 강력하지만 읽기 전용 속성 및 기능에 가장 유용한 경향이 있습니다.
달성하려는 것(기본값이 있는 저장 속성)에 대해 클래스와 상속이 실제로 더 우아한 솔루션일 수 있습니다.
다음과 같은 것:
class Identifiable {
var id: Int = 0
var name: String = "default"
}
class A:Identifiable {
}
class B:Identifiable {
}
let a = A()
print("\(a.id) \(a.name)")
a.id = 42
a.name = "foo"
print("\(a.id) \(a.name)")
Objective-C 관련 개체
Objective-C 관련 개체를 사용하여 기본적으로 stored property
a class
또는 에 a 를 추가 할 수 있습니다 protocol
. 연결된 개체는 클래스 개체에 대해서만 작동합니다.
import ObjectiveC.runtime
protocol Identifiable: class {
var id: Int { get set }
var name: String { get set }
}
var IdentifiableIdKey = "kIdentifiableIdKey"
var IdentifiableNameKey = "kIdentifiableNameKey"
extension Identifiable {
var id: Int {
get {
return (objc_getAssociatedObject(self, &IdentifiableIdKey) as? Int) ?? 0
}
set {
objc_setAssociatedObject(self, &IdentifiableIdKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
var name: String {
get {
return (objc_getAssociatedObject(self, &IdentifiableNameKey) as? String) ?? "default"
}
set {
objc_setAssociatedObject(self, &IdentifiableNameKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
}
이제 간단히 작성 하여 class
준수 할 수 있습니다.Identifiable
class A: Identifiable {
}
시험
var a = A()
print(a.id) // 0
print(a.name) // default
a.id = 5
a.name = "changed"
print(a.id) // 5
print(a.name) // changed
이것이 속성을 설정할 수 없는 이유입니다.
속성은 ObjC에서와 같이 _x와 같은 지원 변수가 없다는 것을 의미하는 계산된 속성이 됩니다. 아래 솔루션 코드에서 xTimesTwo는 아무 것도 저장하지 않고 단순히 x에서 결과를 계산하는 것을 볼 수 있습니다.
계산된 속성에 대한 공식 문서를 참조하십시오.
원하는 기능은 속성 관찰자일 수도 있습니다.
세터/게터는 Objective-C에서와 다릅니다.
필요한 것은 다음과 같습니다.
var x:Int
var xTimesTwo:Int {
set {
x = newValue / 2
}
get {
return x * 2
}
}
setter/getter 내에서 다른 속성을 수정할 수 있습니다.
ReferenceURL : https://stackoverflow.com/questions/38885622/swift-protocol-extensions-property-default-values
'IT이야기' 카테고리의 다른 글
갤러리에서 이미지를 가져오는 Android가 회전합니다. (0) | 2021.10.15 |
---|---|
-XX:-TieredCompilation (0) | 2021.10.15 |
ggmap 오류: GeomRasterAnn이 호환되지 않는 버전의 ggproto로 빌드되었습니다. (0) | 2021.10.15 |
보안을 처리하고 사용자가 입력한 URL로 XSS를 방지하는 가장 좋은 방법 (0) | 2021.10.14 |
Entity Framework 엔터티를 비즈니스 개체로 사용합니까? (0) | 2021.10.14 |