아래 코드는 잘 작동합니다.
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] 삭제
몇 마디 만하겠습니다