Practical scenarios for using Objective-C method dispatch system in Swift.

Salman khalid
2 min readDec 2, 2023

While working with swift we can witness a difference in the nature of this language from its predecessor especially in the method dispatch system. Objective-C is very dynamic in nature and it makes it very easy to work with but at a cost of stability and performance.

As we know that the main magic in Objective-C comes from its dynamic message based dispatch system, whereas Swift relies on V or Witness table based dispatch system.

These are the some of the cases where one can refer to the Objective-C run time to exploit this dynamism. Obviously they are not considered to be a good practice and can also create performance issues.

  1. Adding stored properties in extension:

While working with some native types its easier to add stored properties in extension without subclassing the actual type.

fileprivate var storedObjectKey: UInt8 = 0

extension UIViewController {
var storedProperty: String? {
get {
guard let storedValue = objc_getAssociatedObject(self, &storedObjectKey) as? String else {
return nil
}
return storedValue
}
set {
objc_setAssociatedObject(self, &storedObjectKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
}

In the above example, a stored property is being created on UIViewController in the extension which is not possible in pure Swift environment.

2. Method Swizzling

Swizzling means to switch the implementation of a method at run time. This concept is also dependent on Objective-C run time. I have seen some third party libraries also using it if they need to add an hook in some App life cycle method.

extension UIViewController {

static let modalDismissed = Notification.Name("modalDismissed")
static func swizzleDismiss() {

let originalSelector = #selector(UIViewController.dismiss(animated:completion:))
let swizzledSelector = #selector(UIViewController.trackedDismiss(animated:completion:))
let originalMethod = class_getInstanceMethod(self, originalSelector)
let swizzledMethod = class_getInstanceMethod(self, swizzledSelector)

if let originalMethod = originalMethod
, let swizzledMethod = swizzledMethod {

method_exchangeImplementations(originalMethod, swizzledMethod)
}
}

@objc func trackedDismiss(animated flag: Bool, completion: (() -> Void)? = nil) {

trackedDismiss(animated: flag) {

completion?()
NotificationCenter.default.post(name: UIViewController.modalDismissed, object: nil)
}

}
}

In the above example a dismiss() method is being swizzled with the local method. Now every time this method gets called our native method will be called and which is throwing a notification which can be caught in other places.

3. Overriding a computed property which is defined in super class extension

In case we add a property in an extension of a super class and try to override it in a subclass, it wont let the sub class override property unless we use the “objc” directive with the super class.

extension UIViewController {
@objc var someProperty: String {
return "From UIViewController"
}
}

class CustomVC: UIViewController {
override var someProperty: String {
"From CustomVC"
}
}

let customVC = CustomVC()
print("\(customVC.someProperty)")

In the above example a computed property is used to provide a default value for all UIViewControllers and for specific cases its can be overridden.

--

--