协议扩展似乎不会在消费者中强制执行变量?

时间:2017-01-22 22:47:05

标签: ios swift protocols

说你

protocol Able: class {
    var v:UIView? { get set }
    var x:CGFloat { get set }
}

当然,当你使用Able时,

enter image description here

如果忘记“v”或“x”......

这是一个错误。这很好。

这样做:

class ScreenThing: UIViewController, Able {
    @IBOutlet var v: UIView?
    var x: CGFloat = 0.0
}

一切都很好。那很好。

强制您指定“v”和“x”并确实初始化它们。

但是。试试这个......

var _H: UInt8 = 0

protocol Able: class {
}

extension Able where Self:UIViewController {

    var p:P {
    get {
        return objc_getAssociatedObject(self, &_H) as! P
        }
    set {
        objc_setAssociatedObject(self, &_H, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        __setter()
        }
    }
}

现在有一个属性p。

您可以在Able中的函数中完美地使用p,或者在ScreenThing中的函数中使用p。那很好。

然而.....

当你这样做时......

class ScreenThing: UIViewController, Able {
}

收到错误。

你可以忘记初始化“p”(它会崩溃)。

实际上,您不必将“p”指定为变量(因为必须使用“v”和“x”)。

为什么会这样?

这似乎是个大问题。

我是否需要做一些不同的事情,让编译器强制执行“p”,就像它当然通常会在协议中强制执行变量一样?

另一种看待这个问题的方法:

完全按照上面的代码:

有没有办法强制编译器在消费者类中需要“p”的初始值设定项?

例如。

我试过了......

class ScreenThing: UIViewController, Able {
    var p:P
}

但这不起作用。

(奇怪的是,编译 - 实际上我不知道它到底在做什么!它似乎是与扩展中的p“不同”的p。但无论如何它都没有强制执行需要初始化程序。)

简而言之,上面是否有一些我可以做或添加的内容,这会让编译器强制我初始化伪属性,就像我在协议中放置属性时通常会这样做作为“x”或“v”。

  • 也许我必须在协议中添加一些普通的属性(比如“pp”),并以某种方式使p与之相关?只是一个想法。

(脚注 - 请参阅this以了解上述协议中所需的“:class”。)

回答我自己的问题:

我上面的困惑是没有什么可以初始化。扩展程序中的var p:P (带有get和set代码块)只是两个函数。

无需初始化。

所以例如:在我的额外问题中,我问“如何强制符合要求的类在唤醒时启动它?”这毫无意义。如果有的话,人们可以问:“如何迫使合格的班级确保'唤醒时使用这些功能'?” - 与初始化无关。

另请注意,我在计算变量中的具体示例代码恰好(无关地)使用了未初始化的变量 - 导致混淆。

1 个答案:

答案 0 :(得分:1)

您不必在协议的采用者中实施p,因为协议扩展已提供了实施。这就是协议扩展

更简单的例子:

protocol P {}
extension P {
    func greet() {print("hello")}
}
class C : P {}
C().greet()

注意,(1)即使C没有声明greet也会编译,并且(2)它会运行,即使C不包含greet的实现。那是因为这是协议扩展的工作。