Lumos 0.1.0

Lumos 0.1.0

Suyash Shekhar 维护。



Lumos 0.1.0

  • 作者:
  • Suyash Shekhar

lumos

A light wrapper around Objective-C Runtime.

究竟什么是 lumos?

lumos 如同所述,是一个围绕 Objective-C 运行时函数的 light 包装器,以便更容易地访问运行时。它使得如 swizzling 和 hooking 之类的操作在 Swift 中变得非常简单。

例如,假设您希望在 `ViewController` 的 `viewDidLoad` 方法被调用时运行一块代码

使用 lumos,您可以这样做

// 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")
}

同样,您可以为方法返回之前要调用的方法添加一个块,甚至可以使用 replace 来用您传递的块替换方法的实现。

如果您需要更多的灵活性,可以使用以下行来使用 swizzling 调整 `viewDidLoad` 方法

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

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

method?.swapImplementation(with: myMethod)

您感受到了这种超级能力了吗?也许您想要列出在运行时注册的所有类

Lumos.getAllClasses()

有趣的事实:运行时注册了大约 12,000 个类。尝试 `Lumos.getAllClasses().count`

您可以使用以下命令获取任何类的类层次结构:

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

有趣的事实:一些类如 `URLSessionTask` 实际上是虚拟类,它们在运行时会用底层类如 `__NSCFLocalSessionTask` 替换。

使用 lumos,您可以遍历变量、函数、协议等,并在运行时对它们进行操作。尽情探索吧!

用法

只需在任何 `NSObject` 子类的实例上使用 .lumos,或者当 `object` 类型为 `AnyClass`、`AnyObject`、`Protocol`、`Ivar`、`objc_property_t` 或 `objc_property_attribute_t` 时使用 `Lumos(object)`。

screen shot 2018-07-21 at 2 45 10 am

screen shot 2018-07-21 at 2 59 58 am

附录:现在的代码本身 是文档。还有很多 lumos 提供的方法没有在本文档中讨论。干杯 :)

为什么要 lumos

Objective-C 运行时提供了许多强大的方法来在运行时操纵对象、类和方法。虽然误用可能会导致灾难,但这些方法提供了一种很好的方式来深入了解运行时并与之交互。

不过,使用这些方法有时并不容易。例如,以下方法用于获取在运行时注册的所有类的列表

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

然而,在使用这个方法之前需要做大量的准备工作。以下是我的操作方法

static func classList() -> [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
}

现在获取类列表只需调用这个方法即可。也许您想获取符合某个协议的类列表

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

也许您想在运行时交换方法实现

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);
    }
}

提示:您可能需要在使用上面的方法进行大量交换时,通过 dispatch_once 来避免在多个线程中多次调用。

安装

CocoaPods

CocoaPods 是一个用于 Cocoa 项目的依赖项管理器。您可以使用以下命令安装它

$ gem install cocoapods

要将 lumos 集成到使用 CocoaPods 的 Xcode 项目中,请在您的 Podfile 中指定它

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

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

然后,运行以下命令

$ pod install

许可证

Lumos 在 Apache-2.0 许可下发布。有关详细信息,请参阅 LICENSE