在协议中使用 self in 函数
Using self in function in a protocol
我有这个协议:
从故事板实例化一个 ViewController:
protocol Storyboarded {
static func instantiate() -> Self
}
extension Storyboarded where Self: UIViewController {
static func instantiate() -> Self {
// this pulls out "MyApp.MyViewController"
let fullName = NSStringFromClass(self)
// this splits by the dot and uses everything after, giving "MyViewController"
let className = fullName.components(separatedBy: ".")[1]
// load our storyboard
let storyboard = UIStoryboard(name: "Main", bundle: Bundle.main)
// instantiate a view controller with that identifier, and force cast as the type that was requested
return storyboard.instantiateViewController(withIdentifier: className) as! Self
}
}
一个将依赖项注入到 Viewcontrollers 中:
protocol DependencyInjection where Self: UIViewController {
associatedtype myType: DependencyVC
func injectDependencys(dependency: myType)
}
现在我想添加另一个,这样我就可以从依赖本身创建 ViewController:
protocol DependencyVC {
associatedtype myType: DependencyInjectionVC & Storyboarded
func createVC() -> myType
}
extension DependencyVC {
func makeVC<T: Storyboarded & DependencyInjection>() -> T where T.myType == Self {
let viewController = T.instantiate()
viewController.injectDependencys(dependency: self)
return viewController
}
}
但我自己得到这个错误:
Cannot invoke 'injectDependencys' with an argument list of type
'(dependency: Self)'
这是我拥有的 DependencyClass:
class TopFlopDependency: DependencyVC {
typealias myType = TopFlopVC
var topFlopState: TopFlopState
lazy var topFlopConfig: TopFlopConfig = {
let SIBM = StatIntervalBaseModel(stat: "ppc", interval: "24h", base: "usd")
return TopFlopConfig(group: Groups.large, base: "usd", valueOne: SIBM)
}()
init(state: TopFlopState) {
self.topFlopState = state
}
func createVC() -> TopFlopVC {
let topflopVC = TopFlopVC.instantiate()
topflopVC.injectDependencys(dependency: self)
let viewController: TopFlopVC = makeVC()
return topflopVC
}
}
我在使用 makeVC 时遇到这个错误:
'TopFlopDependency' requires the types 'TopFlopDependency.myType' and
'TopFlopDependency.myType' (aka 'TopFlopVC') be equivalent to use
'makeVC'
其他解决方案:
protocol DependencyVC {
}
extension DependencyVC {
func makeVC<T: Storyboarded & DependencyInjection>() -> T where T.myType == Self {
let viewController = T.instantiate()
viewController.injectDependencys(dependency: self)
return viewController
}
}
尝试使用时:
let viewController: TopFlopVC = makeVC()
我收到无法推断 T 的错误。
为什么我不能这样做?你有解决方案吗?
谢谢!
当您调用 viewController.injectDependencys(dependency: self)
时,已知 self
属于 DependencyVC
的某个子类型。但是,DependencyInjection
的 associatedtype myType: DependencyVC
只是说符合 DependencyInjection
的类型将使用 some 类型 myType
(符合DependencyVC
)。所以不能保证它的实际类型是 myType
.
的子类型
associatedtype
s 与泛型类型参数的工作方式并不完全相同,因为 associatedtype
s 在 "defining" 类型时给出,而泛型类型参数在 "using"一种。
归根结底,你可能不想associatedtype myType
,而是直接DependencyVC
。
更新
鉴于您提供的额外信息,我认为这将是最佳解决方案:
protocol DependencyInjection where Self: UIViewController {
func injectDependency(_ dependency: DependencyVC)
}
protocol DependencyVC {
func makeVC<T: Storyboarded & DependencyInjection>() -> T
}
extension DependencyVC {
func makeVC<T: Storyboarded & DependencyInjection>() -> T {
let viewController = T.instantiate()
viewController.injectDependency(self)
return viewController
}
}
如您所见,我冒昧地将 injectDependencys(dependency: DependencyVC)
重命名为 injectDependency(_ dependency: DependencyVC)
,因为您只注入了一个依赖项,而 dependency:
标签并没有真正添加任何内容在呼叫站点。
无论如何,这允许您使用您的依赖项创建视图控制器的实例。假设您将依赖项存储在一个名为 dependency
的变量中,那么您可以通过 let topFlopVC: TopFlopVC = dependency.makeVC()
从它创建一个视图控制器
您需要添加另一个约束条件。您的 DependencyInjection 协议需要非常特定类型的 DependencyVC (myType)。但是您的 DependencyVC 扩展适用于任何 DependencyVC。所以你需要用 where 子句将 T 的 myType 限制为相同的类型:func createVC<T: Storyboarded & DependencyInjection>() -> T where T.myType == Self
所以一个完整的例子是这样的:
protocol Storyboarded {
static func instantiate() -> Self
}
extension Storyboarded where Self: UIViewController {
static func instantiate() -> Self {
...
}
}
protocol DependencyVC {
}
protocol DependencyInjection where Self: UIViewController {
associatedtype myType: DependencyVC
func injectDependencys(dependency: myType)
}
extension DependencyVC {
func makeVC<T: Storyboarded & DependencyInjection>(type _: T.Type? = nil) -> T where T.myType == Self {
let viewController = T.instantiate()
viewController.injectDependencys(dependency: self)
return viewController
}
}
struct MyDependency: DependencyVC {}
class MyVC: UIViewController, Storyboarded, DependencyInjection {
func injectDependencys(dependency: MyDependency) {
print(dependency)
}
}
我有这个协议:
从故事板实例化一个 ViewController:
protocol Storyboarded {
static func instantiate() -> Self
}
extension Storyboarded where Self: UIViewController {
static func instantiate() -> Self {
// this pulls out "MyApp.MyViewController"
let fullName = NSStringFromClass(self)
// this splits by the dot and uses everything after, giving "MyViewController"
let className = fullName.components(separatedBy: ".")[1]
// load our storyboard
let storyboard = UIStoryboard(name: "Main", bundle: Bundle.main)
// instantiate a view controller with that identifier, and force cast as the type that was requested
return storyboard.instantiateViewController(withIdentifier: className) as! Self
}
}
一个将依赖项注入到 Viewcontrollers 中:
protocol DependencyInjection where Self: UIViewController {
associatedtype myType: DependencyVC
func injectDependencys(dependency: myType)
}
现在我想添加另一个,这样我就可以从依赖本身创建 ViewController:
protocol DependencyVC {
associatedtype myType: DependencyInjectionVC & Storyboarded
func createVC() -> myType
}
extension DependencyVC {
func makeVC<T: Storyboarded & DependencyInjection>() -> T where T.myType == Self {
let viewController = T.instantiate()
viewController.injectDependencys(dependency: self)
return viewController
}
}
但我自己得到这个错误:
Cannot invoke 'injectDependencys' with an argument list of type '(dependency: Self)'
这是我拥有的 DependencyClass:
class TopFlopDependency: DependencyVC {
typealias myType = TopFlopVC
var topFlopState: TopFlopState
lazy var topFlopConfig: TopFlopConfig = {
let SIBM = StatIntervalBaseModel(stat: "ppc", interval: "24h", base: "usd")
return TopFlopConfig(group: Groups.large, base: "usd", valueOne: SIBM)
}()
init(state: TopFlopState) {
self.topFlopState = state
}
func createVC() -> TopFlopVC {
let topflopVC = TopFlopVC.instantiate()
topflopVC.injectDependencys(dependency: self)
let viewController: TopFlopVC = makeVC()
return topflopVC
}
}
我在使用 makeVC 时遇到这个错误:
'TopFlopDependency' requires the types 'TopFlopDependency.myType' and 'TopFlopDependency.myType' (aka 'TopFlopVC') be equivalent to use 'makeVC'
其他解决方案:
protocol DependencyVC {
}
extension DependencyVC {
func makeVC<T: Storyboarded & DependencyInjection>() -> T where T.myType == Self {
let viewController = T.instantiate()
viewController.injectDependencys(dependency: self)
return viewController
}
}
尝试使用时:
let viewController: TopFlopVC = makeVC()
我收到无法推断 T 的错误。
为什么我不能这样做?你有解决方案吗?
谢谢!
当您调用 viewController.injectDependencys(dependency: self)
时,已知 self
属于 DependencyVC
的某个子类型。但是,DependencyInjection
的 associatedtype myType: DependencyVC
只是说符合 DependencyInjection
的类型将使用 some 类型 myType
(符合DependencyVC
)。所以不能保证它的实际类型是 myType
.
associatedtype
s 与泛型类型参数的工作方式并不完全相同,因为 associatedtype
s 在 "defining" 类型时给出,而泛型类型参数在 "using"一种。
归根结底,你可能不想associatedtype myType
,而是直接DependencyVC
。
更新
鉴于您提供的额外信息,我认为这将是最佳解决方案:
protocol DependencyInjection where Self: UIViewController {
func injectDependency(_ dependency: DependencyVC)
}
protocol DependencyVC {
func makeVC<T: Storyboarded & DependencyInjection>() -> T
}
extension DependencyVC {
func makeVC<T: Storyboarded & DependencyInjection>() -> T {
let viewController = T.instantiate()
viewController.injectDependency(self)
return viewController
}
}
如您所见,我冒昧地将 injectDependencys(dependency: DependencyVC)
重命名为 injectDependency(_ dependency: DependencyVC)
,因为您只注入了一个依赖项,而 dependency:
标签并没有真正添加任何内容在呼叫站点。
无论如何,这允许您使用您的依赖项创建视图控制器的实例。假设您将依赖项存储在一个名为 dependency
的变量中,那么您可以通过 let topFlopVC: TopFlopVC = dependency.makeVC()
您需要添加另一个约束条件。您的 DependencyInjection 协议需要非常特定类型的 DependencyVC (myType)。但是您的 DependencyVC 扩展适用于任何 DependencyVC。所以你需要用 where 子句将 T 的 myType 限制为相同的类型:func createVC<T: Storyboarded & DependencyInjection>() -> T where T.myType == Self
所以一个完整的例子是这样的:
protocol Storyboarded {
static func instantiate() -> Self
}
extension Storyboarded where Self: UIViewController {
static func instantiate() -> Self {
...
}
}
protocol DependencyVC {
}
protocol DependencyInjection where Self: UIViewController {
associatedtype myType: DependencyVC
func injectDependencys(dependency: myType)
}
extension DependencyVC {
func makeVC<T: Storyboarded & DependencyInjection>(type _: T.Type? = nil) -> T where T.myType == Self {
let viewController = T.instantiate()
viewController.injectDependencys(dependency: self)
return viewController
}
}
struct MyDependency: DependencyVC {}
class MyVC: UIViewController, Storyboarded, DependencyInjection {
func injectDependencys(dependency: MyDependency) {
print(dependency)
}
}