在Swift中,你能编写一个扩展来返回扩展所在类的类型化实例吗?

时间:2017-05-16 16:52:49

标签: swift casting swift-extensions

这是看起来足够简单的事情之一,但不能像你期望的那样工作。

我正在为我的类开发一个'流畅/链接'式的API,允许你通过可以链接在一起的函数设置属性,这样你就不必为初始化器疯狂了。此外,使用map,filter和reduce等共享同一种API的函数时,它更方便。

考虑这个RowManager扩展程序......

extension RowManager
{
    @discardableResult
    public func isVisible(_ isVisible:Bool) -> RowManager
    {
        self.isVisible = isVisible

        return self
    }
}

这完全符合人们的预期。但是这里存在一个问题......如果您正在使用RowManager的子类,则会将对象向下转发回RowManager,从而丢失所有子类特定的细节。

“不用担心!”我想。 “我只会使用Selfself来处理这种类型!”所以我把它改成了......

extension RowManager
{
    @discardableResult
    public func isVisible(_ isVisible:Bool) -> Self // Note the capitalization representing the type, not instance
    {
        self.isVisible = isVisible

        return self // Note the lowercase representing the instance, not type
    }
}

...但由于某种原因,甚至不会编译出现以下错误......

  

命令因信号失败:分段错误:11

更新

做更多研究,这似乎是因为我们的代码既包含动态库,也在动态库中使用。关于SO的其他问题也谈到了那些情况下的特定错误。也许这是编译器的一个错误,因为正如其他人正确指出的那样,这个代码在独立测试中运行良好,但是一旦在我们的代码中进行了更改,就会出现分段错误。

记住与返回该类型实例的类函数类似的东西,我回忆一下你如何使用私有泛型函数来进行实际的转换,所以我尝试将该模式与以下内容相匹配......

extension RowManager
{
    @discardableResult
    public func isVisible(_ isVisible:Bool) -> Self // Note the capitalization
    {
        self.isVisible = isVisible

        return getTypedSelf()
    }
}

private func getTypedSelf<T:RowManager>() -> T
{
    guard let typedSelfInstance = self as? T
    else
    {
        fatalError() // Technically this should never be reachable.
    }

    return typedSelfInstance
}

不幸的是,这也不起作用。

作为参考,这里是我尝试基于类的代码(className是另一个只返回你调用它的类名称的字符串表示的扩展名)...

extension UITableViewCell
{
    /// Attempts to dequeue a UITableViewCell from a table, implicitly using the class name as the reuse identifier
    /// Returns a strongly-typed optional
    class func dequeue(from tableView:UITableView) -> Self?
    {
        return self.dequeue(from:tableView, withReuseIdentifier:className)
    }

    /// Attempts to dequeue a UITableViewCell from a table based on the specified reuse identifier
    /// Returns a strongly-typed optional
    class func dequeue(from tableView:UITableView, withReuseIdentifier reuseIdentifier:String) -> Self?
    {
        return self.dequeue_Worker(tableView:tableView, reuseIdentifier:reuseIdentifier)
    }

    // Private implementation
    private class func dequeue_Worker<T:UITableViewCell>(tableView:UITableView, reuseIdentifier:String) -> T?
    {
        return tableView.dequeueReusableCell(withIdentifier: reuseIdentifier) as? T
    }
}

1 个答案:

答案 0 :(得分:0)

在WWDC Apple确认这是一个Swift编译器问题,其他东西在我们的代码库中触发,添加在任何情况下都不应该出现编译器中出现Seg11错误的情况,所以这个问题实际上是无效的。现在关闭它,但是我会报告它们是否曾经解决过它。