2

This is probably 2 swift questions in one...

How do I solve a situation where I want to extend an existing base class (UIView in my case) with functionality that requires stored properties? ...so that I can reuse the code for other classes?

I have tried to solve it through composition below, but I don't know if there is a more obvious way that I just can't see as I am fairly new to swift...

The second question: In my implementation I have an abstract class ManagedComponentImpl which needs an eventReceiver object which is going to be the containing UIView subclass.

The problem I have with my implementation is that swift forces me to define an object binding where Receiver:NSObject for ManagedComponentImpl, so that I can declare the optional variable eventReceiver as weak. (and I guess I would create a memory leak otherwise). However I would want to use this implementation on a variety of objects (which could of course all inherit NSObject, but they do not actually need to for other reasons but this, so it seems odd). So question number 2: Is there a way to avoid this?

EDIT: And yes! I made a mistake mixing model and view code here, but I guess the fundamental problem remains when you switch UIViewController for UIView :-)

public protocol ManagedConnection {
    var connectionKey:String { get set }
}


public protocol ManagedComponent: ConnectionObserver {
    var connectionKey:String { get set }

    func connectTo()
    func disconnectFrom()
}

public protocol EventReceiver: ConnectionObserver {
    var variableSet:Set<VariableID>? { get }
    var handleVariableUpdates: ((Set<VariableID>)->Void)? { get }
}

class ManagedComponentImpl<Receiver: EventReceiver> where Receiver:NSObject {

    public var _connectionKey: String = Shared

    //The connection Key
    public var connectionKey: String
    {
        set {
            disconnectFrom()
            self._connectionKey = newValue
            connectTo()
        }
        get {
            return _connectionKey
        }
    }

    // The  varset needed by this control
    weak var eventReceiver:Receiver!

    //  handler for the status pane variables
    //
    var connectionObserverHandlerID:UInt16 = 0
    var eventHandlerID:UInt16 = 0

    public init(receiver:Receiver) {
        self.eventReceiver = receiver
    }


    public func connectTo() {
        guard let manager = Connections.shared[self.connectionKey] else { return }
        let connection = manager.connection

        // disconnect any previous connections
        disconnectFrom()

        // Connect the connection observer
        connectionObserverHandlerID = connection.addConnectionObserver(observer: eventReceiver)

        if let variableSet = eventReceiver.variableSet, let handler = eventReceiver.handleVariableUpdates {
            eventHandlerID = connection.requestVariables(variables: variableSet, handler: handler)
        }
    }

    public func disconnectFrom(){
        guard let manager = Connections.shared[self.connectionKey] else { return }
        let connection = manager.connection

        // Disconnect
        if connectionObserverHandlerID != 0 {
            connection.removeConnectionObserver(id: connectionObserverHandlerID)
        }

        if eventHandlerID != 0 {
            connection.unRequestVariables(ident: eventHandlerID)
        }

    }

}


class ManagedUIView: UIView, ManagedComponent, EventReceiver {


    private var component:ManagedComponentImpl<ManagedUIView>!

    public var variableSet:Set<VariableID>? 
    public var handleVariableUpdates:((Set<VariableID>)->Void)?

    public override init(frame: CGRect) {
        super.init(frame: frame)
        component = ManagedComponentImpl<ManagedUIView>(receiver: self)
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        component = ManagedComponentImpl<ManagedUIView>(receiver: self)
    }

    var connectionKey:String {
        set {
            component.connectionKey = newValue
        }
        get {
            return component.connectionKey
        }
    }

    func connectTo() {
        component.connectTo()
    }

    func disconnectFrom() {
        component.disconnectFrom()
    }

    func notifyState(state: ConnectionState) {}
}

1 Answer 1

1

Okay - for everybody reading this, the answers are: - The problem should probably be solved by a delegate and not by inheritance. - To avoid inheriting from NSObject: the problem seems to be that protocols can not only be implemented by classes. Therefore the protocol needs a class limitation to work as weak references. As a result ManagedComponentImpl does not need to be generic any more and I can just have a weak CAPEvent receiver optional.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.