协议扩展中的快速闭包

问题描述 投票:0回答:3

我想装饰 UIViewController,使其能够在从另一个类(例如网络状态管理器)调用

setInteractionEnabled
方法时调整其界面。所有更改(如果有)应通过覆盖
onInteractionChanged
在具体控制器中提供。这是我的代码:

import Foundation

typealias InteractionClosure = ((enabled: Bool) -> Void)

protocol Interaction: class {

    var onInteractionChanged: InteractionClosure? { get set }

    func setInteractionEnabled(enabled: Bool)

}

extension Interaction where Self: UIViewController {

    // Default: Do nothing
    // Throws: - Extensions may not contain stored properties
    var onInteractionChanged: InteractionClosure? = nil

    func setInteractionEnabled(enabled: Bool) {
        onInteractionChanged?(enabled: enabled)
    }

}

extension UIViewController : Interaction {}

如何添加默认实现

onInteractionChanged

ios swift protocols
3个回答
4
投票

回答我自己的问题通常是我不做的事情,但这是我的解决方案:

typealias InteractionClosure = (enabled: Bool) -> Void

protocol Interaction: class {

    func addOnInteractionChanged(closure: InteractionClosure)
    func setInteractionEnabled(enabled: Bool)

}

extension Interaction where Self: UIViewController {

    func addOnInteractionChanged(closure: InteractionClosure) {
        onInteractionChanged = closure
    }

    func setInteractionEnabled(enabled: Bool) {
        onInteractionChanged?(enabled: enabled)
    }

    // MARK: - Private

    private var onInteractionChanged: InteractionClosure? {
        get {
            let wrapper =
                objc_getAssociatedObject(self, &icAssociationKey) as? ClosureWrapper
            return wrapper?.closure
        }
        set(newValue) {
            objc_setAssociatedObject(self,
                                     &icAssociationKey,
                                     ClosureWrapper(newValue),
                                     .OBJC_ASSOCIATION_RETAIN)
        }
    }

}

extension UIViewController : Interaction {}

// Helpers

private var icAssociationKey: UInt8 = 0

private class ClosureWrapper {
    var closure: InteractionClosure?

    init(_ closure: InteractionClosure?) {
        self.closure = closure
    }
}

客户端类:

class LoginViewController: UIViewController {

    // MARK: - Lifecycle

    override func viewDidLoad() {
        super.viewDidLoad()
        self.setup()
    }

    // MARK: - Private

    private func setup() {
        // ...

        addOnInteractionChanged { [unowned self] (enabled) in            
            self.signInButton.enabled = enabled
            self.activityIndicatorView.hidden = !enabled
        }
    }

}

经理班:

visibleViewController?.setInteractionEnabled(true)

3
投票

如果您希望属性仅具有

{ get }
能力,您可以使用:

protocol TestProtocol {
    var testClosure: ((_ parameter: Bool) -> Void)? { get }
}

extension TestProtocol {
    var testClosure: ((_ parameter: Bool) -> Void)? {
        return { parameter in
            print(parameter)
        }
    }
}

0
投票

在协议中使用闭包的现代-Swift 紧凑方式如下

typealias InteractionClosure = (Bool) -> Void

protocol Interaction {
    var interactionClosure: InteractionClosure? { get set }
}


class SomeViewController: UIViewController { }

extension SomeViewController: Interaction {
    
    private struct AssociatedKeys {
        static var interactionClosure: UInt8 = 0
    }

    var interactionClosure: InteractionClosure? {
        get {
            let wrapper =
            objc_getAssociatedObject(self, &AssociatedKeys.interactionClosure) as? InteractionClosure
            return wrapper
        }
        set(newValue) {
            objc_setAssociatedObject(self, &AssociatedKeys.interactionClosure, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
}

这里我们没有任何全局变量和补充函数。

并且我们不使用默认实现的协议扩展,因为我们需要将此闭包设置为不同的

UIViewController
实例。

如果我们使用全局 var 作为关联值的键,那么我们将用第二个实例覆盖第一个实例的闭包设置器。

默认实现也不是那么明显,大多数时候必须与

self
上下文相关联(只有全局抽象默认值是好的)。

© www.soinside.com 2019 - 2024. All rights reserved.