XAspect Learning Summary

Posted by rReLmy on Wed, 26 Jun 2019 18:28:51 +0200

http://www.jianshu.com/p/bb0374ec3e7e

Aspect is a lightweight library for facet-oriented programming.It allows you to include any code in the methods that exist in each class and instance.

First, give the github address: XAspect , the original description, you can see README in the project, or a detailed description Documents Or this article Aspects iOS AOP Face Oriented Programming Library If you are interested in its source code, you can refer to this article How iOS implements Aspect Oriented Programming (above)

After downloading the source code, drag the XAspect folder into the project or, if using Pod, add the following code to your Podfile:

pod "Aspects"

Then create a new empty.m file:

The name here can be used freely and function-related names are recommended.

Next, open the file and add the following code:

#import "XAspect.h"
#import "AppDelegate.h"

// Must have macro definitions, and must be written at the top
// AtAspect field is fixed and cannot be modified
// LZProjectName, which can be customized, is generally related to the class you need to inject code into
#define AtAspect LZProjectName

// Classes that require code injection
// AtAspectOfClass fixed field, cannot be modified
// Classes that AppDelegate needs to inject code into
#define AtAspectOfClass AppDelegate
// Make room for this parameter class name to match the above class
@classPatchField(AppDelegate)


/**
 Methods to be added

 @param - Method Type: - Instance Method; + Class Method
 @param BOOL return type
 @param UIApplication Method Entity
 @return Return
 */
AspectPatch(-, BOOL, application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions) {

    NSLog(@"app did launched");

    return XAMessageForward(application:(UIApplication *)application
                            didFinishLaunchingWithOptions:(NSDictionary *)launchOptions);
}

@end
#undef AtAspectOfClass
#undef AtAspect

Here is the code injected into the application:(UIApplication) application didFinishLaunchingWithOptions:(NSDictionary) launchOptions method of the AppDelegate class, just an output statement;
You can write any code here that needs to be initialized when the program starts, for example, third-party information registration such as sharing, pushing, etc.
It works the same as application:(UIApplication) application didFinishLaunchingWithOptions:(NSDictionary) launchOptions written in the AppDelegate class.
Similarly, he can inject code into the methods of any system's classes, such as:

#define AtAspectOfClass NSObject
@classPatchField(NSObject)


/**
 Methods to be added

 @param - Method Type: - Instance Method; + Class Method
 @param BOOL return type
 @param UIApplication Method Entity
 @return Return
 */
AspectPatch(-, instancetype, init)
{
    // Add your custom implementation here.
    NSLog(@"[Init]: %@", NSStringFromClass([self class]));

    // Forward the message to the origin implementation.
    return XAMessageForward(init);
}

@end

This information is printed when all NSObject classes are initialized.

Give one more:

#define AtAspectOfClass UIViewController
@classPatchField(UIViewController)

@synthesizeNucleusPatch(Default, -, void, viewDidLoad);
@synthesizeNucleusPatch(Default, -, void, viewDidAppear:(BOOL)animated);

AspectPatch(-, void, viewDidLoad){

    DDLogInfo(@"[CocoaLumberjack Log]: %@'s view did load.", NSStringFromClass([self class]));

    return XAMessageForward(viewDidLoad);
}

AspectPatch(-, void, viewDidAppear:(BOOL)animated){

    DDLogInfo(@"[CocoaLumberjack Log]: %@'s view did appear.", NSStringFromClass([self class]));

    return XAMessageForward(viewDidAppear:(BOOL)animated);
}

@end

That's the basic use. Here's a look at the sentences used:

#define AtAspect LZProjectName

Define a namespace, which generates a unique identifier in the current context. Defining a namespace with this macro is mandatory

#define AtAspectOfClass AppDelegate
@classPatchField(AppDelegate)

@end

Use @classPatchField (<#ClassName#>)... @end Field to create a class to implement the code you need to inject, similar to @ implementation... @end Before that, you need to use the macro #define AtAspectOfClass <#ClassName#> class to define the class that needs to be injected into code, where the class name matches the parameter class name in @classPatchField (<#ClassName#>).

@synthesizeNucleusPatch(Default, -, void, viewDidLoad);

Before implementing the XAspect method, you must ensure that it exists in the source class. The macro @synthesizeNucleusPatch() can detect if the method exists in the source class. If it does not, go back and try calling the default method, or an exception will be thrown.

Parameters:

  • First: Type, there are two types
    1.Default: If neither the current class nor its parent implements this method, XAspect will attempt to call a default method with a return value of nil/0;
    2.SuperCaller: If its parent implements this method and the current class does not, XAspect calls the parent's method.
  • Second: Method Type - Instance Method; + Class Method
  • Third: Method return value type
  • Fourth: Method Entities
@tryCustomizeDefaultPatch()

If we want to specify a return value type when a method does not exist, we can use this method.
For example, if the source class does not implement the -application:didFinishLaunchingWithOptions:method, we want to return YES directly, as follows:

@tryCustomizeDefaultPatch(1, -, BOOL, application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions) {
// Don't implement any logic here, just return a value.
    return YES;
}

If you want to change the return value or behavior of a parent method, you can do so:

@tryCustomizeSupercallerPatch(1, -, void, viewDidLoad) {
    XAMessageForwardSuper(viewDidLoad); // invoke superclass's implementation.
}
XAMessageForward(application:(UIApplication *)application
                            didFinishLaunchingWithOptions:(NSDictionary *)launchOptions)

In the AspectPatch macro, you need to use the XAMessageForward macro to forward messages to the source class.

Write more confusing, more can refer to the demo in the source code.

Topics: Programming iOS github