Skip to content

Instantly share code, notes, and snippets.

@janodev
Created March 16, 2018 10:22
Show Gist options
  • Save janodev/de54d10224b1bee1d0be5aa0a8b9b352 to your computer and use it in GitHub Desktop.
Save janodev/de54d10224b1bee1d0be5aa0a8b9b352 to your computer and use it in GitHub Desktop.
A delegate implemented with generics and a static method
// From “Better Strategies Through Types”
// http://www.figure.ink/blog/2018/3/11/better-strategies-through-types
import UIKit
protocol BouncyDelegate {
static func animateBounce(for view: UIView)
}
enum ShakeStrategy: BouncyDelegate
{
static func animateBounce(for view: UIView)
{
let base = CGAffineTransform.identity
let offset = base.translatedBy(x: 30, y: 0)
view.transform = offset
UIView.animate(withDuration: 0.5, delay: 0,
usingSpringWithDamping: 0.2,
initialSpringVelocity: 0,
options: [],
animations: { view.transform = base },
completion: nil)
}
}
class BouncyButton<Strategy>: UIControl where Strategy: BouncyDelegate
{
private weak var button: UIButton!
override init(frame: CGRect) {
super.init(frame: frame)
let b = UIButton(frame: CGRect(origin: CGPoint(x: 0, y: 0), size: frame.size))
b.backgroundColor = .blue
b.addTarget(self, action: #selector(handleTap), for: .touchUpInside)
addSubview(b)
button = b
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
@objc func handleTap() {
Strategy.animateBounce(for: button)
sendActions(for: .touchUpInside)
}
}
import UIKit
public class ControlAction {
let closure: ()->()
init (_ closure: @escaping ()->()) {
self.closure = closure
}
@objc func invoke () {
closure()
}
}
extension UIControl
{
/// Add a closure to be fired in response to a control event.
public func add(for controlEvents: UIControlEvents, _ closure: @escaping ()->()) {
let controlAction = ControlAction(closure)
addTarget(controlAction, action: #selector(ControlAction.invoke), for: controlEvents)
objc_setAssociatedObject(self, UUID().uuidString, controlAction, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN)
}
}
import Foundation
// Encapsulate creation and configuration of an object.
func create<Type>(_ value : Type, block: (_ object: Type) -> Void) -> Type {
block(value)
return value
}
import UIKit
class ViewController: UIViewController
{
private typealias ShakyButton = BouncyButton<ShakeStrategy>
private let button = create(ShakyButton(frame: CGRect(x: 50, y: 50, width: 100, height: 100))) { (button) in
button.backgroundColor = UIColor.lightGray
button.add(for: .touchUpInside, { print("pickles") })
}
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(button)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment