如何将 UIViewController 数组转换为协议类型数组
How to cast an array of UIViewControllers to an array of protocol types
我有一个 UITabBarController
,其 viewControllers
都实现了协议 Refreshable
。为什么我无法将选项卡栏控制器的 viewControllers
属性 解包为 Refreshable
类型的数组?
if let tabs = self.tabBarController.viewControllers as? [Refreshable] {
// Some code
tabs[0].refresh() // refresh() is a function in Refreshable
}
没有编译错误,但是 if let
闭包中的代码永远不会执行。我怎样才能正确地做到这一点?
添加:
这个可行,但我不喜欢它--我觉得我应该可以像上面那样表达这个。
if let tabs = self.tabBarController.viewControllers as? [UIViewController] {
if tabs[0] is Refreshable {
(tabs[0] as! Refreshable).refresh()
}
}
标签栏控制器中的 viewControllers
属性 被声明为 [AnyObject]?
.. 所以类型检查 as? [Refreshable]
不会通过。
相反,遍历视图控制器并检查每个视图控制器的类型:
for viewController in self.tabBarController!.viewControllers! {
if let refreshableTab = viewController as? Refreshable {
refreshableTab.refresh()
}
}
如果您的数组是 [UIViewController]
,它不会接受类型为 Refreshable
的项目,因为其他任意 classes 可能符合它,但没有UIViewController
的属性。
换句话说,仅 Refreshable
对您的数组来说还不够强大,因为它不能保证 UIViewController
个实例。
原始表达式仅适用于数组,其中类型由协议类型指定,如下所示:
// Suppose MyClass conforms to Refreshable
let myArray: [Refreshable] = [
MyClass(),
MyClass(),
MyClass(),
MyClass(),
]
// Now you can use refresh() without problems
for item in myArray {
item.refresh()
}
不幸的是,由于您在标签栏控制器上使用 属性,恐怕这不适合您。确保您只使用符合 Refreshable
的实例的一种可能方法是首先 filter/map 您的数组,如下所示:
let items = myarray.filter({ [=11=] is Refreshable }).map({ return [=11=] as! Refreshable })
// items will be [Refreshable]
for item in items {
item.refresh()
}
这里需要注意的是,如果您使用 items
类型 [Refreshable]
,您不能再假设它具有原始 class 的属性(即 MyClass
),只有协议授予它们的那些(即本例中的 refresh()
)。
总结@József Vesza 的好答案,您可以执行以下操作:
if let tabs = self.tabBarController.viewControllers as? [UIViewController],
let refreshables = tabs.filter({ [=10=] is Refreshable }).map({ [=10=] as! Refreshable } {
refreshables[0].refresh()
}
我有一个 UITabBarController
,其 viewControllers
都实现了协议 Refreshable
。为什么我无法将选项卡栏控制器的 viewControllers
属性 解包为 Refreshable
类型的数组?
if let tabs = self.tabBarController.viewControllers as? [Refreshable] {
// Some code
tabs[0].refresh() // refresh() is a function in Refreshable
}
没有编译错误,但是 if let
闭包中的代码永远不会执行。我怎样才能正确地做到这一点?
添加:
这个可行,但我不喜欢它--我觉得我应该可以像上面那样表达这个。
if let tabs = self.tabBarController.viewControllers as? [UIViewController] {
if tabs[0] is Refreshable {
(tabs[0] as! Refreshable).refresh()
}
}
标签栏控制器中的 viewControllers
属性 被声明为 [AnyObject]?
.. 所以类型检查 as? [Refreshable]
不会通过。
相反,遍历视图控制器并检查每个视图控制器的类型:
for viewController in self.tabBarController!.viewControllers! {
if let refreshableTab = viewController as? Refreshable {
refreshableTab.refresh()
}
}
如果您的数组是 [UIViewController]
,它不会接受类型为 Refreshable
的项目,因为其他任意 classes 可能符合它,但没有UIViewController
的属性。
换句话说,仅 Refreshable
对您的数组来说还不够强大,因为它不能保证 UIViewController
个实例。
原始表达式仅适用于数组,其中类型由协议类型指定,如下所示:
// Suppose MyClass conforms to Refreshable
let myArray: [Refreshable] = [
MyClass(),
MyClass(),
MyClass(),
MyClass(),
]
// Now you can use refresh() without problems
for item in myArray {
item.refresh()
}
不幸的是,由于您在标签栏控制器上使用 属性,恐怕这不适合您。确保您只使用符合 Refreshable
的实例的一种可能方法是首先 filter/map 您的数组,如下所示:
let items = myarray.filter({ [=11=] is Refreshable }).map({ return [=11=] as! Refreshable })
// items will be [Refreshable]
for item in items {
item.refresh()
}
这里需要注意的是,如果您使用 items
类型 [Refreshable]
,您不能再假设它具有原始 class 的属性(即 MyClass
),只有协议授予它们的那些(即本例中的 refresh()
)。
总结@József Vesza 的好答案,您可以执行以下操作:
if let tabs = self.tabBarController.viewControllers as? [UIViewController],
let refreshables = tabs.filter({ [=10=] is Refreshable }).map({ [=10=] as! Refreshable } {
refreshables[0].refresh()
}