I want to know what do you think about the structure of this code. If you think that there is some structural improvement to be made, tell me!Here is a github link: https://github.com/LucianoPolit/LPDropdownMenuHere is the code:////  LPDropdownMenu.swift//  Created by Luciano Polit on 1/8/16.//  Copyright (c) 2016 Luciano Polit. All rights reserved.//import UIKit@objc protocol LPDropdownMenuViewDelegate {    optional func dropdownMenuView(dropdownMenuView: LPDropdownMenuView, shouldSwipeToPosition position: CGFloat) -> Bool    optional func dropdownMenuView(dropdownMenuView: LPDropdownMenuView, shouldTouchToPosition position: CGFloat) -> Bool    optional func dropdownMenuView(dropdownMenuView: LPDropdownMenuView, shouldDoubleTouchToPosition position: CGFloat) -> Bool    optional func dropdownMenuView(dropdownMenuView: LPDropdownMenuView, shouldAproximateToPosition position: CGFloat) -> Bool    optional func dropdownMenuView(dropdownMenuView: LPDropdownMenuView, shouldFinishSlidingAtPosition position: CGFloat) -> Bool    optional func dropdownMenuView(dropdownMenuView: LPDropdownMenuView, willSwipeToPosition position: CGFloat)    optional func dropdownMenuView(dropdownMenuView: LPDropdownMenuView, willTouchToPosition position: CGFloat)    optional func dropdownMenuView(dropdownMenuView: LPDropdownMenuView, willDoubleTouchToPosition position: CGFloat)    optional func dropdownMenuView(dropdownMenuView: LPDropdownMenuView, willAproximateToPosition position: CGFloat)    optional func dropdownMenuView(dropdownMenuView: LPDropdownMenuView, willFinishSlidingAtPosition position: CGFloat)    optional func dropdownMenuView(dropdownMenuView: LPDropdownMenuView, didSwipeToPosition position: CGFloat)    optional func dropdownMenuView(dropdownMenuView: LPDropdownMenuView, didTouchToPosition position: CGFloat)    optional func dropdownMenuView(dropdownMenuView: LPDropdownMenuView, didDoubleTouchToPosition position: CGFloat)    optional func dropdownMenuView(dropdownMenuView: LPDropdownMenuView, didAproximateToPosition position: CGFloat)    optional func dropdownMenuView(dropdownMenuView: LPDropdownMenuView, didFinishSlidingAtPosition position: CGFloat)    optional func dropdownMenuView(dropdownMenuView: LPDropdownMenuView, didStartMovingAtPosition position: CGFloat)    optional func dropdownMenuView(dropdownMenuView: LPDropdownMenuView, didFinishMovingAtPosition position: CGFloat)}class LPDropdownMenuView: UIView {    private var panGestureRecognizer: UIPanGestureRecognizer!    private var tapGestureRecognizer: UITapGestureRecognizer!    private var doubleTapGestureRecognizer: UITapGestureRecognizer!    private var movingCondition: Bool = false    var delegate: LPDropdownMenuViewDelegate?    var freeSlideable: Bool = true    var swipeable: Bool = true    var touchable: Bool = true    var doubleTouchable: Bool = true    var autoSetProperties: Bool = true    var marginProximity: CGFloat = 50    var swipeSensibility: CGFloat = 600    var minPosition: CGFloat!    var maxPosition: CGFloat!    var contentFrame: CGRect! {        didSet {            setProperties()        }    }    var barView: UIView! {        willSet {            if (self.barView != nil) {                self.barView.removeFromSuperview()            }        }        didSet {            let height = barView.frame.size.height + (contentFrame.maxY - barView.frame.maxY)            frame = CGRectMake(barView.frame.origin.x, barView.frame.origin.y, barView.frame.size.width, height)            barView.frame.origin.y = 0            addSubview(barView)            setPosition(frame.origin.y)            setProperties()            setGestures()        }    }    var menuView: UIView! {        willSet {            if (self.menuView != nil) {                self.menuView.removeFromSuperview()            }        }        didSet {            if (!(menuView is UIScrollView)) {                let newValue = menuView                newValue.frame.origin.y = 0                let height = frame.size.height - barView.frame.size.height                menuView = UIScrollView(frame: CGRectMake(0, barView.frame.size.height, newValue.frame.size.width, height))                (menuView as! UIScrollView).contentSize = CGSize(width: newValue.frame.size.width, height: newValue.frame.size.height)                (menuView as! UIScrollView).bounces = false                menuView.addSubview(newValue)            } else {                let height = frame.size.height - barView.frame.size.height                menuView.frame = CGRectMake(0, barView.frame.size.height, menuView.frame.size.width, height)            }            addSubview(menuView)        }    }    init (frame: CGRect, barView: UIView, menuView: UIView) {        super.init(frame: frame)        self.contentFrame = frame        initView(barView, menuView: menuView)    }    override init(frame: CGRect) {        super.init(frame: frame)        self.contentFrame = frame        let barView = DefaultBarView(frame: CGRectMake(0, frame.size.height - 60, frame.size.width, 60))        let menuView = DefaultMenuView(frame: CGRectMake(0, barView.frame.size.height, frame.size.width, 600))        initView(barView, menuView: menuView)    }    required init?(coder aDecoder: NSCoder) {        fatalError(init(coder:) has not been implemented)    }    private func initView(barView: UIView, menuView: UIView) {        self.initGestures()        self.barView = barView        self.menuView = menuView    }}extension LPDropdownMenuView {    func getPosition() -> CGFloat {        return frame.origin.y    }    func setProperties() {        if (contentFrame != nil && autoSetProperties) {            minPosition = contentFrame.maxY / 3            maxPosition = contentFrame.maxY - barView.frame.size.height        }    }    func setPosition(position: CGFloat) {        self.frame.origin.y = position        self.frame.size.height = self.contentFrame.size.height - position        if (menuView != nil) {            self.menuView.frame.size.height = self.contentFrame.size.height - self.barView.frame.size.height - position        }    }    func setPositionWithAnimation(position: CGFloat, time: NSTimeInterval, completion: ((Void) -> Void)?) {        UIView.animateWithDuration(time, delay: 0, options: .CurveEaseOut, animations: {            self.frame.origin.y = position            self.frame.size.height = self.contentFrame.size.height - position            self.menuView.frame.size.height = self.contentFrame.size.height - position - self.barView.frame.size.height            }, completion: { _ in                if (completion != nil) {                    completion!()                }        })    }}extension LPDropdownMenuView {    private func initGestures() {        doubleTapGestureRecognizer = UITapGestureRecognizer(target: self, action: handleDoubleTapGestures:)        doubleTapGestureRecognizer.numberOfTapsRequired = 2        tapGestureRecognizer = UITapGestureRecognizer(target: self, action: handleTapGestures:)        tapGestureRecognizer.numberOfTapsRequired = 1        tapGestureRecognizer.requireGestureRecognizerToFail(doubleTapGestureRecognizer)        panGestureRecognizer = UIPanGestureRecognizer(target: self, action: handlePanGestures:)        panGestureRecognizer.minimumNumberOfTouches = 1        panGestureRecognizer.maximumNumberOfTouches = 1    }    private func setGestures() {        barView.addGestureRecognizer(doubleTapGestureRecognizer)        barView.addGestureRecognizer(tapGestureRecognizer)        barView.addGestureRecognizer(panGestureRecognizer)    }    internal func handleDoubleTapGestures(sender: UITapGestureRecognizer) {        if (doubleTouchable) {            let minPosition = contentFrame.origin.y            let maxPosition = contentFrame.maxY - barView.frame.size.height            let fartherPosition = getFartherPosition(minPosition, maxPosition: maxPosition)            if (delegate?.dropdownMenuView?(self, shouldDoubleTouchToPosition: fartherPosition) != false) {                delegate?.dropdownMenuView?(self, willDoubleTouchToPosition: fartherPosition)                setPositionWithAnimation(fartherPosition, time: 0.3, completion: {                    delegate?.dropdownMenuView?(self, didDoubleTouchToPosition: fartherPosition)                })            }        }    }    internal func handleTapGestures(sender: UITapGestureRecognizer) {        if (touchable) {            let fartherPosition = getFartherPosition(minPosition, maxPosition: maxPosition)            if (delegate?.dropdownMenuView?(self, shouldTouchToPosition: fartherPosition) != false) {                delegate?.dropdownMenuView?(self, willTouchToPosition: fartherPosition)                setPositionWithAnimation(fartherPosition, time: 0.3, completion: {                    delegate?.dropdownMenuView?(self, didTouchToPosition: fartherPosition)                })            }        }    }    internal func handlePanGestures(sender: UIPanGestureRecognizer) {        let location = sender.locationInView(sender.view!.superview!)        if (sender.state != .Ended && sender.state != .Failed) {            if (!movingCondition) {                movingCondition = true                delegate?.dropdownMenuView?(self, didStartMovingAtPosition: frame.origin.y)            }            let minPosition = contentFrame.origin.y            let maxPosition = contentFrame.maxY - barView.frame.size.height            let newPosition = frame.origin.y + location.y - (sender.view!.frame.size.height / 2)            if (newPosition > minPosition && newPosition < maxPosition) {                setPosition(newPosition)            } else {                if (newPosition < minPosition) {                    setPosition(minPosition)                } else {                    setPosition(maxPosition)                }            }        }        if (sender.state == .Ended) {            movingCondition = false            delegate?.dropdownMenuView?(self, didFinishMovingAtPosition: frame.origin.y)            if (checkMarginProximity(contentFrame.origin.y)) {                if (delegate?.dropdownMenuView?(self, shouldAproximateToPosition: contentFrame.origin.y) != false) {                    delegate?.dropdownMenuView?(self, willAproximateToPosition: contentFrame.origin.y)                    setPositionWithAnimation(contentFrame.origin.y, time: 0.3, completion: {                        delegate?.dropdownMenuView?(self, didAproximateToPosition: contentFrame.origin.y)                    })                    return                }            }            if (checkMarginProximity(contentFrame.maxY - barView.frame.size.height)) {                let proximatePosition = contentFrame.maxY - barView.frame.size.height                if (delegate?.dropdownMenuView?(self, shouldAproximateToPosition: proximatePosition) != false) {                    delegate?.dropdownMenuView?(self, willAproximateToPosition: proximatePosition)                    setPositionWithAnimation(contentFrame.maxY - barView.frame.size.height, time: 0.3, completion: {                        delegate?.dropdownMenuView?(self, didAproximateToPosition: proximatePosition)                    })                    return                }            }            if (swipeable) {                let swipePosition = getSwipePosition(sender.velocityInView(sender.view))                if (swipePosition != nil) {                    let swipeCondition = delegate?.dropdownMenuView?(self, shouldSwipeToPosition: swipePosition!) != false                    if (swipeCondition) {                        delegate?.dropdownMenuView?(self, willSwipeToPosition: swipePosition!)                        setPositionWithAnimation(swipePosition!, time: 0.3, completion: {                            delegate?.dropdownMenuView?(self, didSwipeToPosition: swipePosition!)                        })                        return                    }                }            }            if (freeSlideable && delegate?.dropdownMenuView?(self, shouldFinishSlidingAtPosition: frame.origin.y) == false) {                let nearestPosition = getNearestPosition()                delegate?.dropdownMenuView?(self, willAproximateToPosition: nearestPosition)                setPositionWithAnimation(nearestPosition, time: 0.3, completion: {                    delegate?.dropdownMenuView?(self, didAproximateToPosition: nearestPosition)                })                return            }            if (!freeSlideable) {                let nearestPosition = getNearestPosition()                delegate?.dropdownMenuView?(self, willAproximateToPosition: nearestPosition)                setPositionWithAnimation(nearestPosition, time: 0.3, completion: {                    delegate?.dropdownMenuView?(self, didAproximateToPosition: nearestPosition)                })                return            }            delegate?.dropdownMenuView?(self, willFinishSlidingAtPosition: frame.origin.y)            delegate?.dropdownMenuView?(self, didFinishSlidingAtPosition: frame.origin.y)        }    }    private func checkMarginProximity(position: CGFloat) -> Bool {        if (frame.origin.y < position + marginProximity && frame.origin.y > position - marginProximity) {            return true        }        return false    }    private func getNearestPosition() -> CGFloat {        let currentPosition = frame.origin.y + (barView.frame.size.height / 2)        let positions = [contentFrame.origin.y, minPosition, maxPosition, contentFrame.maxY]        var nearestPosition: CGFloat!        var distance: CGFloat!        for position in positions {            if (distance == nil || distance > abs(currentPosition - position)) {                distance = abs(currentPosition - position)                nearestPosition = position            }        }        return nearestPosition    }    private func getSwipePosition(velocity: CGPoint) -> CGFloat? {        if (velocity.y > swipeSensibility) {            return maxPosition        }        if (velocity.y < -swipeSensibility) {            if (frame.origin.y < minPosition) {                return contentFrame.origin.y            } else {                return minPosition            }        }        return nil    }    private func getFartherPosition(minPosition: CGFloat, maxPosition: CGFloat) -> CGFloat {        let rangeMinPosition: CGFloat = 1.5        let rangeMaxPosition: CGFloat = 0.5        let distanceFromMin = (frame.origin.y - minPosition) * rangeMinPosition        let distanceFromMax = (maxPosition - frame.origin.y) * rangeMaxPosition        if (distanceFromMin > distanceFromMax) {            return minPosition        } else {            return maxPosition        }    }}class DefaultBarView: UIView {    override init(frame: CGRect) {        super.init(frame: frame)        backgroundColor = UIColor.blueColor()        initLabel()    }    required init?(coder aDecoder: NSCoder) {        fatalError(init(coder:) has not been implemented)    }    private func initLabel() {        let label = UILabel(frame: CGRectMake(0, 0, frame.size.width, frame.size.height))        label.textAlignment = .Center        label.textColor = UIColor.whiteColor()        label.font = UIFont.systemFontOfSize(22)        label.text = Something cool here!        addSubview(label)    }}class DefaultMenuView: UIView {    override init(frame: CGRect) {        super.init(frame: frame)        backgroundColor = UIColor.grayColor()        initLabel()    }    required init?(coder aDecoder: NSCoder) {        fatalError(init(coder:) has not been implemented)    }    private func initLabel() {        let label = UILabel(frame: CGRectMake(0, 0, frame.size.width, frame.size.height))        label.textAlignment = .Center        label.textColor = UIColor.whiteColor()        label.font = UIFont.systemFontOfSize(22)        label.text = An amazing view here!        addSubview(label)    }}The code works perfect, but I want your opinion!
Swift menu code
ios;swift;gui
There is a whole lot of code here, but I actually want to focus strictly on the protocol that we've created for delegates of this menu.  There are a few things that immediately jump out to me, but the first thing, I'll illustrate with a screenshot.The protocol has a total of 17 methods.  All of which start with the same 69 characters.  Now, that alone is not that problematic.  If we take a look at other protocols (even, some of Apple's, like table views and collection views), we'll see the same thing.  But here, the problem is, we have provided no comments and the organization of the methods leaves a lot to be desired.Let's compare, for example, the documentation for UITableViewDelegate:Notice the organization into more useful categories.  Your organization is this:should happenwill happendid happenAnd then a final did happen section that is somewhat inexplicably separated from the other did happen methods... but actually makes some as its own section (if we take a look at the Apple organization).I'd rather see your protocol organized into six section of roughly 3 methods each.  The natural organization looks more like this...swiping...should swipewill swipedid swipetouching...should touchwill touchdid touchetc...Moreover, I would expect every single on of these method declarations to have appropriate Apple docs with them.This, for example, is what the shouldSwipeToPosition method might have:Your methods are well named, but I'm certainly going to expect documentation like this for a delegate protocol.  It's the biggest clue I have as to exactly how and when this method works.  Your description should even be more detailed than what I've provided.  Consider, for example, the documentation that Apple provides for a similar protocol method found in UIKit:This documentation is on their website, but it's also available via Xcode in the same manner as I showed in the screenshot demonstrating an example of the documentation you should be providing.You've dumped everything into a single file.  For what you've provided, I'd expect six different files.  This means reconsidering your access modifiers.The thing is, you've designed this with the idea in mind that the user will copy & paste this file into their project and just go... the thing is, that's a terrible way to bring 3rd party code into my project.  When I bring code into my projects, I expect to bring it in via Cocoapods.  As a rule (with the rare exception), I completely pass over libraries that aren't Cocoapod compatible.It's important to note that if our code IS being used via a Cocoapod, then only the things marked as public are seen by the outside world.  This is nice.  It allows us to access code across our entire library, allowing us to use multiple files, and still preventing the outside world from calling these directly.  It is something you should consider seriously.