协议的Swift扩展存储

时间:2016-01-21 20:44:13

标签: swift

我制定了一个协议:

protocol SomeProtocol {
    func getData() -> String
}

我创建了一个符合它的结构:

struct SomeStruct: SomeProtocol {
    func getData() -> String {
        return "Hello"
    }
}

现在我希望每个UIViewController都有一个名为source的属性,所以我可以做类似......

class MyViewController : UIViewController {
    override func viewDidLoad() {
        self.title = source.getData()
    }
}

为实现这一目标,我创建了一个协议来定义属性:

protocol SomeProtocolInjectable {
    var source: SomeProtocol! { get set }
}

现在我只需要使用以下属性扩展视图控制器:

extension UIViewController: SomeProtocolInjectable {
    // ???
}

如何将存储的属性与协议类型一起破解?

什么没有用:

还有其他建议吗?

3 个答案:

答案 0 :(得分:3)

您可以使用静态和视图控制器hash

进行攻击
struct SomeProtocol {/*....*/}

struct DataProxy {
    var data: [Int: SomeProtocol]
}



protocol SomeProtocolInjectable {
    var source: SomeProtocol! { get set }
}

extension UIViewController: SomeProtocolInjectable {

    static var dataProxy = DataProxy(data: [:])

    var source: SomeProtocol! {
        get{
            return UIViewController.dataProxy.data[self.hashValue]
        }
        set{
            UIViewController.dataProxy.data[self.hashValue] = newValue
        }
    }

}

答案 1 :(得分:3)

任何协议对象都可以转换为类型擦除类。构建AnySomeProtocol并存储该内容。

private var sourceKey: UInt8 = 0

final class AnySomeProtocol: SomeProtocol {
    func getData() -> String { return _getData() }
    init(_ someProtocol: SomeProtocol) { _getData = someProtocol.getData }
    private let _getData: () -> String
}

extension UIViewController: SomeProtocolInjectable {
    var source: SomeProtocol! {
        get {
            return objc_getAssociatedObject(self, &sourceKey) as? SomeProtocol
        }
        set(newValue) {
            objc_setAssociatedObject(self, &sourceKey, AnySomeProtocol(newValue), .OBJC_ASSOCIATION_RETAIN)
        }
    }
}

class MyViewController : UIViewController {
    override func viewDidLoad() {
        self.title = source.getData()
    }
}

调用者只能使用它来访问协议方法。你不能用as强制它恢复原来的类型,但无论如何你应该避免这种情况。

作为旁注,我建议source返回SomeProtocol?而不是SomeProtocol!。这里没有任何承诺source将被设定。你甚至不能在viewDidLoad之前设置它。

答案 2 :(得分:0)

如何为> percent(c(0.123,0.00234)) [1] "12.3%" "0.2%" 添加默认实现,为协议提供虚拟结构实现,并将其用作getData()变量的默认值:

source

我冒昧地扩展protocol SomeProtocol { func getData() -> String } extension SomeProtocol { func getData() -> String { return "Hello" } } protocol SomeProtocolInjectable { var source: SomeProtocol { get set } } struct DummyProtocolImplementation: SomeProtocol { } class MyViewController : UIViewController { var _source: SomeProtocol = DummyProtocolImplementation() override func viewDidLoad() { self.title = source.getData() } } extension MyViewController: SomeProtocolInjectable { var source: SomeProtocol { get { return _source } set { _source = newValue } } } 而不是MyViewController,因为后者无论如何都不知道协议。