이니셜 라이저에서 제한된 제네릭에 대한 동적 디스패치를 얻는 방법

프랭크 R.

아래 코드는 잘 작동합니다.

protocol VariableType {
    
    associatedtype T
    
    var value : T { get }
 
}

class UserDefaultsVariable<T> : VariableType {
   
    let storageKey : String
    
    var value : T {
        
        get {
            return UserDefaults.standard.object(forKey: storageKey) as! T
        }
        
        set(value) {
            UserDefaults.standard.set(value, forKey: storageKey)
        }
    }
    
    init( storageKey : String, initialValue : T  ) {
        self.storageKey = storageKey
        // I want dynamic dispatch here so that if T: RawRepresentable then the
        // function in the extension is called
        self.registerDefaultValue(initialValue: initialValue)
    }
    
    func registerDefaultValue( initialValue : T ) {
        debugPrint("this is called both times!")
        UserDefaults.standard.register(defaults: [storageKey : initialValue])
    }
    
}

부름:

let simpleDefault = UserDefaultsVariable<Int>(storageKey: "simple", initialValue: 0)
let initialValue = simpleDefault.value

예상대로 초기 값은 0이됩니다.

RawRepresentable유형 을 지원하도록 확장하려고 할 때 문제가 발생 합니다.

extension UserDefaultsVariable where T: RawRepresentable {
    
    var value: T {
        get {
            let rawValue = UserDefaults.standard.object(forKey: storageKey) as! T.RawValue
            return T(rawValue: rawValue)!
        }
        set {
            UserDefaults.standard.set(newValue.rawValue, forKey: storageKey)
        }
    }
    
    func registerDefaultValue( initialValue : T ) {
        debugPrint("this is never called!")
        UserDefaults.standard.register(defaults: [storageKey:initialValue.rawValue])
    }
}

내가 이것을 부를 때 :

let simpleDefault = UserDefaultsVariable<Int>(storageKey: "simple", initialValue: 0)
let initialValue = simpleDefault.value

enum Direction : Int {
    case left = 0
    case right = 1
}

let enumedDefault = UserDefaultsVariable<Direction>(storageKey: "enumed", initialValue: .left)

의 registerDefaults 구현 UserDefaultsVariable<T>이 특수 UserDefaultsVariable<T:RawRepresentable>구현 대신 호출 되기 때문에 코드가 충돌합니다 .

이니셜 라이저 외부 에서 호출하기 , 예 :

enumedDefault.registerDefaultValue(initialValue: .left)

올바른 구현을 호출합니다!? 그래서 디스패치는 일반적으로 동적이지만 이니셜 라이저 내부가 아닌 것처럼 보입니다 . 아니면 전체 수업?

어떤 도움이라도 대단히 감사하겠습니다.

해결책

@matt가 지적했듯이 Swift가 어떤 형태의 다형성을 통해 제한된 버전의 함수를 호출 할 것이라고 잘못 기대하지만 컴파일러는 컴파일 타임에 호출을 해결하고 "가장 구체적인 구현"을 찾으려고 시도하지 않습니다.

@Asperi는 실행 가능한 솔루션을 제공하지만 DefaultsVariable은 초기 값없이 초기화 될 수 있다는 단점이 있습니다.

내가 한 일은 UserDefaultsVariable을 단순히 서브 클래 싱하여 다형성을 도입하는 것이 었습니다.

class RawRepresentableUserDefaultsVariable<T: RawRepresentable> : UserDefaultsVariable<T>{
    
    override var value: T {
        get {
            let rawValue = UserDefaults.standard.object(forKey: storageKey) as! T.RawValue
            return T(rawValue: rawValue)!
        }
        set {
            UserDefaults.standard.set(newValue.rawValue, forKey: storageKey)
        }
    }
    
    override func registerDefaultValue( initialValue : T ) {
        UserDefaults.standard.register(defaults: [storageKey:initialValue.rawValue])
    }
}

let enumedDefault = RawRepresentableUserDefaultsVariable<Direction>(storageKey: "enumed", initialValue: .left)

let initialEnumValue = enumedDefault.value

이것은 잘 컴파일 registerDefaultValue되고 수퍼 클래스의 이니셜 라이저에서 하위 클래스 의을 호출합니다 .

도움을 주셔서 정말 감사합니다.

그의 성질

여기에 가능한 접근 방식이 있습니다.

아이디어는 확장에서 이니셜 라이저 편의를 만드는 것이므로 제네릭 전문 확장은 기본 확장과 겹칩니다.

Xcode 11.4 / swift 5.2 테스트 및 작동

class UserDefaultsVariable<T> : VariableType {

    let storageKey : String

    init(storageKey: String) {
        self.storageKey = storageKey
    }

    var value : T {

        get {
            return UserDefaults.standard.object(forKey: storageKey) as! T
        }

        set(value) {
            UserDefaults.standard.set(value, forKey: storageKey)
        }
    }

    func registerDefaultValue( initialValue : T ) {
        UserDefaults.standard.register(defaults: [storageKey : initialValue])
    }

}

extension UserDefaultsVariable {

    // this initializer uses default T
    convenience init(storageKey : String, initialValue : T) {

        self.init(storageKey: storageKey)
        self.registerDefaultValue(initialValue: initialValue)
    }
}

extension UserDefaultsVariable where T: RawRepresentable {

    // this initializer uses specialised T
    convenience init(storageKey : String, initialValue : T) {

        self.init(storageKey: storageKey)
        self.registerDefaultValue(initialValue: initialValue)
    }

    var value: T {
        get {
            let rawValue = UserDefaults.standard.object(forKey: storageKey) as! T.RawValue
            return T(rawValue: rawValue)!
        }
        set {
            UserDefaults.standard.set(newValue.rawValue, forKey: storageKey)
        }
    }

    func registerDefaultValue( initialValue : T ) {
        UserDefaults.standard.register(defaults: [storageKey:initialValue.rawValue])
    }
}

이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.

침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제

에서 수정
0

몇 마디 만하겠습니다

0리뷰
로그인참여 후 검토

관련 기사

분류에서Dev

제네릭과 트레이 트를 위해 Rust에서 동적 디스패치를 사용하는 방법은 무엇입니까?

분류에서Dev

런타임에 제네릭 클래스에 대한 TypeTag를 얻는 방법

분류에서Dev

C #의 형식 안전 컬렉션에 제한된 제네릭 형식이있는 작업 대리자를 저장하는 방법은 무엇입니까?

분류에서Dev

제네릭 Dart 메서드에서 제네릭 유형 T에 대한 제약을 적용하는 방법

분류에서Dev

Swift에서 이러한 이니셜 라이저를 작성하는 방법은 무엇입니까?

분류에서Dev

메서드 링크 된 제네릭 유형에 대한 TRTTIType을 얻는 방법

분류에서Dev

제네릭이있는 gson에 대한 적절한 구문

분류에서Dev

반복기에 대한 제네릭 메서드를 구현하는 적절한 방법

분류에서Dev

생성자에서 이니셜 라이저를 사용하여 동일한 값으로 2D 배열을 설정하는 방법은 무엇입니까?

분류에서Dev

내 반응 네이티브 redux 앱의 구성 요소 메서드에서 디스패치 메서드에 대한 참조를 얻는 방법

분류에서Dev

Swift 5.0에서 " '(MKMapRect)' '유형의 인수 목록이있는'MKMapRect '유형에 대한 이니셜 라이저를 호출 할 수 없음"오류 수정 방법

분류에서Dev

제한된 기간 동안 자동화 된 테스트에서 최대 가치를 얻는 방법은 무엇입니까?

분류에서Dev

제한된 기간 동안 자동화 된 테스트에서 최대 가치를 얻는 방법은 무엇입니까?

분류에서Dev

스칼라에서 제한된 제네릭 클래스를 작성하는 방법

분류에서Dev

[DisallowNull]에서 개체 이니셜 라이저에 대한 오류를 표시하는 방법은 무엇입니까?

분류에서Dev

TypeScript에서 제한된 제네릭 유형의 인스턴스를 인스턴스화하는 방법이 있습니까?

분류에서Dev

제출하기 전에 동적 필드에 대한 클라이언트 측 임시 데이터를 저장하는 가장 논리적 인 방법

분류에서Dev

두 번째 이니셜 라이저에서 사용되는 SwiftUI 제네릭

분류에서Dev

TypeScript 제네릭 함수에 대한 제네릭 유형 별칭을 만드는 방법은 무엇입니까?

분류에서Dev

지정된 이니셜 라이저에서 프로토콜 확장 이니셜 라이저를 호출하는 방법은 무엇입니까?

분류에서Dev

클릭 이벤트에서 자동으로 생성 된 버튼에 대한 특정 정보를 얻는 방법

분류에서Dev

제네릭 클래스 메서드에 대한 올바른 확장 메서드를 얻는 방법은 무엇입니까?

분류에서Dev

ng-view와 함께 angularjs의 라이트 박스 모달에서 이미지에 대한 동적 경로를 제공하는 방법은 무엇입니까?

분류에서Dev

SwiftUI-제네릭 뷰에 대해 빈 이니셜 라이저를 정의 할 수 있습니까?

분류에서Dev

UIView에 대한 정적 이니셜 라이저 만들기

분류에서Dev

객체 유형 캐스팅에 대한 제네릭이 암시적인 이유는 무엇입니까?

분류에서Dev

객체 유형 캐스팅에 대한 제네릭이 암시적인 이유는 무엇입니까?

분류에서Dev

Swift에서 실패 가능한 이니셜 라이저를 위임하는 올바른 방법은 무엇입니까?

분류에서Dev

Kotlin에서 제네릭 클래스를 동일한 클래스의 제네릭 배열에 매핑하는 방법

Related 관련 기사

  1. 1

    제네릭과 트레이 트를 위해 Rust에서 동적 디스패치를 사용하는 방법은 무엇입니까?

  2. 2

    런타임에 제네릭 클래스에 대한 TypeTag를 얻는 방법

  3. 3

    C #의 형식 안전 컬렉션에 제한된 제네릭 형식이있는 작업 대리자를 저장하는 방법은 무엇입니까?

  4. 4

    제네릭 Dart 메서드에서 제네릭 유형 T에 대한 제약을 적용하는 방법

  5. 5

    Swift에서 이러한 이니셜 라이저를 작성하는 방법은 무엇입니까?

  6. 6

    메서드 링크 된 제네릭 유형에 대한 TRTTIType을 얻는 방법

  7. 7

    제네릭이있는 gson에 대한 적절한 구문

  8. 8

    반복기에 대한 제네릭 메서드를 구현하는 적절한 방법

  9. 9

    생성자에서 이니셜 라이저를 사용하여 동일한 값으로 2D 배열을 설정하는 방법은 무엇입니까?

  10. 10

    내 반응 네이티브 redux 앱의 구성 요소 메서드에서 디스패치 메서드에 대한 참조를 얻는 방법

  11. 11

    Swift 5.0에서 " '(MKMapRect)' '유형의 인수 목록이있는'MKMapRect '유형에 대한 이니셜 라이저를 호출 할 수 없음"오류 수정 방법

  12. 12

    제한된 기간 동안 자동화 된 테스트에서 최대 가치를 얻는 방법은 무엇입니까?

  13. 13

    제한된 기간 동안 자동화 된 테스트에서 최대 가치를 얻는 방법은 무엇입니까?

  14. 14

    스칼라에서 제한된 제네릭 클래스를 작성하는 방법

  15. 15

    [DisallowNull]에서 개체 이니셜 라이저에 대한 오류를 표시하는 방법은 무엇입니까?

  16. 16

    TypeScript에서 제한된 제네릭 유형의 인스턴스를 인스턴스화하는 방법이 있습니까?

  17. 17

    제출하기 전에 동적 필드에 대한 클라이언트 측 임시 데이터를 저장하는 가장 논리적 인 방법

  18. 18

    두 번째 이니셜 라이저에서 사용되는 SwiftUI 제네릭

  19. 19

    TypeScript 제네릭 함수에 대한 제네릭 유형 별칭을 만드는 방법은 무엇입니까?

  20. 20

    지정된 이니셜 라이저에서 프로토콜 확장 이니셜 라이저를 호출하는 방법은 무엇입니까?

  21. 21

    클릭 이벤트에서 자동으로 생성 된 버튼에 대한 특정 정보를 얻는 방법

  22. 22

    제네릭 클래스 메서드에 대한 올바른 확장 메서드를 얻는 방법은 무엇입니까?

  23. 23

    ng-view와 함께 angularjs의 라이트 박스 모달에서 이미지에 대한 동적 경로를 제공하는 방법은 무엇입니까?

  24. 24

    SwiftUI-제네릭 뷰에 대해 빈 이니셜 라이저를 정의 할 수 있습니까?

  25. 25

    UIView에 대한 정적 이니셜 라이저 만들기

  26. 26

    객체 유형 캐스팅에 대한 제네릭이 암시적인 이유는 무엇입니까?

  27. 27

    객체 유형 캐스팅에 대한 제네릭이 암시적인 이유는 무엇입니까?

  28. 28

    Swift에서 실패 가능한 이니셜 라이저를 위임하는 올바른 방법은 무엇입니까?

  29. 29

    Kotlin에서 제네릭 클래스를 동일한 클래스의 제네릭 배열에 매핑하는 방법

뜨겁다태그

보관