Class Hooking
-
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
ClassHookwith that class as theTargettype. For example, to hookMyClassone could declareclass 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 useNSObjectif no class which is more specific is available at compile-time), and provide the actual target class’ name by implementing the statictargetNameproperty.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
classmethod.In either case, the method must not be
finalorstatic. Methods which have a visibility offileprivateorprivatewill be ignored by Orion and can thus be used as helper methods.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 theorigproxy. Similarly, the superclass implementation can be accessed via thesuprproxy.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 examplefunc initWithFrame(_ frame: CGRect) -> Target. Inside the method, your first statement should be a call to an initializer onsuprororig, after which you can configuretargetas you desire before you return it. To hookNSObject.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
deinitializerfunction (notdeinit). For more information, seeClassHookProtocol.deinitializer().Adding to the Class
Properties
Use the
@Propertyproperty 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.protocolsproperty.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
ClassHookwith theTargetortargetNameas the base class, and declare thesubclassModeproperty with a value ofSubclassMode.createSubclass(to automatically pick a subclass name) or useSubclassMode.createSubclassNamed(_:)if you need a specific name.The static
targetproperty 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") } }Declaration
Swift
public typealias ClassHook<Target> = ClassHookClass<Target> & ClassHookProtocol where Target : AnyObject -
Declaration
Swift
public protocol ClassHookProtocol : AnyObject, AnyHook -
A property wrapper which allows
ClassHooktypes to add new properties to their hooked class.This type is an ergonomic wrapper around Objective-C associated objects. The type of the associated object is the generic argument
T.If you are declaring a property on a
ClassHook, you likely want to use this. Note that this property only works on types which conform toClassHook.Important
All properties with this attribute must have a default value.Attributes
This property wrapper gives you the ability to specify attributes on the property, which are similar to those used by Objective-C’s
@property. For a description of each attribute, seeProperty.Assign,Property.Atomicity, andProperty.RetainOrCopy.The default attributes are
atomicandretain. Specifyingassignwill replace both defaults, and specifying an atomicity and/or retain policy will only override the respective default.Example
See more@objcMembers class Person: NSObject { dynamic func sayHello() -> String { "hello" } } class PersonHook: ClassHook<Person> { @Property(.nonatomic) var x = 0 func sayHello() -> String { x += 1 return "Hi! I've been called \(x) time(s)" } } // later... let alice = Person() alice.sayHello() // Hi! I've been called 1 time(s) alice.sayHello() // Hi! I've been called 2 time(s) let bob = Person() bob.sayHello() // Hi! I've been called 1 time(s) bob.sayHello() // Hi! I've been called 2 time(s)Declaration
Swift
@propertyWrapper public struct Property<T> -
Declaration
Swift
public enum SubclassMode -
The action to perform after a
ClassHookProtocol.deinitializer()is run.Unless you’re managing the target class’ own resources, you usually want to use
See morecallOrig.Declaration
Swift
public enum DeinitPolicy
View on GitHub
Install in Dash
Class Hooking Reference