2014-09-06 18 views
6

我想懒/ inline在Swift中实现一个协议。 所以我将有机会获得该协议范围以外的变量的执行点,懒/ inline在Swift中实现一个协议

同用Java实现一个接口不声明类:

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() 
} 

编辑----

谢谢我看这个解决方案,我没有看到如何访问父类的变量。 所有示例都显示Anonymous类,但没有一个示例访问父变量。

+0

注意,所有上讨论关闭其他问题的答案还解决您的问题关于“获得变数协议范围之内。”闭包可以捕获和修改这些变量。 – 2014-09-07 02:38:09

+0

谢谢我看这个解决方案,我没有看到如何访问父类的变量。 所有示例都显示Anonymous类,但没有一个示例访问父变量。 – 2014-09-07 17:43:22

回答

3

你要找的是一个内部类(不一定是匿名的),它在一个范围内声明,它允许它访问变量的MyClass实例,并且采用在不同范围定义的协议。现在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,其中selfHelper实例,而不是MyView实例“拥有” Helper实例。并且没有办法从Helper的方法中引用该实例(或其属性),因为您可以在没有现有的MyView实例的情况下构建MyView.Helper()。 Swift中的内部类(或通常嵌套类型)只能在词法范围内嵌套,而不能在存在所有权中嵌套。 (换句话说,因为你引用了Java:Swift中的所有内部类都像Java中的静态内部类,没有非静态的内部类。)如果这是你想要的功能,但是,it's probably worth telling Apple you want it

你也可以尝试在MyView.init()里面声明Helper - 在Swift中,你可以在任何地方嵌套类型定义,包括函数内部或其他类型的方法。在那里定义,它可以参考MyView的属性。但是,现在Helper的类型信息仅在MyView.init()内部可见,所以当您将其分配给someComponent.delegate(其类型仅为SomeProtocol)时,您无法使用它......甚至导致编译器崩溃。 (这是另一个bug to report,但很难说错误是真的“编译器崩溃的有效用法”或“代码不好,但编译器崩溃,而不是产生错误”。)

最接近的解决方案,我能想出看起来是这样的:

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是内部结构(可能是一类,而是一个结构是更简单)
  • 它实现了a0a1方法,满足的要求SomeProtocol
  • 个该的a0实现a1电话接到关闭decinc,这是本Helper结构的存储特性(又名实例变量)
  • 当你构建一个Helper实例(使用你写的(或规定),这些关闭默认成员明智的初始化,Helper(dec: (Void -> Void), inc: (Void -> Void))
  • 因为你可以初始化Helper时写的封锁,关闭那些可以捕捉你在哪里调用初始化变量,包括指MyClass实例创建Helper隐含self

同时需要a0/a1dec/inc,因为你需要关闭(后者),而不是方法,捕捉封闭状态。即使闭包和funcs /方法在很多方面是可以互换的,但是你不能通过给方法/ func名称赋一个闭包来创建一个方法/ func实现。 (这将会是一个不同的故事,如果需要封闭性的,而不是方法SomeProtocol,但我假设SomeProtocol是不是你的控制之下的东西。)

无论如何,这是一种很多的样板和一层您可能并不真正需要的抽象,因此可能需要寻找其他方法来构建代码。


注:我的例子中使用了封闭{ self.count -= 1 }下,您可能希望{ self.count-- }。后者不起作用,因为这是一个带有值的表达式,所以Swift会将其解释为闭包返回值的简写。然后它会抱怨说,您为() ->()(又名Void -> Void)关闭的房产分配了() -> Int闭合。改用-= 1来解决这个问题。

+0

谢谢!,很好的黑客:),这个例子可以为我服务,为什么我需要'dec','inc'方法。我可以直接使用a0,01吗?这是一个快速的限制吗? – 2014-09-09 22:22:36

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 < SomeObject>和SomeProtocol <如果需要,可以同时使用这种方式。

亲切的问候