【问题标题】:How to cast an array of UIViewControllers to an array of protocol types如何将 UIViewControllers 数组转换为协议类型数组
【发布时间】:2015-07-13 14:55:23
【问题描述】:

我有一个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()
    }
}

【问题讨论】:

  • 你能不能只记录self.tabBarController.viewControllers,我怀疑它由UINavigationController而不是UIViewController组成,你可能需要做两个循环。
  • 啊,不。标签栏控制器直接包含视图控制器——中间没有导航控制器。事实上,如果我测试每个标签是否is Refreshable,代码执行(见传入问题更新)。
  • 啊,你已经得到答案了,这对我来说是正确的。
  • 你试过用as! [Refreshable]强制类型转换
  • 如果? 转换失败,! 只会导致崩溃。

标签: ios cocoa swift cocoa-touch foundation


【解决方案1】:

如果您的数组是[UIViewController],它将不接受类型为Refreshable 的项目,因为其他任意类可能符合它,它们不具有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 的实例的一种可能方法是首先过滤/映射您的数组,如下所示:

let items = myarray.filter({ $0 is Refreshable }).map({ return $0 as! Refreshable })

// items will be [Refreshable]
for item in items  {
    item.refresh()
}

这里需要注意的是,如果你使用 items 将是 [Refreshable] 类型,你不能再假设它具有来自其原始类的属性(即MyClass),只有那些协议授予它们(即在这种情况下为refresh())。

【讨论】:

    【解决方案2】:

    标签栏控制器中的viewControllers 属性被声明为[AnyObject]? .. 所以类型检查as? [Refreshable] 不会通过。 相反,遍历视图控制器并检查每个控制器的类型:

    for viewController in self.tabBarController!.viewControllers! {
        if let refreshableTab = viewController as? Refreshable {
            refreshableTab.refresh()
        }
    }
    

    【讨论】:

    • 即使我的Refreshable 协议扩展了AnyObject,我也觉得这很奇怪。无论如何,请投赞成票。
    【解决方案3】:

    总结@József Vesza 很好的答案,您可以执行以下操作:

    if  let tabs = self.tabBarController.viewControllers as? [UIViewController],
        let refreshables = tabs.filter({ $0 is Refreshable }).map({ $0 as! Refreshable } {
            refreshables[0].refresh()
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-05-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-06
      • 1970-01-01
      • 2023-02-05
      相关资源
      最近更新 更多