Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Swift 为什么这个带有可选参数的方法不重写基类方法?_Swift - Fatal编程技术网

Swift 为什么这个带有可选参数的方法不重写基类方法?

Swift 为什么这个带有可选参数的方法不重写基类方法?,swift,Swift,结果是“a”,但我希望它是“b”。我想知道为什么,以及如何在没有参数的情况下调用doTest来打印“b” 获得a输出的原因是,您没有调用新方法func-doTest(\uu不同:Bool=true),该方法需要Bool bObjc.doTest(true) // b 实际上,您正在调用从父类AA继承的方法doTest() 如果要覆盖AA中的方法,只需执行以下操作: class BB: AA { override func doTest() { print("b")

结果是“a”,但我希望它是“b”。我想知道为什么,以及如何在没有参数的情况下调用
doTest
来打印“b”


获得
a
输出的原因是,您没有调用新方法
func-doTest(\uu不同:Bool=true)
,该方法需要
Bool

bObjc.doTest(true)  // b
实际上,您正在调用从父类
AA
继承的方法
doTest()


如果要覆盖
AA
中的方法,只需执行以下操作:

class BB: AA {
    override func doTest() {
        print("b")
    }
}

let bObjc = BB()
bObjc.doTest()

Class
BB
不会重写
AA
中的方法,这意味着
BB
上存在两个方法:

func doTest() // inherited
func doTest(_ different: Bool = true) // declared
当你打电话的时候

bObjc.doTest()

编译器必须选择其中一个。它更喜欢没有参数的方法,而不是有默认参数的方法。

这是一个不幸的情况。没有办法影响编译器如何用这样的简单Swift消除调用的歧义

让我们看看一些选项:

  • 确认编译器所做的操作并重写
    BB.doTest()
    以将调用转发到
    BB.doTest(:)
  • 使用
    #选择器(BB.doTest(:)
    指定所需方法的签名
  • 使用Swift协议限制编译器正在考虑的可能方法
  • 重写类似命名的基本方法(可能是最简单的解决方案) 在这种情况下,强制编译器不使用最简单方法签名的最简单方法是重写
    B
    中的
    doTest
    ,并重新路由调用:

    AA级{
    func doTest(){
    打印(“a”)
    }
    }
    BB类:AA{
    重写func doTest(){
    self.doTest(真)
    }
    func doTest(u不同:Bool=true){
    打印(“b”)
    }
    }
    设bObjc=BB()
    bObjc.doTest()
    
    如果不可能,请继续阅读

    指定
    doTest(:)
    选择器(ObjC) 您可以指定是否要通过选择器调用
    doTest()
    doTest(_:)
    。但是,如果将方法注释为
    @objc
    ,并使类型继承自
    NSObject
    ,则只能通过其选择器调用方法。因此,在实践中,这可能是矫枉过正

    <代码>导入基础 AA类:NSObject{ @objc func doTest(){ 打印(“a”) } } BB类:AA{ @objc func doTest(uu不同:Bool=true){ 打印(“b”) } } 设bObjc=BB() bObjc.performSelector(onMainThread:#selector(BB.doTest(:)),with:nil,waitUntilDone:true) 使用协议消除歧义 您可以通过拆分类型来帮助编译器选择正确的解决方案,其中进一步定义了
    doTest()
    doTest(\)
    。使用一个协议,然后将“代码”> doTest< /Cord>消息的接收方提交给协议,让编译器知道它应该使用协议中定义的方法。 步骤1:提取协议 议定书本身:

    协议点测试特定{
    func doTest(uu不同:Bool)
    }
    
    不幸的是,您不能在协议的方法定义中指定默认参数值。只有实现可以定义默认参数

    步骤2:使用
    BB
    类中的协议

    铸造<代码>(BOBJC为doTestApple)将告诉编译器不要考虑<代码> AA. doTest。但是,由于协议未指定默认参数,您现在必须在调用站点上提供值:

    AA级{
    func doTest(){
    打印(“a”)
    }
    }
    BB类:AA,DoTestSpecific{
    func doTest(u不同:Bool=true){
    打印(“b”)
    }
    }
    设bObjc=BB()
    (bObjc作为DoTestSpecific)。doTest(假)
    
    步骤3:将实现移动到协议扩展 cast
    (bObjc作为DoTestSpecific)
    的结果不知道
    BB
    的方法实现及其附带的默认参数值

    但是,您可以将实现移动到协议扩展,从而使实现不需要知道参数,甚至不需要知道强制转换的结果

    最终代码:

    AA级{
    func doTest(){
    打印(“a”)
    }
    }
    协议点测试特定{
    func doTest(uu不同:Bool)
    }
    扩展点特定{
    func doTest(u不同:Bool=true){
    打印(“b”)
    }
    }
    BB类:AA,DoTestSpecific{
    }
    设bObjc=BB()
    (bObjc作为DoTestSpecific).doTest()
    
    这正如预期的那样有效。它需要在协议扩展中添加协议和实现。但是现在在呼叫网站上已经没有了模棱两可的地方了


    如果示例代码更复杂,并且包含对对象状态或其他对象的依赖关系,那么实现这一点可能会更加困难甚至不可能。

    您的用例是什么?你什么时候有过这样的实现?你上面的例子是一个编译器问题这个
    func doTest(\uu不同:Bool=true)
    有一个
    func doTest()
    的变量,编译器甚至不应该编译这个代码,因为基类有一个类似的1
    func doTest(\uu不同:Bool=true)
    已声明,但有一个变量
    func doTest()
    ,您应该澄清这一点
    bObjc.doTest()