当前位置: 首页 > 面试题库 >

如果不应该,则可选绑定成功

萧建木
2023-03-14
问题内容

这是我在Swift(略作修改)中发布的遍历视图控制器层次结构的可能解决方案:

extension UIViewController {

    func traverseAndFindClass<T where T : UIViewController>(T.Type) -> T? {
        var currentVC = self
        while let parentVC = currentVC.parentViewController {
            println("comparing \(parentVC) to \(T.description())")
            if let result = parentVC as? T { // (XXX)
                return result
            }
            currentVC = parentVC
        }
        return nil
    }
}

该方法应遍历父视图控制器层次结构,并返回给定类的第一个实例;如果未找到,则返回nil。

但这是行不通的,我也不知道为什么。标有的可选绑定(XXX) 始终会成功执行 ,因此即使第一个父视图控制器不是的实例,也将返回它T

这很容易被复制:创建一个从在Xcode6通用的“iOS的主从应用程序”模板的项目,下面的代码添加到viewDidLoad()该的MasterViewController类:

if let vc = self.traverseAndFindClass(UICollectionViewController.self) {
    println("found: \(vc)")
} else {
    println("not found")
}

selfMasterViewController(的子类UITableViewController),并且其父视图控制器是UINavigationControllerUICollectionViewController父视图控制器层次结构中没有该类,因此我希望该方法返回nil并且输出“未找到”。

但这是发生了什么:

comparing <UINavigationController: 0x7fbc00c4de10> to UICollectionViewController
found: <UINavigationController: 0x7fbc00c4de10>

这显然是错误的,因为UINavigationController它不是的子类
UICollectionViewController。也许我犯了一些愚蠢的错误,但我找不到它。

为了找出问题,我还尝试使用独立于UIKit的自己的类层次结构来重现它:

class BaseClass : NSObject {
    var parentViewController : BaseClass?
}

class FirstSubClass : BaseClass { }

class SecondSubClass : BaseClass { }

extension BaseClass {

    func traverseAndFindClass<T where T : BaseClass>(T.Type) -> T? {
        var currentVC = self
        while let parentVC = currentVC.parentViewController {
            println("comparing \(parentVC) to \(T.description())")
            if let result = parentVC as? T { // (XXX)
                return result
            }
            currentVC = parentVC
        }
        return nil
    }
}

let base = BaseClass()
base.parentViewController = FirstSubClass()

if let result = base.traverseAndFindClass(SecondSubClass.self) {
    println("found: \(result)")
} else {
    println("not found")
}

你猜怎么着?现在可以正常工作了!输出是

comparing <MyApp.FirstSubClass: 0x7fff38f78c40> to MyApp.SecondSubClass
not found

更新:

  • 在通用方法中删除类型约束
    func traverseAndFindClass<T>(T.Type) -> T?
    

如@POB在评论中所建议,使其按预期工作。

  • 用“两步绑定”替换可选绑定
    if let result = parentVC as Any as? T { // (XXX)
    

正如@vacawama在他的回答中所建议的,它也可以按预期工作。

  • 构建配置从“调试”更改为“发布”还可以使该方法按预期工作。(到目前为止,我仅在iOS模拟器中对此进行了测试。)

最后一点可能表明这是Swift编译器或运行时错误。而且我仍然无法理解为什么问题出现在的子类中UIViewController,而不是出现在我的子类中BaseClass。因此,在接受答案之前,我将让问题开放一段时间。

更新2:Xcode 7起, 此问题已修复。

在最终的Xcode 7版本中,该问题不再发生。现在,在Release和Debug配置中if let result = parentVC as? T,该traverseAndFindClass()方法中的可选绑定 均按预期工作(并且失败)。


问题答案:

如果您尝试在Playground中将类型UINavigationController为object的对象UICollectionViewController强制转换为:

var nc = UINavigationController()

if let vc = nc as? UICollectionViewController {
    println("Yes")
} else {
    println("No")
}

您收到此错误:

游乐场执行失败:: 33:16:错误:如果让vc = nc为“ UICollectionViewController”不是“
UINavigationController”的子类型? UICollectionViewController {

但是,如果您这样做:

var nc = UINavigationController()

if let vc = (nc as Any) as? UICollectionViewController {
    println("Yes")
} else {
    println("No")
}

它显示“否”。

所以我建议尝试:

extension UIViewController {

    func traverseAndFindClass<T where T : UIViewController>(T.Type) -> T? {
        var currentVC = self
        while let parentVC = currentVC.parentViewController {
            println("comparing \(parentVC) to \(T.description())")
            if let result = (parentVC as Any) as? T { // (XXX)
                return result
            }
            currentVC = parentVC
        }
        return nil
    }
}


 类似资料:
  • 问题内容: 我想知道是否可以选择列的值(如果该列存在),否则选择null。换句话说,当列不存在时,我想“举起” select语句来处理这种情况。 注意,我正在巩固我的数据模型和设计。我希望在接下来的几周中排除这种逻辑,但是我真的想超越这个问题,因为数据模型修复比我现在想解决的要耗费更多时间。 另请注意,我希望能够在一个查询中执行此操作。所以我不是在寻找像这样的答案 首先检查子查询中的列。然后修改您

  • 问题内容: 快速使用以下语法进行流控制 在这种情况下 ,真值上下文的语义是什么 ? 是否允许 表达式链接 (如下所示)? 如果是这样,布尔表达式是否会短路? 问题答案: 首先检查它是否为零或是否有数据。如果为零,则不会执行if语句。如果有数据,则将数据解包并分配给if语句的范围。然后执行括号内的代码。 无法在一个if语句中链接此功能。不直接评估为布尔值。最好将“ if let”视为一个特殊关键字。

  • 问题内容: 考虑程序的三个不同的运行: 是否可以在第一种情况下,第二种情况下,第三种情况下使用? 问题答案: 带有参数的参数可以很好地处理此三向输入。 我也可以给它一个参数。 如何使用argparse在python中添加多个参数选项?

  • 问题内容: 最初使我不愿在代码中加入太多可选绑定的一件事是添加了更多的变量名。例如,我通常会写: 因为替代方案似乎有些混乱: 那是很多香蕉。我见过人们使用诸如新变量名之类的东西(在较大的代码块中可能很难看懂),但是我想知道是否存在一种普遍认可的变量名样式标准可以与可选绑定?谢谢阅读。 问题答案: 只需使用相同的名称: 不要使用匈牙利符号-如果您使用的是未包装的可选内容,则编译器会抱怨。

  • 这是我的可选装订 所以现在当我尝试调用这个构造函数时: 我得到了这个错误: 绑定

  • 我对如何在登录时重定向用户感到困惑 脚本: - 我正在计划我的身份验证。ts,第一次登录时,在我的firebase上,我将设置一个类似于1(如果用户完成了测试)和0(如果用户没有完成测试)的检查器 以下是登录代码: 一个uth.ts