Lazy / inline implements protocol in Swift

I want lazy / inline to implement the protocol in Swift. Therefore, at the time of implementation, I get access to variables outside the scope of the protocol,

Same as Java interface implementation without class declaration:

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

edit ----

thanks, I am looking at this solution and I have not seen how to access the variable of the parent class. all examples show an anonymous class, but none of the examples access parent variables.

+6
source share
2 answers

What you are looking for is an inner class (not necessarily anonymous) declared in a scope that allows it to access the count variable of the MyClass instance and accepts a protocol defined in a different scope. Swift has a few of these right now, but it doesn't look like you can put them all together in any compressed form you might be looking for.

You might consider 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 this will not work, because count implicitly self.count , where self is an instance of Helper , and not an instance of MyView that "owns" an instance of Helper . And there is no way to reference this instance of MyView (or its properties) from Helper methods, because you could just build MyView.Helper() without having an existing instance of MyView . Inner classes (or nested types in general) in Swift nest only in the lexical domain, and not in existential property. (Or, to put it another way, since you are referencing Java: all inner classes in Swift are static inner classes in Java. There is no non-static inner class.) If you need this function, you might want to tell Apple that you want it .

You can also try declaring Helper inside MyView.init() - in Swift you can insert type definitions anywhere, including internal functions or methods of other types. Defined there, it can refer to MyView properties. However, now type information for Helper is visible only inside MyView.init() , so when you assign it to someComponent.delegate (whose type is just SomeProtocol ), you cannot use it ... it's even a compiler failure. (This is another error , but itโ€™s hard to say whether the error is โ€œcompiler crashes on actual useโ€ or โ€œcode is bad,โ€ but the compiler crashes rather than creating an error. ")

The closest solution I can come up with is 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 - internal structure (may be a class, but structure is simpler)
  • It implements methods a0 and a1 that satisfy SomeProtocol requirements
  • Implementations a0 and a1 close dec and inc , which are stored properties (like instance variables) of the Helper struct
  • You record (or otherwise indicate) these closures when creating an instance of Helper (using the default initializer, Helper(dec: (Void -> Void), inc: (Void -> Void)) )
  • Because you can write closures during Helper initialization, these locks can capture the variables in which you invoke the initializer, including the implicit self , which refers to the MyClass instance that creates the Helper .

You need both a0 / a1 and dec / inc , because you need to close (the last), not the methods, to capture the on state. Although locks and funcs / methods are largely interchangeable, you cannot create an implementation of the / func method by assigning a closure to the / func method name. (It would be different if SomeProtocol required a closure property instead of methods, but I assume SomeProtocol not under your control.)

In any case, this is a kind of many templates and an abstraction layer that you might not need, so itโ€™s probably worth exploring other ways to archive your code.


Note. My example uses closure { self.count -= 1 } , where you can expect { self.count-- } . The latter does not work because the expression is with a value, so Swift will interpret it as a shorthand for the return value of the closure. He then complains that you have assigned a closure () -> Int to the property that is awaiting closure () -> () (aka Void -> Void ). Using -= 1 instead works around this issue.

+3
source

I would go for a different approach, I know this is a pretty old topic, but just in case, someone else is struggling with this problem:

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

Following this approach, you can also enable the same protocol several times, say your protocol supports the general one and you want to implement it twice. SomeProtocol <SomeObject> and SomeProtocol <OtherObject> can be used this way if necessary.

Yours faithfully

+1
source

Source: https://habr.com/ru/post/974922/


All Articles