Aspects-iOS's AOP cross-section programming library, aspectsaop

Source: Internet
Author: User

Aspects-iOS's AOP cross-section programming library, aspectsaop
Introduction

A concise and efficient library that enables iOS to support AOP for Aspect-Oriented Programming. it helps you change the behavior of a class without changing the code of a class or class instance. it is simpler and more efficient than the traditional iOS AOP method. you can execute a method either before or after it is executed. I used to be a part of PSPDFKit. PSPDFKit has applications in Dropbox and Evernote. It is now open-source for everyone.

Project homepage: Aspects

Latest instance: Click to download

Note: AOP is a completely different design mode from OOP. For more information, refer to: AOP Baidu encyclopedia

Quick Start environment requirements
  • ARC
  • IOS 7 + or OS X 10.7 +
Install and use CocoaPods
pod "Aspects"
Manual Installation

FileAspects. h/mDrag it to the project.

Application scenarios

Aspects is used to support the AOP (Aspect-Oriented Programming) mode and is used to partially solve specific problems that the OOP (object-oriented) mode cannot solve. specifically, it refers to the operations that are not allowed or are difficult to be effectively classified in multiple methods, such:

  • Whenever a user obtains server data through a client, permission check is always required.
  • No matter when the user interacts with the market, more user operations should always be provided to purchase reference or related products.
  • All operations that require logging.
Interface Overview

AspectsNSObject extends the following method:

/// Add a block of code before/After a method of a specified class is executed. all objects in this class will work. ///// @ param block when the hook is added, Aspectes copies the signature information of the method. /// the first parameter will be 'id <AspectInfo> ', and the remaining parameters will be the parameters of the called method. /// these parameters are optional and will be used to pass the parameters to the corresponding position of the block code block. /// you even use a block code block without any parameters or with only one 'id <AspectInfo> 'parameter. ///// @ Note: you cannot add a hook to a static method. /// @ return returns a unique value to cancel this hook. + (id <AspectToken>) aspect_hookSelector :( SEL) selector withOptions :( AspectOptions) options usingBlock :( id) block error :( NSError **) error; /// Add a block of code before/After a method of a specified object is executed. only applies to the current object. -(id <AspectToken>) aspect_hookSelector :( SEL) selector withOptions :( AspectOptions) options usingBlock :( id) block error :( NSError **) error; // undo an Aspect hook. /// @ return YES: The operation is successful. Otherwise, NO is returned. id <AspectToken> aspect = ...; [aspect remove];

 

All calls are thread-safe. aspects uses Objective-C to forward messages, resulting in performance consumption. aspects is not recommended for all calls that are too frequent. aspects is more suitable for view/controller-related code that calls no more than 1000 times per second.

Sample Code

You can use Aspects to dynamically add logging when debugging applications.

[UIViewController conditions: @ selector (viewWillAppear :) witexceptions: AspectPositionAfter usingBlock: ^ (id <AspectInfo> aspectInfo, BOOL animated) {NSLog (@ "Controller % @ will display: % tu ", aspectInfo. instance, animated);} error: NULL];

 

When you use it, the settings of the analysis function are simple:

Https://github.com/orta/ARAnalytics

You can use it in your test cases to check whether a method is actually called (when it involves inheritance or category extension, it is easy to see if a parent class/subclass method is not called as expected ):

-(Void) testExample {TestClass * testClass = [TestClass new]; TestClass * testClass2 = [TestClass new]; _ block BOOL testCallCalled = NO; [testClass aspect_hookSelector: @ selector (testCall) witexceptions: AspectPositionAfter usingBlock: ^ {testCallCalled = YES;} error: NULL]; [testClass2 testCallAndExecuteBlock: ^ {[testClass testCall];} error: NULL]; XCTAssertTrue (testCallCalled, @ "testCallAndExecuteBlock must call testCall ");}

 

It will play a major role in application debugging. here I want to know when the gesture state changes (if it is a subclass of your custom gesture, you can rewrite setState: method to achieve similar results; but the real purpose here is to capture the light-click gestures of all types of controls to accurately analyze the reasons ):

[_singleTapGesture aspect_hookSelector:@selector(setState:) withOptions:AspectPositionAfter usingBlock:^(id<AspectInfo> aspectInfo) {    NSLog(@"%@: %@", aspectInfo.instance, aspectInfo.arguments);} error:NULL];

 

The following is an example of when the controller you monitor a modal display disappears. generally, you can write a subclass to achieve similar effects, but using Aspects can effectively reduce your code volume:

@implementation UIViewController (DismissActionHook)// Will add a dismiss action once the controller gets dismissed.- (void)pspdf_addWillDismissAction:(void (^)(void))action {    PSPDFAssert(action != NULL);    [self aspect_hookSelector:@selector(viewWillDisappear:) withOptions:AspectPositionAfter usingBlock:^(id<AspectInfo> aspectInfo) {        if ([aspectInfo.instance isBeingDismissed]) {            action();        }    } error:NULL];}@end

 

Benefits for debugging

Aspectes automatically marks itself, so it is easy to check whether a method has been called in the call Stack:

Use Aspects when the return value is not void

You can use the NSInvocation object class to customize the return value:

[PSPDFDrawView aspect_hookSelector: @ selector (shouldProcessTouches: withEvent :) witexceptions: Using usingBlock: ^ (id <AspectInfo> info, NSSet * touches, UIEvent * event) {// call the original implementation of the method. BOOL processTouches; NSInvocation * invocation = info. response; [invocation invoke]; [invocation getReturnValue: & processTouches]; if (processTouches) {processTouches = Response (touches, event); [invocation setReturnValue: & processTouches];} error: NULL];

 


Compatibility and limitations
  • When applied to a class (using the class method to add a hook), the same method of the parent class and the subclass cannot be hooked at the same time; otherwise, the loop call problem may occur. however, this restriction does not apply to examples of a class (using the instance method to add hooks.
  • When using KVO, it is bestAspect_hookSelector:Add the observer after the call; otherwise, it may cause a crash.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.