I want to lazy/inline implement a protocol in Swift. So in the point of the implementation I will have access to variables outside the protocol scope ,
Same as implementing a interface in Java without declaring a class:
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()
}
editing----
thanks i look at this solution, and i didn't see how to access a variable of the parent class. all the examples show an Anonymous class but no one of the examples is accessing the parent variables .
As mentioned in Swift's documentation: “You can use protocol extensions to provide a default implementation to any method or computed property requirement of that protocol.” In fact, not only can you provide a default implementation to methods or computed properties defined in the protocol, you can also add new ones.
To create a protocol, use the protocol keyword followed by the name you want and defined by the curly braces. Protocols can be of 2 types: read-only/read-write. Read-only means you can only get the variable, but you cannot set it. Read-write means you can both set and get properties.
Any class, structure or enumeration can conform to a protocol by implementing the methods and variables defined in the protocol definition. Protocols are declared using the protocol keyword.
Swift 4 allows multiple protocols to be called at once with the help of protocol composition.
What you're looking for is an inner class (not necessarily an anonymous one), declared in a scope that lets it access the count
variable of a MyClass
instance, and that adopts a protocol defined at a different scope. Right now Swift has a few of those pieces, but it doesn't look like you can put them all together in any way that's as concise as what you might be looking for.
You might think about declaring an inner class:
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()
}
}
But that won't work, because count
is implicitly self.count
, where self
is a Helper
instance, not the MyView
instance that "owns" the Helper
instance. And there isn't a way to reference that MyView
instance (or its properties) from within a Helper
's methods, because you could just as well construct a MyView.Helper()
without having an existing MyView
instance. Inner classes (or nested types in general) in Swift nest only in lexical scope, not in existential ownership. (Or to put it another way, since you referenced Java: all inner classes in Swift are like static inner classes in Java. There's no non-static inner class.) If that's a feature you'd like, though, it's probably worth telling Apple you want it.
You could also try declaring Helper
inside MyView.init()
-- in Swift you can nest type definitions anywhere, including inside functions or methods of other types. Defined there, it can refer to MyView
's properties. However, now the type information for Helper
is only visible inside of MyView.init()
, so when you assign it to someComponent.delegate
(whose type is just SomeProtocol
), you can't make use of it... this crashes the compiler, even. (That's another bug to report, but it's hard to say whether the bug is really "compiler crashes on valid usage" or "code is bad, but compiler crashes instead of producing error".)
The closest solution I can come up with looks something like this:
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 }
)
}
}
How it works:
Helper
is an inner struct (could be a class, but a struct is simpler)a0
and a1
methods, satisfying the requirements of SomeProtocol
a0
and a1
call through to the closures dec
and inc
, which are stored properties (aka instance variables) of the Helper
structHelper
instance (using the default member-wise initializer, Helper(dec: (Void -> Void), inc: (Void -> Void))
)Helper
, those closures can capture variables where you're calling the initializer, including the implicit self
that refers to the MyClass
instance creating the Helper
.You need both a0
/a1
and dec
/inc
because you need closures (the latter), not methods, for capturing the enclosing state. And even though closures and funcs/methods are in many ways interchangeable, you can't create a method/func implementation by assigning a closure to a method/func name. (It'd be a different story if SomeProtocol
required closure properties instead of methods, but I'm assuming SomeProtocol
isn't something under your control.)
Anyway, this is kind of a lot of boilerplate and a layer of abstraction that you might not really need, so it's probably worth looking into other ways to architect your code.
Note: my example uses the closure { self.count -= 1 }
where you might expect { self.count-- }
. The latter doesn't work because that's an expression with a value, so Swift will interpret it as shorthand for the closure's return value. Then it'll complain that you assigned a () -> Int
closure to a property that expects a () -> ()
(aka Void -> Void
) closure. Using -= 1
instead works around this issue.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With