💡 A light Swift wrapper around Objective-C Runtime

Overview

LMMethod Methods

A light wrapper around Objective-C Runtime.

What exactly is lumos?

lumos as mentioned is a light wrapper around objective-c runtime functions to allow an easier access to the runtime. It makes operations such as swizzling and hooking very simple in Swift.

For example, say you wish to run a block of code whenever a ViewController's viewDidLoad method is called

With lumos, you can do the following:

// In AppDelegate (or any conveinient place)..

let method = Lumos.for(ViewController.self).getInstanceMethod(selector: #selector(ViewController.viewDidLoad))
        
method?.prepend {
    // This block will be run every time a viewDidLoad is called
    print("View Controller loaded")
}

Similarily you can append a block to a method which will be called right before the method returns. You can even use replace to replace the method's implementation with the block you pass in as a parameter.

If you wanted more flexibility, you could swizzle the viewDidLoad method using the following lines:

@objc func myMethod() {
    // Do anything here
}

let myMethod = self.lumos.getInstanceMethod(selector: #selector(myMethod))

method?.swapImplementation(with: myMethod)

Do you feel the superpower yet? Maybe you wish to list all the classes registered at runtime:

Lumos.getAllClasses()

Fun Fact: There are almost 12,000 classes registered at runtime Try Lumos.getAllClasses().count

You could get the class hierarchy of any class just with:

myObject.lumos.getClassHierarcy()   // For UIView: [UIView, UIResponder, NSObject]

Fun Fact: Some classes such as URLSessionTask are actually dummy classes which are replaced with underlying classes such as __NSCFLocalSessionTask during runtime.

With lumos, you can iterate through variables, functions, protocols etc and meddle with them at runtime. Have fun exploring!

Usage

Just incantate .lumos on any instance of a NSObject subclass or use Lumos.for(object) for where object is of type AnyClass, AnyObject, Protocol, Ivar, objc_property_t or objc_property_attribute_t.

LMMethod Methods

LMClass Methods

P.s The code itself is the documentation for now. There are many more methods that lumos offers which are not discussed in this document. Cheers :)

Why lumos?

The Objective-C Runtime provides many powerful methods to manipulate objects, classes and methods at runtime. Although disasterous when misused, these methods provide a great way to peek into the runtime and meddle with it.

However, the methods are not exactly easy to use sometimes. For example the following method is used to obtain a list of all classes registered at runtime:

func objc_getClassList(_ buffer: AutoreleasingUnsafeMutablePointer<AnyClass>?, _ bufferCount: Int32) -> Int32

Often, a lot of dirty work needs to be done before one gets the list out. Here is how I would do it:

static func getClassList() -> [AnyClass] {
    let expectedClassCount = objc_getClassList(nil, 0)
    let allClasses = UnsafeMutablePointer<AnyClass?>.allocate(capacity: Int(expectedClassCount))

    let autoreleasingAllClasses = AutoreleasingUnsafeMutablePointer<AnyClass>(allClasses)
    let actualClassCount: Int32 = objc_getClassList(autoreleasingAllClasses, expectedClassCount)

    var classes = [AnyClass]()
    for i in 0 ..< actualClassCount {
        if let currentClass: AnyClass = allClasses[Int(i)] {
            classes.append(currentClass)
        }
    }

    allClasses.deallocate()
    return classes
}

Now all you would need to do to obtain the list of classes would be to invoke this method. Maybe you wish to get a list of classes that conform to a certain protocol:

static func classesImplementingProtocol(_ requiredProtocol: Protocol) -> [AnyClass] {
    return Lumos.getClassList().filter { class_conformsToProtocol($0, requiredProtocol) }
}

Perhaps you wish to swizzle method implementations at runtime:

static func swizzle(originalClass: AnyClass, originalSelector: Selector, swizzledClass: AnyClass, swizzledSelector: Selector) {
    guard let originalMethod = class_getInstanceMethod(originalClass, originalSelector),
    let swizzledMethod = class_getInstanceMethod(swizzledClass, swizzledSelector) else {
        return
    }

    let didAddMethod = class_addMethod(originalClass, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod))

    if didAddMethod {
        class_replaceMethod(originalClass, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod))
    } else {
        method_exchangeImplementations(originalMethod, swizzledMethod);
    }
}

You can now use:

Lumos.swizzle(originalClass: URLSessionTask,
              originalSelector: #selector(URLSessionTask.resume),
              swizzledClass: SwizzledSessionTask,
              swizzledSelector: #selector(SwizzledSessionTask.resume))

P.S you might want to use dispatch_once with the method above to above swizzling more than once across multiple threads.

Installation

CocoaPods

CocoaPods is a dependency manager for Cocoa projects. You can install it with the following command:

$ gem install cocoapods

To integrate lumos into your Xcode project using CocoaPods, specify it in your Podfile:

source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '10.0'
use_frameworks!

target '<Your Target Name>' do
    pod 'Lumos'
end

Then, run the following command:

$ pod install

License

Lumos is released under the Apache-2.0. See LICENSE for details.

You might also like...
An iPhone Simulator
An iPhone Simulator "Wrapper" for SwiftUI Apps on macOS

SwiftUIPhone Run a SwiftUI app (or any SwiftUI view) in an iPhone Simulator "wrapper", directly on macOS! To be clear, this is not an iPhone Simulator

A new property wrapper for SwiftUI ObservableObject.

SharedObject 🍱 @SharedObject is an alternative to @StateObject, @ObservedObject, @EnvironmentObject to handle ObservableObject. If you need to have m

Swift Playgrounds desenvolvido para o Swift Student Challenge da WWDC 21
Swift Playgrounds desenvolvido para o Swift Student Challenge da WWDC 21

Pile Up Swift Playgrounds desenvolvido para o Swift Student Challenge da WWDC 21 Descrição Pile Up é um quebra cabeça cujo objetivo é empilhar os bloc

Swift Language Weather is an iOS weather app developed in Swift
Swift Language Weather is an iOS weather app developed in Swift

Swift Language Weather SwiftWeather has renamed to Swift Language Weather. Because this repo is ranked number one in Google when we search "Swift Weat

Todo-app-swift- - A Todo Lists app built using swift

TODO-Lists App Available on the App Store What is this? This is a todo app I mad

Matrix-rust-components-swift - Swift package providing components from the matrix-rust-sdk

Swift package for Matrix Rust components This repository is a Swift Package for

Swift playground teaching basics of buffer overflow vulnerability and ARM64 assembly by exploiting vulnerable app on ARM64 emulator (WWDC22 Swift Student Challenge Winner)
Swift playground teaching basics of buffer overflow vulnerability and ARM64 assembly by exploiting vulnerable app on ARM64 emulator (WWDC22 Swift Student Challenge Winner)

Pwnground Project overview Pwnground is a project created as my submission for WWDC22 Swift Student Challenge (winner). It is an interactive Swift Pla

A small SwiftUI based chat client for IRC, using swift-nio-irc
A small SwiftUI based chat client for IRC, using swift-nio-irc

NeoIRC A simple Internet Relay Chat client implemented using SwiftNIO and SwiftUI. Inspired by: For maximum NIO someone (I’m tempted) should adopt NIO

🎮 Favorite your games filter and see the upcoming games and ! Swift + Combine = 💜 Hacktoberfest 🎃 👾
🎮 Favorite your games filter and see the upcoming games and ! Swift + Combine = 💜 Hacktoberfest 🎃 👾

✨ Revill is App to list games and search best games ✨ Design in Swift UI + Combine ✨ The idea is develop this app in Hacktober Fest Expected To Do Des

Comments
  • Crash upon accessing anything from Lumos.getAllClasses()

    Crash upon accessing anything from Lumos.getAllClasses()

    Doing something like this:

    let classes =  Lumos.getAllClasses().filter { b in
          return true
    }
            
    print(classes[0].description())
    

    crashes with:

    [ description] sent to deallocated instance 0x123195e58

    The filtered array wasn't empty, sure thing. Xcode 9.4.1.

    opened by reenboog 4
  • Dummy classes swizzling

    Dummy classes swizzling

    Fun Fact: Some classes such as URLSessionTask are actually dummy classes which are replaced with underlying classes such as __NSCFLocalSessionTask during runtime.

    Just wondering is it possible to swizzle __NSCFLocalSessionTask using Lumos?

    opened by shams-ahmed 0
  • Swift API Guidelines

    Swift API Guidelines

    Small nitpick here, the Swift API Guidelines state that getters should not begin with get, as it's implicit in the fact that the method returns something.

    Maybe change things like:

    func getMethods() -> [Selector] { ... }
    func getImplementation(selector: Selector) -> IMP? 
    

    to

    var methods: [Selector] { ... }
    func implementation(for selector: Selector) -> IMP?
    
    opened by harlanhaskins 1
Owner
Suyash Shekhar
learning how to learn
Suyash Shekhar
xcode project wrapper around the Elixir TodoApp Desktop app to run on iOS

TodoApp iOS: An iOS Sample App This xcode project wraps the Desktop Sample App to run on an iPhone. How to build & run Install xcode from the app stor

elixir-desktop 43 Nov 7, 2022
A SwiftUI wrapper around the `Add to Siri` button used to donate INIntents to the system.

AddToSiri A SwiftUI wrapper around the Add to Siri button used to donate INIntents to the system. Originally created by Reddit user u/dippnerd (Github

Florian Schweizer 5 Nov 23, 2022
App for LaTeX quick reference and light equation editor

LaTeX Draft I miss the LaTeX Help app, which is too ancient to work under the latest iOS unfortunately. So I will write one in hommage to LaTeX Help a

mizu-bai 1 Mar 9, 2022
Project The Light homework #1

The Light Project The Light homework #1 1. App icon added 2. When the applicatio

Nikita 0 Dec 19, 2021
BeezyLight.app✦ tiny macOS app to control a usb-connected light

BeezyLight.app✦ tiny macOS app to control a usb-connected light

null 2 Jul 11, 2022
A simple App to Track the status of Covid-19 around the World. Using SwiftUI and GraphQL

CovidUI CovidUI is a simple App to Track the status of Covid-19 around the World. This is a simple App I made to track the spread of Covid-19 for me a

Mathias Quintero 77 Dec 14, 2022
Want to know the current weather around the globe? Clima has your back!

Clima (a weather app) Dreaming about going on vacation somewhere? Use Clima to find real time weather from around the world or use your GPS to get loc

null 0 Dec 27, 2021
You can share and communicate with developers around the world through the Fabula app.

FabulaItemsProvider This is the source package for the Fabula project. You can share and communicate with developers around the world through the Fabu

jasu 231 Dec 31, 2022
EasyFirebase - a Swift wrapper for all things Firebase

?? A Swifty solution for all things Firebase. Quickly implement Firestore and Authentication on iOS + macOS using Swift protocols and methods.

Flowductive 41 Jan 6, 2023
A SwiftUI dynamic property wrapper for fetching media from your photo library. (iOS, tvOS, macOS)

Media Also available as a part of my SwiftUI+ Collection – just add it to Xcode 13+ A package for simplifying the user of the camera and the user's ph

SwiftUI+ 20 Nov 16, 2022