ClassHook

public typealias ClassHook<Target> = ClassHookClass<Target> & ClassHookProtocol where Target : AnyObject

The base class hook type. All class hooks must subclass this.

This type allows hooking methods of a chosen target class. For a detailed description of all available configuration options, see ClassHookProtocol.

Specifying a Target Class

In order to hook a class which is known by the Swift compiler at compile-time, specialize ClassHook with that class as the Target type. For example, to hook MyClass one could declare class MyHook: ClassHook<MyClass>.

In order to hook a class which is not known by the Swift compiler at compile-time, specify a class in its inheritance chain as Target (you can use NSObject if no class which is more specific is available at compile-time), and provide the actual target class’ name by implementing the static targetName property.

Hooking Methods

Instance/Class Methods

To hook an instance method on the target class, simply declare an instance method with the same name and method signature in your hook class. The contents of your method will replace the original method implementation.

In order to hook a class method, declare the replacement method as a class method.

In either case, the method must not be final or static. Methods which have a visibility of fileprivate or private will be ignored by Orion and can thus be used as helper methods.

Methods which have an Objective-C selector that begins with alloc, new, copy, or mutableCopy, follow the appropriate Objective-C conventions described here. In the rare case that you need to manually override this behavior, add // orion:returns_retained true (or false) above your method declaration. These directives behave like NS_RETURNS_RETAINED and NS_RETURNS_NOT_RETAINED respectively.

Accessing Target Information

Within a method hook function, the object upon which the hooked method was invoked can be accessed via target. To call the original implementation of the method, call the method itself on the orig proxy. Similarly, the superclass implementation can be accessed via the supr proxy.

Method Naming

To figure out the required Swift name for an Objective-C method, you may want to follow the way that Objective-C APIs are renamed when they are imported into Swift, in reverse. If you cannot figure out the Swift name for the method, you can also provide the Objective-C selector name directly by declaring the function as @objc(selector:name:) func.

Initializers

In order to hook an initializer with Orion, declare an instance method with the initializer’s name and Objective-C method signature, with a return type of Target. For example func initWithFrame(_ frame: CGRect) -> Target. Inside the method, your first statement should be a call to an initializer on supr or orig, after which you can configure target as you desire before you return it. To hook NSObject.init, use backticks to escape the init keyword: func `init`() -> Target.

Example of hooking initWithFrame:

class ViewHook: ClassHook<UIView> {
    func initWithFrame(_ frame: CGRect) -> Target {
        let target = orig.initWithFrame(frame)
        // configure target
        return target
    }
}

Deinitializers

If you find the need to perform custom behavior when a target object is deallocated, you can declare a deinitializer function (not deinit). For more information, see ClassHookProtocol.deinitializer().

Adding to the Class

Properties

Use the @Property property wrapper. For more information, refer to its documentation.

Protocols

You can specify a list of protocols for which conformance will be added to the class, by declaring the ClassHookProtocol.protocols property.

New Methods

To add a new method to the target class, simply declare it on the hook and mark it as final. This may be useful, for example, to make the target class conform to a protocol requirement.

Creating Subclasses

In some situations, you may need to declare a subclass for a base class which is not known at compile-time. In this case, create a ClassHook with the Target or targetName as the base class, and declare the subclassMode property with a value of SubclassMode.createSubclass (to automatically pick a subclass name) or use SubclassMode.createSubclassNamed(_:) if you need a specific name.

The static target property will refer to the subclass type. It is possible to add methods, properties, protocols, and so on to the subclass as described above.

Example

To change the text of all UILabels to “hello”, one could write something like this:

class MyHook: ClassHook<UILabel> {
    func setText(_ text: String) {
        orig.setText("hello")
    }
}