Ios Lazy/inline在Swift中实现协议
我想用Swift实现一个协议。 所以在实现的时候,我可以访问协议范围之外的变量 与在Java中实现接口而不声明类相同:Ios Lazy/inline在Swift中实现协议,ios,swift,protocols,inline,lazy-evaluation,Ios,Swift,Protocols,Inline,Lazy Evaluation,我想用Swift实现一个协议。 所以在实现的时候,我可以访问协议范围之外的变量 与在Java中实现接口而不声明类相同: class MyClass:UIView { var someComponent:SomeInnerComponent = SomeInnerComponent(); var count:Int = 0; var a = :SomeProtocol { //<----- IS THIS POSSIBLE, IF YES HOW ? func a0
class MyClass:UIView {
var someComponent:SomeInnerComponent = SomeInnerComponent();
var count:Int = 0;
var a = :SomeProtocol { //<----- IS THIS POSSIBLE, IF YES HOW ?
func a0() {MyClass.count--}
func a1() {MyClass.count++}
}
someComponenet.delegate = a;
}
protocol SomeProtocol {
func a0()
func a1()
}
类MyClass:UIView{
var someComponent:SomeInnerComponent=SomeInnerComponent();
变量计数:Int=0;
var a=:SomeProtocol{/您正在寻找的是一个内部类(不一定是匿名类),在一个作用域中声明,该作用域允许它访问MyClass
实例的count
变量,并采用在不同作用域中定义的协议。目前,Swift有一些这样的片段,但看起来您无法以任何方式将它们放在一起,而这些方式可能会像您所寻找的那样简洁
您可以考虑声明一个内部类:
class MyView: UIView {
let someComponent = SomeInnerComponent() // type SomeInnerComponent is inferred
var count = 0 // type Int is inferred
class Helper: SomeProtocol {
func a0() { count-- } // ERROR
// ...
}
init() {
someComponent.delegate = Helper()
}
}
但这不起作用,因为count
隐式地是self.count
,其中self
是Helper
实例,而不是“拥有”Helper
实例的MyView
实例。而且没有方法引用该MyView
实例(或其属性)从Helper
的方法中,因为您可以构造一个MyView.Helper()
,而不需要现有的MyView
实例。Swift-nest中的内部类(或通常的嵌套类型)只在词法范围内,而不在存在所有权内。(或者换一种说法,因为您引用了Java:Swift中的所有内部类都类似于Java中的静态内部类。没有非静态内部类。)不过,如果这是您想要的特性
您还可以尝试在MyView.init()内声明Helper
--在Swift中,您可以在任何地方嵌套类型定义,包括内部函数或其他类型的方法。在那里定义的类型定义可以引用MyView
的属性。但是,现在Helper
的类型信息仅在MyView.init()中可见
,因此,当您将其分配给someComponent.delegate
(其类型仅为SomeProtocol
)时,您无法使用它……这甚至会使编译器崩溃。(这是另一种情况,但很难说该错误是否真的是“编译器在有效使用时崩溃”或“代码不好,但编译器崩溃而不是产生错误”。)
我能想到的最接近的解决方案如下:
class SomeInnerComponent {
var delegate: SomeProtocol?
}
protocol SomeProtocol {
func a0()
func a1()
}
class MyClass {
var someComponent = SomeInnerComponent()
var count = 0
struct Helper: SomeProtocol {
var dec: () -> ()
var inc: () -> ()
func a0() { dec() }
func a1() { inc() }
}
init() {
someComponent.delegate = Helper(
dec: { self.count -= 1 }, // see note below
inc: { self.count += 1 }
)
}
}
工作原理:
Helper
是一个内部结构(可以是类,但结构更简单)
- 它实现了
a0
和a1
方法,满足SomeProtocol
a0
和a1
的实现调用了闭包dec
和inc
,它们是助手
结构的存储属性(又称实例变量)
- 在构造
Helper
实例时(使用默认的成员初始值设定项Helper(dec:(Void->Void),inc:(Void->Void))
编写(或以其他方式指定)这些闭包
- 因为您可以在初始化
帮助程序时编写闭包,所以这些闭包可以捕获调用初始值设定项的变量,包括隐式self
,它引用创建帮助程序的MyClass
实例
您需要a0
/a1
和dec
/inc
,因为您需要闭包(后者),而不是方法来捕获封闭状态。即使闭包和func/方法在许多方面是可互换的,您也无法通过将闭包指定给方法/func名称来创建方法/func实现。(如果SomeProtocol
需要闭包属性而不是方法,情况就不同了,但我假设SomeProtocol
不在您的控制之下。)
无论如何,这是一种样板和抽象层,您可能并不真正需要,因此可能值得研究其他方法来构建代码
注意:我的示例使用了闭包{self.count-=1}
,您可能希望在这里使用{self.count-}
。后者不起作用,因为这是一个带值的表达式,所以Swift会将其解释为闭包返回值的缩写。然后它会抱怨您分配了()->Int
关闭一个属性,该属性需要一个()->()
(又称Void->Void
)关闭。使用-=1
可以解决这个问题。我会选择另一种方法,我知道这是一个非常古老的主题,但只是为了防止其他人遇到这个问题:
class MyClass:UIView {
var someComponent:SomeInnerComponent = SomeInnerComponent();
var count:Int = 0;
init(){
// Assign the delegate or do it somewhere else to your preference:
someComponenet.delegate = ProtocolImplementation(myClass: self);
}
private class ProtocolImplementation: SomeProtocol {
let selfReference: MyClass
init(myClass: MyClass){
selfReference = myClass
}
public func a0(){
selfReference.count--
}
public func a1(){
selfReference.count++
}
}
}
protocol SomeProtocol {
func a0()
func a1()
}
通过采用这种方法,还可以多次包含同一协议,假设您的协议支持泛型,并且您希望实现两次。如果需要,SomeProtocol和SomeProtocol都可以这样使用
请注意,关于讨论闭包的其他问题的所有答案都解决了您关于“访问协议范围外的变量”的问题闭包可以捕获和修改这些变量。谢谢,我查看了这个解决方案,但没有看到如何访问父类的变量。所有示例都显示了一个匿名类,但没有一个示例正在访问父变量。谢谢!很好的hack:),这个例子可以帮助我,为什么我需要'dec','inc'方法。我可以直接使用a0,01吗?这是swift中的限制吗?