Created
October 27, 2016 16:56
-
-
Save jeffreybergier/4482b0ab0357b08558a09501d60b6d1d to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// I've tried several combos | |
// I'll list each one and the error it gives | |
// #1 Playground execution failed: error: Untitled Page 2.xcplaygroundpage:4:24: error: cannot specialize non-generic type 'MyWeirdDictionaryDelegate' | |
protocol MyWeirdDictionaryDelegate: class { | |
associatedtype K | |
func willSet(value: K, forKey key: String) -> K? | |
func willReturn(value: K?, forKey: String) -> K? | |
} | |
class MyWeirdDictionary<T> { | |
weak var delegate: MyWeirdDictionaryDelegate<T>? | |
private var data = [String : T]() | |
func set(value: T, forKey key: String) { | |
self.data[key] = self.delegate?.willSet(value: value, forKey: key) ?? value | |
} | |
func value(forKey key: String) -> T? { | |
let existingValue = self.data[key] | |
return self.delegate?.willReturn(value: existingValue, forKey: key) ?? existingValue | |
} | |
} | |
// #2 Playground execution failed: error: Untitled Page 2.xcplaygroundpage:2:24: error: protocol 'MyWeirdDictionaryDelegate' can only be used as a generic constraint because it has Self or associated type requirements | |
protocol MyWeirdDictionaryDelegate: class { | |
associatedtype K | |
func willSet(value: K, forKey key: String) -> K? | |
func willReturn(value: K?, forKey: String) -> K? | |
} | |
class MyWeirdDictionary<T> { | |
weak var delegate: MyWeirdDictionaryDelegate? | |
private var data = [String : T]() | |
func set(value: T, forKey key: String) { | |
self.data[key] = self.delegate?.willSet(value: value, forKey: key) ?? value | |
} | |
func value(forKey key: String) -> T? { | |
let existingValue = self.data[key] | |
return self.delegate?.willReturn(value: existingValue, forKey: key) ?? existingValue | |
} | |
} | |
// #3 Protocols do not allow generic parameters; use associated types instead | |
protocol MyWeirdDictionaryDelegate<K>: class { | |
func willSet(value: K, forKey key: String) -> K? | |
func willReturn(value: K?, forKey: String) -> K? | |
} | |
class MyWeirdDictionary<T> { | |
weak var delegate: MyWeirdDictionaryDelegate<T>? | |
private var data = [String : T]() | |
func set(value: T, forKey key: String) { | |
self.data[key] = self.delegate?.willSet(value: value, forKey: key) ?? value | |
} | |
func value(forKey key: String) -> T? { | |
let existingValue = self.data[key] | |
return self.delegate?.willReturn(value: existingValue, forKey: key) ?? existingValue | |
} | |
} | |
// #4 this is how I got it to work. replacing the protocol with an empty superclass and then subcalssing the delegate class to make my own custom delegate | |
class MyWeirdDictionaryDelegate<K> { | |
func willSet(value: K, forKey key: String) -> K? { return .none } | |
func willReturn(value: K?, forKey: String) -> K? { return .none } | |
} | |
class MyWeirdDictionary<T> { | |
weak var delegate: MyWeirdDictionaryDelegate<T>? | |
private var data = [String : T]() | |
func set(value: T, forKey key: String) { | |
self.data[key] = self.delegate?.willSet(value: value, forKey: key) ?? value | |
} | |
func value(forKey key: String) -> T? { | |
let existingValue = self.data[key] | |
return self.delegate?.willReturn(value: existingValue, forKey: key) ?? existingValue | |
} | |
} |
Thanks. I'll give that a shot. No I want the types to match on the delegate and delegating instance.
import Foundation
protocol MyWeirdDictionaryDelegate: class {
associatedtype K
func willSet(value: K, forKey key: String, weirdDictionary: MyWeirdDictionary<K, Self>) -> K?
func willReturn(value: K?, forKey: String, weirdDictionary: MyWeirdDictionary<K, Self>) -> K?
}
class MyWeirdDictionary<T, D:MyWeirdDictionaryDelegate> where D.K == T {
weak var delegate: D?
private var data = [String : T]()
func set(value: T, forKey key: String) {
self.data[key] = self.delegate?.willSet(value: value, forKey: key, weirdDictionary: self) ?? value
}
func value(forKey key: String) -> T? {
let existingValue = self.data[key]
return self.delegate?.willReturn(value: existingValue, forKey: key, weirdDictionary: self) ?? existingValue
}
}
final class MyAwesomeWeirdDictionaryDelegate: MyWeirdDictionaryDelegate {
typealias K = Date
func willSet(value: K, forKey key: String, weirdDictionary: MyWeirdDictionary<K, MyAwesomeWeirdDictionaryDelegate>) -> K? {
print("Awesome Date: \(value)")
return .none
}
func willReturn(value: K?, forKey: String, weirdDictionary: MyWeirdDictionary<K, MyAwesomeWeirdDictionaryDelegate>) -> K? {
if let value = value {
print("Getting Awesome Date: \(value)")
} else {
print("Couldn't find an awesome date :(")
}
return .none
}
}
let storage = MyWeirdDictionary<Date, MyAwesomeWeirdDictionaryDelegate>()
let delegate = MyAwesomeWeirdDictionaryDelegate()
storage.delegate = delegate
storage.set(value: Date(), forKey: "Hi")
storage.value(forKey: "Hi")
storage.value(forKey: "Hello")
I had to add a Self requirement in the protocol so I could pass a pointer to the delegator through the delegate methods. So now the delegate class cannot be subclassed. It gives the error below. Its ok. I don't need to subclass the delegate.
Also, credit needs to go to Khanlou on his suggestion for changing the names of delegate methods to put the delegator argument at the end. I think it makes them look massively better. http://khanlou.com/2016/09/swifty-delegates/
Playground execution failed: error: Untitled Page 2.xcplaygroundpage:18:10: error: protocol 'MyWeirdDictionaryDelegate' requirement 'willSet(value:forKey:weirdDictionary:)' cannot be satisfied by a non-final class ('MyAwesomeWeirdDictionaryDelegate') because it uses 'Self' in a non-parameter, non-result type position
func willSet(value: K, forKey key: String, weirdDictionary: MyWeirdDictionary<K, MyAwesomeWeirdDictionaryDelegate>) -> K? {
^
error: Untitled Page 2.xcplaygroundpage:22:10: error: protocol 'MyWeirdDictionaryDelegate' requirement 'willReturn(value:forKey:weirdDictionary:)' cannot be satisfied by a non-final class ('MyAwesomeWeirdDictionaryDelegate') because it uses 'Self' in a non-parameter, non-result type position
func willReturn(value: K?, forKey: String, weirdDictionary: MyWeirdDictionary<K, MyAwesomeWeirdDictionaryDelegate>) -> K? {
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Here's one way:
If you don't want to make your dictionary generic over its value type and over the delegate type, then I suspect you need to use some form of type erasure.