AOP-oriented programming of iOS decoupling mode

Source: Internet
Author: User
Tags aop
MVVM decoupling Demo and blog introduction approach to slicing programming (AOP) Demo

At runtime, the programming idea of dynamically slicing code into the specified method of the class, specifying the location, is the aspect-oriented programming.

Aspect-oriented programming (AOP is the acronym for Aspect Oriented program), we know that object-oriented features are inheritance, polymorphism, and encapsulation. Encapsulation requires that the function be dispersed to different objects, which is often called responsibility assignment in software design. In other words, let the different classes design different methods. So the code is dispersed into a class. The benefit of this is to reduce the complexity of the code and make the class reusable.
But it has also been found that the code is more repetitive as it is distributed. What does that mean. For example, in two classes, we might need to log in each method. In the object-oriented design approach, we have to include the contents of the log in the two-class approach. Maybe they are exactly the same, but because object-oriented design makes it impossible to connect classes to classes, and not to unify these repetitive code.
Maybe someone would say, well, we can write this code in a separate class-independent method, and then call it in these two classes. However, in this way, these two classes are coupled to the independent classes we mentioned above, and their changes affect these two classes. So, is there any way that we can add code at random when we need it? At runtime, the programming idea of dynamically slicing code into the specified method of the class, specifying the location, is the aspect-oriented programming.
In general, the code fragment that we cut into the specified method of the specified class is called the slice, and which classes and which methods are called pointcuts. With AOP, we can extract code that is common to several classes into a slice, and then move on to the object as needed to change its original behavior.
In this way, AOP is just a complement to OOP. OOP distinguishes a class from the landscape, while AOP adds a specific code to the object vertically. With the Aop,oop become stereo. If you add the time dimension, AOP makes oop from the original two-dimensional to three-dimensional, from the plane into three-dimensional. Technically, AOP is basically implemented through proxy mechanisms.
AOP is a landmark in the history of programming and is a useful complement to OOP programming.


Demo Introduction

1. Global management report separate pull away

2. Page first entry Refresh

3. Add controls to the page dynamically

4. Maintain the global stack

The demo here is just a simple idea.

first of all, our core ideas for the controller of the cycle of the hook, here can provide two kinds of containers, one is the global static container storage global common functions, there is a and viewcontroller binding a category, each controller corresponds to an array, Used to store the required slicing functionality. Slicing is actually a function of a class, when needed to inject into the container inside the line, in the hook to the life cycle function, take out the operation can be.


1.Hook Exchange Method

Swap methods void Mkjcontrollerlifecircleswizzinstance (class class, Sel originalselector, sel swizzledselector) {method or
    Iginalmethod = Class_getinstancemethod (class, Originalselector);
    
    Method Swizzledmethod = Class_getinstancemethod (class, Swizzledselector); BOOL Didaddmethod = Class_addmethod (class, Originalselector, Method_getimplementation (Swizzledmethod), Method_
    
    Gettypeencoding (Swizzledmethod)); if (Didaddmethod) {Class_replacemethod (class, Swizzledselector, Method_getimplementation (Originalmethod), meth
    Od_gettypeencoding (Originalmethod));
    else {method_exchangeimplementations (Originalmethod, Swizzledmethod);
    } + (void) load{class Viewcontrollerclass = [Uiviewcontroller class]; Mkjcontrollerlifecircleswizzinstance (Viewcontrollerclass, @selector (viewdidappear:), @selector (Mkj_hook_
    Viewdidappear:)); Mkjcontrollerlifecircleswizzinstance (Viewcontrollerclass, @selector (viewdiddisappear:), @selector (Mkj_hook_viEwdiddisappear:)); Mkjcontrollerlifecircleswizzinstance (Viewcontrollerclass, @selector (viewwillappear:), @selector (Mkj_hook_
    Viewwillappear:)); Mkjcontrollerlifecircleswizzinstance (Viewcontrollerclass, @selector (viewwilldisappear:), @selector (Mkj_hook_
Viewwilldisappear:)); }


2. Association containers for Global containers and Viewcontroller

Lazy load of Global action store Nsmutablearray * Mkjviewcontrollerglobalaction () {static Nsmutablearray *mutablearray = nil;
    Static dispatch_once_t Oncetoken;
    Dispatch_once (&oncetoken, ^{mutablearray = [[Nsmutablearray alloc] init];
    });
return mutablearray; ///Global registers to Simple array void mkjviewcontrollerregisterglobalaction (Mkjviewlifecirclebaseaction *action) {void (^register) (Voi
        D) = ^ (void) {nsmutablearray* actions = mkjviewcontrollerglobalaction (); if (![
        Actions Containsobject:action]) {[Actions addobject:action];
    
    }
    };
    if ([Nsthread Mainthread]) {Register ();
        else {Dispatch_async (Dispatch_get_main_queue (), ^{Register ();
    }); }//Remove void Mkjviewcontrollerremoveglobalaction (Mkjviewlifecirclebaseaction *action) {void (^remove) (void) = ^ (Voi
        d) {nsmutablearray* actions = mkjviewcontrollerglobalaction ();
     if ([Actions containsobject:action]) {       [Actions removeobject:action];
    }
    };
    if ([Nsthread Mainthread]) {Remove ();
        else {Dispatch_async (Dispatch_get_main_queue (), ^{Remove ();
    }); }
}

/Category Association Properties-(void) Setlifecircleaction: (Nsarray *) array{objc_setassociatedobject (self, Mkjviewappearkey, array, O
Bjc_association_retain);
    }-(Nsarray *) getlifecircleaction {Nsarray *array = Objc_getassociatedobject (self, mkjviewappearkey);
    If the first time you do not get a nil if it does not set up an if ([Array Iskindofclass:[nsarray class]]) {return array;
return [Nsarray array]; ///According to the page registration to the need to cut the operation of the binding mount to the corresponding VC above, this is not global, is based on the VC-bound array-(mkjviewlifecirclebaseaction*) Registerlifecircleaction: ( Mkjviewlifecirclebaseaction *) Action {nsmutablearray* array = [Nsmutablearray arraywitharray:[self getLifeCircleActio
    N]]; if ([array containsobject:action]) {for (Mkjviewlifecirclebaseaction* Act in array) {if [action IsE
            Qual:act]) {return act;
    }} [array addobject:action];
    [Self setlifecircleaction:array];
Return action;
 }//Remove-(void) Removelifecircleaction: (mkjviewlifecirclebaseaction *) Action {   nsarray* array = [self getlifecircleaction];
    Nsinteger index = [array indexofobject:action];
    if (index = = nsnotfound) {return;
    } nsmutablearray* Marray = [Nsmutablearray Arraywitharray:array];
    [Marray Removeobjectatindex:index];
[Self setlifecircleaction:array];
 }
3.Hook Execution Method
Four hooks come out of the method-(void) Mkj_hook_viewwillappear: (BOOL) animated{[self mkj_hook_viewwillappear:animated]; [Self mkj_hook_performaction:^ (mkjviewlifecirclebaseaction *action) {if ([Action respondstoselector: @selector (hookviewcontroller:viewwillappear:)]) {[Action Hookviewcon
        Troller:self viewwillappear:animated];
}
    }];
    }-(void) Mkj_hook_viewdidappear: (BOOL) animated{[self mkj_hook_viewdidappear:animated]; [Self mkj_hook_performaction:^ (mkjviewlifecirclebaseaction *action) {if ([Action respondstoselector: @selector (hookviewcontroller:viewdidappear:)]) {[Action Hookviewcont
        Roller:self viewdidappear:animated];
}
    }];
    }-(void) Mkj_hook_viewwilldisappear: (BOOL) animated{[self mkj_hook_viewwilldisappear:animated]; [Self mkj_hook_performaction:^ (mkjviewlifecirclebaseaction *action) {if ([Action respondstoselector: @selector (hookviewcontroller:viewwilldisappear:)]) {[Action HookviewController:self viewwilldisappear:animated];
}
    }];
    }-(void) Mkj_hook_viewdiddisappear: (BOOL) animated{[self mkj_hook_viewdiddisappear:animated]; [Self mkj_hook_performaction:^ (mkjviewlifecirclebaseaction *action) {if ([Action respondstoselector: @selector (hookviewcontroller:viewdiddisappear:)]) {[Action HOOKVIEWC
        Ontroller:self viewdiddisappear:animated];
}
    }]; The method execution code for the/** hook first gets the global container and the associated container to traverse, and then executes the slice action stored inside @param block callback/-(void) Mkj_hook_performaction: (Mkjaopac
    
    Tionblock) block{//1. Get Global Action Simple mkjcallbackaction ([Mkjviewcontrollerglobalaction () copy], block);
2. Get the mounted action mkjcallbackaction the array stored by the page ([[Self getlifecircleaction] copy], block);  }//execute Action void mkjcallbackaction (nsarray* actions, Mkjaopactionblock block) {for (mkjviewlifecirclebaseaction*
        Action in Actions} {if (block) {blocks (action); }
    }
}

4. Create a slice action

Depending on the function you hook up to, you actually remove the action that was injected into the container before you take the action, and the global container is the one that is managed by whichever controller, and the optional associated container is bound by the page, so the container self is triggered when the trigger is

/** the
 base class of all slices of the base class is processed by the periodic function of VC
 * *
@interface mkjviewlifecirclebaseaction:nsobject

@property ( nonatomic,strong,readonly) Uiviewcontroller *liveviewcontroller;


-(void) Hookviewcontroller: (Uiviewcontroller *) controller viewwillappear: (BOOL) animated;

-(void) Hookviewcontroller: (Uiviewcontroller *) controller viewdidappear: (BOOL) animated;

-(void) Hookviewcontroller: (Uiviewcontroller *) controller viewwilldisappear: (BOOL) animated;

-(void) Hookviewcontroller: (Uiviewcontroller *) controller viewdiddisappear: (BOOL) animation;


@end

5. Global slices

A global slice is a code that does not need to write any processing outside, directly in this class, load is added to the data can be recalled

@implementation mkjviewcontrollerlogaction//Global registration + (void) load{//register to the global static array, each page cycle function triggers hook will enter here to print log Mkjview
Controllerregisterglobalaction ([[Mkjviewcontrollerlogaction alloc] init]); }//This action can be used to do global printing, easy to use, in the load can be removed or injected, completely does not affect the business logic and Pollution Code-(void) Hookviewcontroller: (Uiviewcontroller *)
    Controller viewwillappear: (BOOL) animated{[Super Hookviewcontroller:controller viewwillappear:animated];
NSLog (@ "viewcontroller---->%@-------SEL------>%@", Controller,nsstringfromselector (_cmd)); }-(void) Hookviewcontroller: (Uiviewcontroller *) controller viewdidappear: (BOOL) animated{[Super Hookviewcontroller:
Controller viewdidappear:animated]; }-(void) Hookviewcontroller: (Uiviewcontroller *) controller viewwilldisappear: (BOOL) animated{[Super Hookviewcontrol
    Ler:controller viewwilldisappear:animated];
NSLog (@ "viewcontroller---->%@-------SEL------>%@", Controller,nsstringfromselector (_cmd)); }-(void) Hookviewcontroller: (Uiviewcontroller *) Controller VIewdiddisappear: (BOOL) animation{[Super Hookviewcontroller:controller viewdiddisappear:animation];} @end

6. Special slice action (optional)

Private responsibilities depending on the container above, the array is based on the page, so you need to add a small number of registered code on the page

-(Instancetype) Initwithactionblock: (mkjviewcontrollerfirstappearblock) block{
    self = [super init];
    if (self) {
        _isfirstappear = YES;
        _actionblock = Block;
    }
    return self;
}

-(void) Hookviewcontroller: (Uiviewcontroller *) controller viewwillappear: (BOOL) animated{
    [Super Hookviewcontroller:controller viewwillappear:animated];
    if (_isfirstappear) {
        if (_actionblock) {
            _actionblock (controller,animated);
        }
        _isfirstappear = NO;
    }
    
Mkjviewcontrollerfirstenteraction *firstaction = [[Mkjviewcontrollerfirstenteraction alloc] initWithActionBlock:^ ( Viewcontroller *controller, BOOL animation) {
        [controller pop:animation];
    }];
    [Self registerlifecircleaction:firstaction];


Here follow a blogger's ideas and code to write a look at the analysis, the basic logic is very clear

Bottom Slice logic

Based on the bottom slice, the controller jumps to the slice realization, maintains a global stack with the slice


Update:

The above AOP implementations are based on the exchange of the upper SEL and imp, and the simplest way

There is a wheel on the net based on runtime message forwarding intercept, each message is dynamically pointing to objc_msgforward into the forwarding process to achieve

Aspects




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.