Ohi*_*end 5 generics unit-testing ios associated-types swift
我试图找出是否有关于 Swift 协议associatedtype使用 a=而不是:.
例如。
associatedtype Thing = SomeOtherThing
与
associatedtype Thing: SomeOtherThing
不要与我typealias Thing = SomeOtherThing始终=相信的(可能让我困惑的)混淆。
我试图抽象包含委托并使用=for associatedtypes 的类的用法,直到遇到一个问题,即该类型的变量由于 而没有公开其属性=,而是需要通常的:,这对我来说是从某种意义上说,但是当我将一个特定更改=为 a时:,它导致一切都崩溃了。我在下面提供了一个示例,其中的想法是能够自由获取/设置委托对象,但或多或少有一个协议说它的委托必须是关联类型的类型(带有 )而=不仅仅是正如似乎暗示的那样,“你必须遵守这一点” :。
我也不知道我是否迈出了这一步太过分的一步,还有其他更好的方法可以在测试方面表达这一点。这似乎是必需的,因为我不能完全依赖外部对象在测试中按预期工作,而是需要模拟它以故意失败,在某些情况下如此。
import Foundation
// Concrete objects (eg external framework)
protocol ManagerDelegate: AnyObject {
func managerDidSomething(_ manager: Manager)
}
class Manager {
weak var delegate: ManagerDelegate?
func doSomething() {
delegate?.managerDidSomething(self)
}
}
// Custom objects using concrete objects, set up to be testable
class CustomManagerDelegate: ManagerDelegate {
func managerDidSomething(_ manager: Manager) {
print(#function)
}
}
class CustomClass<ManagerType: SomeManager> {
private(set) var doSomethingCustomCalled = false
private let managerDelegate: ManagerType.DelegateType
private let manager: ManagerType
init(manager: ManagerType, managerDelegate: ManagerType.DelegateType) {
self.manager = manager
self.managerDelegate = managerDelegate
manager.delegate = managerDelegate
}
func doSomethingCustom() {
doSomethingCustomCalled = true
manager.doSomething()
}
}
// Example creation of custom object
class Example {
static func createCustomObject() {
let customObject = CustomClass(
manager: Manager(),
// if `:` used instead of `=` for `SomeManager.DelegateType`, error is:
// Cannot convert value of type 'CustomManagerDelegate' to expected argument type 'Manager.DelegateType'
managerDelegate: CustomManagerDelegate() // error fix: add `as! Manager.DelegateType`
)
customObject.doSomethingCustom()
}
}
// Testable interface
protocol SomeManager: AnyObject {
// This `=` is the only thing keeping it together
associatedtype DelegateType = SomeManagerDelegate
// This doesn't work
//associatedtype DelegateType: SomeManagerDelegate
var delegate: DelegateType? { get set }
func doSomething()
}
protocol SomeManagerDelegate {
associatedtype ManagerType: SomeManager
func managerDidSomething(_ manager: ManagerType)
}
// Testable interface conformance
// if `:` used instead of `=` for `SomeManager.DelegateType`, error is:
// Type 'Manager' does not conform to protocol 'SomeManager'
extension Manager: SomeManager {
// already conforms
}
class MockManagerDelegate: SomeManagerDelegate {
typealias ManagerType = MockManager
func managerDidSomething(_ manager: ManagerType) {
print(#function)
}
}
class MockManager: SomeManager {
weak var delegate: MockManagerDelegate?
func doSomething() {
delegate?.managerDidSomething(self)
}
}
// Tests
class CustomClassTests {
func testCustomSomethingWasCalled() {
let mockInjectedCustomClass = CustomClass(
manager: MockManager(),
managerDelegate: MockManagerDelegate()
)
mockInjectedCustomClass.doSomethingCustom()
print("Was Called:", mockInjectedCustomClass.doSomethingCustomCalled)
assert(mockInjectedCustomClass.doSomethingCustomCalled)
}
}
CustomClassTests().testCustomSomethingWasCalled()
/* console:
managerDidSomething(_:)
Was Called: true
*/
Run Code Online (Sandbox Code Playgroud)
the=和 the:是关联类型声明的两个独立部分,而不是相互排斥的。这是协议关联类型声明的完整语法:
attributes(opt)
access-level-modifier(opt)
'associatedtype'
typealias-name
type-inheritance-clause(opt)
typealias-assignment(opt)
generic-where-clause(opt)
Run Code Online (Sandbox Code Playgroud)
部分: TypeName是type-inheritance-clause,而= TypeName是typealias-assignment。
: TypeName限制关联类型可以是什么类型,即它必须继承/符合TypeName. 这就是为什么: SomeManagerDelegate在你的情况下不起作用的原因。你说的SomeManager.DelegateType一定是某种类型的SomeManagerDelegate,但是对于 来说Manager,这不是真的 -Manager.delegate是类型ManagerDelegate,这是一个完全不相关的协议。即使是这样SomeManagerDelegate,它也不会起作用,因为协议本身并不符合协议。
= TypeName为关联类型设置默认类型。如果编译器无法推断一致性的关联类型应该是什么类型,并且您也没有明确说明它,它将使用该类型。但就你而言,这个事实并不重要。实际上导致您的代码工作的不是添加,= SomeManagerDelegate而是删除了约束: SomeManagerDelegate。您不再限制关联类型应该是什么类型(它可以是任何类型!),因此对于Manager,关联类型现在可以推断为ManagerDelegate。请注意,您不必明确地说:
typealias DelegateType = ManagerDelegate
Run Code Online (Sandbox Code Playgroud)
事实上,你可以完全删除= SomeManagerDelegate并只说:
associatedtype DelegateType
Run Code Online (Sandbox Code Playgroud)
=因此,“这是唯一将其保持在一起的东西”,这与事实相去甚远。
这种= TypeName语法似乎没有很好的记录。这是相关的Swift 论坛帖子。
| 归档时间: |
|
| 查看次数: |
203 次 |
| 最近记录: |