在Swift中闭包如何调用父类函数(super)

16

我想要将一个函数链接到父类的实现上,就像以下示例一样:

class BaseClass {
  func myFunc() {
    // do something
  }
}

class MyClass: BaseClass {
  override func myFunc() {
    self.myOtherFunc(completionHandler: {
      super.myFunc() // error: 'super' members cannot be referenced in a non-class type
    })
  }
  ...
}

编译错误实际上清楚地告诉我原因:闭包不是类类型,不允许使用。寻求任何建议,如何调用在父类中定义的方法?


我认为这是一个bug,因为如果self可用,那么super也应该可用,因为super只是使用不同的方法查找方案调用的self - newacct
但是方法查找方案是“从此方法所属的类下面开始查找”,而这个信息在闭包中并不存在。 - gnasher729
这真的感觉像是那种“仅仅因为你能够做到,并不意味着你应该这样做”的情况。但它有着迷人的含义。如果你将超类调用推迟到类构造函数中会发生什么?这让人难以想象。 - Shayne
3个回答

23
更新:从Swift 1.2 b3开始,这个问题已经修复 - 原始代码可以按预期工作。耶,进步!
class BaseClass {
    func myFunc() {
        println("BaseClass.myFunc()")
    }
}

class MyClass: BaseClass {
    func myOtherFunc(c: () -> ()) {
        c()
    }

    override func myFunc() {
        println("MyClass.myFunc()")
        self.myOtherFunc {
            super.myFunc()
        }
    }
}

MyClass().myFunc()
// MyClass.myFunc()
// BaseClass.myFunc()

理想情况下,您可以只写:


class MyClass: BaseClass {
  override func myFunc() {
    let superFunc = super.myFunc
    self.myOtherFunc(completionHandler: {
      superFunc()
    })
  }
}

但是这并不起作用,它只是调用了self.myFunc()。我前几天在推特上发了一条推文,得到了一个Swift开发者的回复,说这是一个已知的bug。唯一的解决方法是使用另一种方法将调用传递给super:
class MyClass: BaseClass {
  override func myFunc() {
    self.myOtherFunc(completionHandler: {
      self.callSuperMyFunc()
    })
  }

  func callSuperMyFunc() {
    super.myFunc()
  }
}

我想给Nat和Rintaro都正确的答案。由于我只能选择一个,我喜欢“kinda”建议的命名临时解决方法:现在,我将其命名为superMyFunc(用于super.myFunc)。然而,Rintaro对于命名也有他的观点。无论如何,知道这是一个临时性的错误肯定是好的。 - Sean

6
这个回答可能并没有解决你的问题...
令人惊讶的是,下面的代码会导致无限递归调用。可能是一个bug吗?
class MyClass: BaseClass {
    override func myFunc() {
        let superMyFunc = super.myFunc
        self.myOtherFunc(completionHandler: {
            superMyFunc() // this actually calls MyClass.myFunc
            return
        })
    }
}

// ALSO
class MyClass: BaseClass {
    override func myFunc() {
        let superMyFunc = BaseClass.myFunc(self as BaseClass)
        self.myOtherFunc(completionHandler: {
            superMyFunc() // this actually calls MyClass.myFunc
            return
        })
    }
}

我找到的唯一解决方法是定义另一个方法:
class MyClass: BaseClass {
    override func myFunc() {
        self.myOtherFunc(completionHandler: {
            self.callSuperMyFunc()
            return
        })
    }
    func callSuperMyFunc() {
        super.myFunc()
    }
}

但是,我认为你应该使用另一个方法名:

class MyClass: BaseClass {
    func myFuncAsync() {
        self.myOtherFunc(completionHandler: {
            self.myFunc()
            return
        })
    }
}

谢谢您的建议!创建一个帮助方法来调用super确实是这里应该采取的方法,因为仍然没有办法弱化捕获super(需要逃逸闭包)。 - fredpi

0
我使用下面的方法:
let parentFunction = super.function
functionWithClosure {
    parentFunction()
}

这对我很有效。使用Swift 5.3版本,我仍然遇到了这个问题。一个小缺点是,因为parentFunction现在是一个闭包,所以你必须去掉参数标签。 - Chris Prince
1
这段代码在将parentFunction变量赋值时,会导致super.function执行吗? - Adam
不,因为函数本身被分配给parentFunction(就像对一个函数的引用)。 - Nikaaner
1
@Adam 是的,我遇到了这个问题:当向parentFunction赋值时,会导致super.function执行。 - Ratan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接