Ios 协议扩展不';似乎没有在消费者中强制执行变量?
你说 当然,当你使用Able时 如果你忘了“v”或“x” 这是一个错误。很好。 这样做:Ios 协议扩展不';似乎没有在消费者中强制执行变量?,ios,swift,protocols,Ios,Swift,Protocols,你说 当然,当你使用Able时 如果你忘了“v”或“x” 这是一个错误。很好。 这样做: protocol Able: class { var v:UIView? { get set } var x:CGFloat { get set } } 一切都好。太好了 您必须指定“v”和“x”,并对它们进行初始化 但是。试试这个 class ScreenThing: UIViewController, Able { @IBOutlet var v: UIView? v
protocol Able: class {
var v:UIView? { get set }
var x:CGFloat { get set }
}
一切都好。太好了
您必须指定“v”和“x”,并对它们进行初始化
但是。试试这个
class ScreenThing: UIViewController, Able {
@IBOutlet var v: UIView?
var x: CGFloat = 0.0
}
Able现在有一个属性p
您可以在Able中的函数或ScreenThing中的函数中完美地使用p。太好了
然而
当你这样做的时候
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”(它将崩溃)
实际上,您不必将“p”指定为变量(必须使用“v”和“x”)
为什么会这样
这似乎是个大问题
我是否需要做一些不同的事情,让编译器强制执行“p”,就像它通常强制协议中的变量一样
另一种看待这个问题的方式是: 鉴于我的上述代码: 有没有办法强制编译器在consumer类中需要“p”的初始值设定项 比如说 我试过这个
class ScreenThing: UIViewController, Able {
}
但这不起作用
(奇怪的是,它可以编译-实际上我不知道它到底在做什么!它似乎与扩展中的p“不同”了。但无论如何,它并不强制要求使用初始值设定项。)
简言之,在上面,我是否可以做或添加一些事情,使编译器强制我初始化伪属性,就像我在协议中放置属性(如“x”或“v”)时通常做的那样
?
- 也许我必须在协议中添加一些普通属性(比如“pp”),并以某种方式使p与之相关??只是一个想法
(脚注——请参见以了解上述协议中所需的“:class”。)
回答我自己的问题: 我上面的困惑是,没有什么可以初始化的。扩展中的
var p:p
(带有get和set代码块)只是两个函数
没有什么需要初始化的
例如:在我的额外问题中,我问“如何强制一致性类在唤醒时初始化它?”这是毫无意义的。如果有什么问题的话,我们可以问:“如何强制一致性类确保在唤醒时‘使用那些函数’?——这与初始化无关
还请注意,我在计算变量中的具体示例代码碰巧(非最近)使用了一个未初始化的变量,这导致了混淆。您不必在协议的采纳器中实现
p
,因为协议扩展提供了一个实现。这就是协议扩展
更简单的例子:
class ScreenThing: UIViewController, Able {
var p:P
}
注意,(1)即使C不声明
greet
也会编译,(2)即使C不包含greet
的实现也会运行。这是因为这是协议扩展的工作。我不确定您希望编译器做什么-p
不是协议要求(即使是,您已经将默认实现作为计算属性提供给它),那么,您希望编译器在screenshing
中强制您实现什么呢?Swift是一种相对较新的语言,编译器在某些情况下充满了bug。我会提交一份bug报告,看看苹果有什么要说的。@JoeBlow你说的“get set成语”是一个,实际上只不过是一对方法,加上一些语法糖,使它们看起来像一个属性。不需要进行初始化,因为属性p
没有存储空间(同样,只是美化的方法)。您必须初始化v
和x
,因为它们是存储属性,因此它们具有Swift可以强制执行的内存initialise@JoeBlow(续)Swift不会强制您初始化关联的对象,因为它是在Objective-C运行时实现的–由您来确保它有一个值(或者更好,你可以添加一些逻辑来处理objc_getassociated object
返回nil
)的情况。你的更新没有为我编译@JoeBlow–Swift抱怨没有初始值设定器(应该如此)。而且p
一开始甚至不是协议要求;)@Hamish我的看法不同。对我来说,协议扩展材料是一项要求,但它也满足了要求。这是一个自我满足的要求!:)毕竟,如果在实际的协议中列出了greet
,同样的事情也会发生。我的代码的第一行可以是协议P{func greet()}
,但这不会改变任何东西;扩展提供了实现。是的–这实际上只是您答案的第一行,提示了您的评论(可能更多的是吹毛求疵),因为它在某种程度上暗示,如果协议扩展没有提供实现,然后,您必须在协议采纳者中实现p
),但请注意,在实际的协议声明中包含需求本身有一些微妙之处(我相信您可能知道)。这样做,您就将其包括在一致性类型的协议见证表中,在调用作为协议类型的值的协议要求时,允许您动态调度。@matt-这是一个边缘案例,但是,如果建议人们在协议扩展中实现默认实现,而不显式地将该方法声明为协议的一部分,我会很谨慎。如果将此协议用作类型(这是一种常见模式),它将不会调用此默认实现的荣誉覆盖。有关此问题的示例,请参见。注意,这只是一个问题,如果您可能会覆盖默认实现,但我会小心不要显式声明需求。@Rob I d
protocol P {}
extension P {
func greet() {print("hello")}
}
class C : P {}
C().greet()