Example of method Swizzling in Swift

a sexy example of method Swizzling

Might be this looks cool to you, but you might never know where other place you can use this technique. So I have prepared an example that is used often in our programming.

The simple thing I have used on is dismiss keyboard (endEditing) when user taps on other part of screen. In which I have swizzled method of UIViewController to create that functionality. And every viewController in which I want to dismiss keyboard, I have implemented KeyBoardDismissable protocol. code is below:

protocol KeyboardDismissable {

}
private func swizzling(viewController: UIViewController.Type) {

    let originalSelector = #selector(viewController.viewWillAppear(_:))
    let swizzledSelector = #selector(viewController.newViewWillAppear(animated:))

    let originalMethod = class_getInstanceMethod(viewController, originalSelector)
    let swizzledMethod = class_getInstanceMethod(viewController, swizzledSelector)

    method_exchangeImplementations(originalMethod, swizzledMethod)

}

extension UIViewController {

    override public class func initialize() {

        guard self === UIViewController.self else {
            super.initialize()
            return
        }

    swizzling(self)
    super.initialize()
}

// MARK: - Method Swizzling

    @objc private func newViewWillAppear(animated: Bool) {
        if (self as? KeyboardDismissable) != nil {
            self.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(tappedOnView)))
        }

        self.newViewWillAppear(animated)
    }

    @objc private func tappedOnView() {
        self.view.endEditing(true)
    }
}

I use it like:

class CreateUserViewController: UIViewController, KeyboardDismissable {

…

}

Magics of Method Swizzling in Swift

a sexy and nasty gift of Objective-C to Swift

Hi, today I have something special to blog on. I heard so many times from one of my colleague; that in Ruby in Rails we have make a label draggable just by stating it as draggable. (i.e. the label can be dragged around anywhere in screen) Like:

class DraggableLabel: UILabel, Draggable {

}

No any method implementation required. Not method calls is required. Like

label.makeDraggable()

is not required.

I was thinking ,if I have to create draggable label than probably I would add code in override of awakeFromNib() or overriding some other functions.

Please, let me know how would you do that? Probably, the thing I am going to explain below might be primitive than yours. 🙂

I am using method swizzling in swift to create this functionality. If you know nothing about method swizzling, I have blogged about method swizzling in my previous blog. Check it out here!

Actually, let me do something else. I will make any UIView draggable then we can make UITextField or UILabel or any other subclass of UIView be draggable.

1. lets define Draggable protocol:

protocol Draggable {

}

I don’t have anything in mind to do other than dragging so I haven’t kept any function or variables in protocol.

2. Now main part is swizzling see the code below:

// 1: the function that swizzles the awakeFromNib method with new method (global function)
private func swizzling(_ view: UIView.Type) -> () {
    
    // get selectors
    let originalSelector = #selector(view.awakeFromNib)
    let swizzledSelector = #selector(view.newAwakeFromNib)
    // extract methods from selector
    let originalMethod = class_getInstanceMethod(view, originalSelector)
    let swizzledMethod = class_getInstanceMethod(view, swizzledSelector)

    // exchange their implementation (swizzle)
    method_exchangeImplementations(originalMethod, swizzledMethod)
}

extension UIView {
    // 2 : swizzle methods in initialize

    // only class func can be override in extension so initialize() is the best option

    open override class func initialize() {
        swizzling(self)
    }

    // 3 : New function that will be executed instead of awakeFromNib

    // MARK: - Method Swizzling
    @objc fileprivate func newAwakeFromNib() {
        // I also want to call old awakeFromNib so I called this function: remember after swizzling the old function name becomes swizzled function’s name

        self.newAwakeFromNib()

        // 4 : if this view has implemented Draggable protocol, then enable do followings

        if (self as? Draggable) != nil {
            self.isUserInteractionEnabled = true
            self.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(tappedOnView(gesture:))))
        }
    }

    // 5 : Code to handle pan gesture on this view
    @objc private func tappedOnView(gesture: UIPanGestureRecognizer) {
        let newCenter = gesture.translation(in: self.superview)
        self.transform = CGAffineTransform(translationX: newCenter.x, y: newCenter.y)
        switch gesture.state {
        case .ended:
            let oldCenterX = self.center.x
            let oldCenterY = self.center.y
            self.center = CGPoint(x: oldCenterX + newCenter.x, y: oldCenterY + newCenter.y)
            self.transform = CGAffineTransform.identity
        default: break
        }
    }
}

Now I will create a UILabel which will be draggable:

class CustomLabel: UILabel, Draggable {

}

Simple Yeah?

Now I will create UITextView which is draggable:

class CustomLabel: UITextField, Draggable {

}

Cool Yeah?

To use these draggable UIView,  you need to assign class from storyboard or create from code like you create other views.

Other Example on method swizzling: Example

Method Swizzling in Swift

Exchange implementation of methods in runtime. 🙂

Have you heard about it? Its cool stuff to do.

Method swizzling in Swift is from Objective-C, i.e. brought from Objective-C.
In method swizzling, we exchange the implementations of two methods in atomic level. Swizzling is done on runtime so, you can use it for multiple purposes.

Lets say there is a class X and it has two methods one and two.

class X {
    func one() {
        print(“func-1”)
    }

    func two() {
        print(“func-2”)
    }
}

Before I do method swizzling:

let x = X()

x.one() // outputs: func-1

x.two() // outputs: func-2

After I do method swizzling between func one and func two:

let x = X()

x.one() // outputs: func-2, i.e. print string that you defined in func two

x.two() // outputs: func-1, i.e. print string that you defined in func one

After you swizzling (exchange), when you call “func one” it will call “func two”, and when you call “func two” it will call “func one”.

untitled

#You will have to follow the next post for examples. I wanted to write this article for support of next article: Magics of Method Swizzling in Swift