冗余约束:'Self':'AnyObject'

5

我有这个协议:

protocol Container: class where Self: UIViewController {
    var containerView: UIView! { get }
    var currentChild: UIViewController? { get set }
    func remove(child viewController: UIViewController)
    func add(child viewController: UIViewController)
    func replaceCurrentViewController(with newChild: UIViewController)
}

我面临的问题是它显示以下警告:

Redundant constraint 'Self' : 'AnyObject'

这是因为我同时使用了classwhere Self: UIViewController,但我需要两者!原因在于我的协议扩展(如下所示)中使用了UIViewController方法。如果我删除class,我的扩展将显示一个错误,要求添加mutating,但这不应该出现,因为它只是一个类协议。
extension Container {
    func remove(child viewController: UIViewController) {
        viewController.beginAppearanceTransition(false, animated: true)
        viewController.willMove(toParent: nil)
        viewController.removeFromParent()
        viewController.view.removeFromSuperview()
        viewController.endAppearanceTransition()
        currentChild = nil
    }

    func add(child viewController: UIViewController) {
        viewController.beginAppearanceTransition(true, animated: true)
        addChild(viewController)
        viewController.didMove(toParent: self)
        containerView.addSubview(viewController.view)
        viewController.view.frame = containerView.frame
        viewController.endAppearanceTransition()
        currentChild = viewController
    }

    func replaceCurrentViewController(with newChild: UIViewController) {
        if viewIfLoaded != nil, let currentChild = currentChild {
            if let parent = currentChild.parent, parent == self {
                remove(child: currentChild)
            }
            add(child: newChild)
        }
    }
}

那么,有更好的解决方案吗?我能消除这个警告吗?

将方法声明为mutating有什么问题? - Sweeper
1
问题在于这个协议只适用于视图控制器,而我在变量的didset中使用了其中的一个方法,会出现一个错误要求我将didset变为mutating。但是在这样做之后,又会显示另一个错误,说mutating仅适用于函数。 - naif
你能展示一下 didSet 中的代码吗? - Sweeper
下载最新的工具链 https://swift.org/download/(Trunk Development(master)),我认为您不需要额外的约束。 - J. Doe
2个回答

3
在Swift 4中,你可以使用:


protocol Container where Self: UIViewController {
    var containerView: UIView! { get }
    var currentChild: UIViewController? { get set }
    func remove(child viewController: UIViewController)
    func add(child viewController: UIViewController)
    func replaceCurrentViewController(with newChild: UIViewController)
}

Swift 5中,您可以使用以下语法来:
protocol Container: UIViewController {
    var containerView: UIView! { get }
    var currentChild: UIViewController? { get set }
    func remove(child viewController: UIViewController)
    func add(child viewController: UIViewController)
    func replaceCurrentViewController(with newChild: UIViewController)
}

3

应该将 where 子句放在 extension 中,并在其中放置具有默认实现的 UIViewController 特定方法,以便仅有 UIViewController 可以访问这些方法。

protocol Container: class {
    var containerView: UIView! { get }
    var currentChild: UIViewController? { get set }
}

extension Container where Self: UIViewController {
    func remove(child viewController: UIViewController) {
        viewController.beginAppearanceTransition(false, animated: true)
        viewController.willMove(toParent: nil)
        viewController.removeFromParent()
        viewController.view.removeFromSuperview()
        viewController.endAppearanceTransition()
        currentChild = nil
    }

    func add(child viewController: UIViewController) {
        viewController.beginAppearanceTransition(true, animated: true)
        addChild(viewController)
        viewController.didMove(toParent: self)
        containerView.addSubview(viewController.view)
        viewController.view.frame = containerView.frame
        viewController.endAppearanceTransition()
        currentChild = viewController
    }

    func replaceCurrentViewController(with newChild: UIViewController) {
        if viewIfLoaded != nil, let currentChild = currentChild {
            if let parent = currentChild.parent, parent == self {
                remove(child: currentChild)
            }
            add(child: newChild)
        }
    }
} 

我考虑过这个问题,但我想将我的协议限制为仅由视图控制器实现,以便其他类不能实现此协议。只是尽可能正确地使用静态类型。 - naif
@naif 是的,正如 matt 的答案中所提到的,在Swift中这是一个问题。但如果您确实需要放置该限制,则可以通过引入 associatedtype 来实现。 - Kamran
1
我建议你将上面的remove()add()replaceCurrentViewController()从协议要求中删除,并将它们作为扩展方法(而不是默认实现)。真正的协议要求只有containerViewcurrentChild - Rob Napier
1
@naif:“我想将我的协议限制为只能由视图控制器实现,以便其他类不能实现此协议。” 这种理解是错误的,并且没有充分利用静态类型。 协议是要求的描述,而不是对特定实现的要求。 如果必须是 UIViewController,那么 Container 应该是 UIViewController 的子类,而不是协议。 (但是在这里使用协议可能是可以的,根据 Kamran 的示例,它不需要是视图控制器。) - Rob Napier

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