Series of articles:OC Basic principle series.OC Basic knowledge series.Swift bottom exploration series.IOS Advanced advanced series

In the previous article we saw how to create componentized projects. In this article we will talk about the focus of componentization: componentized communication

Componentized communication method

At present, there are three mainstream ways to understand:

  • 1.URLrouting
  • 2.target-action
  • 3.protocolmatching

Protocol trial programming

Use protocol definition specifications at the compile level to implement in different places to achieve distributed management and maintenance of components. This approach also follows the principle of dependency inversion and is a good object-oriented programming practice.

But the plan is also obvious:

  • Due to theProtocol programming lacks a unified scheduling layer, resulting inDifficult to centralize, especiallyProjects get bigger,The team has moreIn the case of,Architectural governance becomes more and more important.
  • Protocol programming interfaceDefine patternToo specification, thus making the architectureNot flexible enough. When you need to introduce aNew design patterns to developWe will find outIt's hard to fit into the current architecture,Lack of architectural uniformity.

middle-borns

It uses the intermediary unified management to control the call relationship between components in the entire life cycle of the App. At the same time, iOS also needs to maintain consistency in the design of component interfaces, so as to facilitate the unified call of intermediaries.

The split components depend on the intermediary, but there is no interdependence between the groups. Communication between components is easier to manage because all other components depend on this intermediary, and communication between components is uniformly scheduled through the intermediary. New design patterns can also be easily added on top of the intermediate, making the architecture easier to extend.

A good architecture is robust and flexible. Easy management of an intermediate architecture leads to a more stable architecture, and easy scalability leads to flexibility.

URL routing

This is also the communication scheme used by many iOS projects. It is based on route matching, or according to the naming convention, the Runtime method is used for dynamic invocation. The IDEA of URL routing adopts the middle-of-the-road mode

  • Advantages:Implement a simple
  • Cons: NeedMaintain the string tableOr,Depends on the naming convention.Can'tinCompile-time exposureOut of allThe problemThat need to be inThe runtimeIn order toFind the error.

Advantages and disadvantages of URL routing

“Advantages”

  • Extremely dynamic, suitable for apps with frequent operation activities. For example, e-commerce
  • Convenient unified managementMulti-platform routing rules
  • Easy to adapt to URL schemes

“Defect”

  • The parameter transmission mode is limitedAnd,Cannot use compile time for parameter type checking(All arguments are converted by string)
  • This applies only to interface modules.Does not apply to generic modules
  • The parameter format is not clearIs a flexible dictionary, and you need a place to look at the parameter format
  • Do not support the storyboard
  • Depends on string hardcoding, difficult to manage, mogujie specially to do a background management of this part
  • There is no guarantee that all modules used will exist
  • The decoupling capability is limitedURL “register”, “implement”, “use” must be usedSame string rules, changes made by either party will invalidate the code elsewhere, andRefactoring is difficult

The URL routing mode is mainly MGJRouter represented by Mogujie

MGJRouter

The realization idea is as follows:

  • The App is startedInstantiate the component modules, and then theseThe component registers the URL with MGJRouterAnd, in some cases,No instantiation is required.Using Class registration

  • whenComponent ANeed to becallcomponentB when.Pass the URL to the ModuleManager.Parameters are passed as GET along with the URL.Similar openURL. And then byThe ModuleManager is responsible for scheduling component BAnd finally finish the task.

MGJRouter usingURL routingBut hisDecoupling abilityorCo., LTD.

In addition to the MGJRouter above, there are the following tripartite frameworks

  • routable-ios
  • JLRoutes
  • HHRouter

target-action

This solution is based on the OC runtime/category feature to dynamically fetch modules, such as NSClassFromString to fetch classes and create instances, and NSInvocation to dynamically invoke methods via performSelector+NSInvocation

This method is mainly represented by CTMediator of Casatwy

CTMediator

The implementation of CTMediator:

  • 1.Use classificationforAdd a new interface to the routeIn theinterfacethroughString gets the corresponding class
  • 2. ByruntimeCreate an instance,Dynamically invoke the instance's methods

Specific usage: The reference relationships between modules are as follows: “Advantages”:

  • usingclassificationcanThe statement interface,Compile the inspection
  • implementationlightweight

【 Disadvantages 】:

  • Need to be inMediator and targetIn theTo addeachinterface.modularwhencodeThe moretedious
  • incategoryStill want toHard coding of strings is introducedFor internal useDictionary and referenceAnd, to some extent, there are also alpha and betaURL routing same problem
  • There is no guarantee that the module being used exists.Target after modification, the user can only use theErrors can only be found at runtime
  • createToo many Target classes, resulting inTarget class flood

CTMediator source code analysis

CTMediator uses URL routing

This method is mainly aimed at mutual tuning of remote apps. The jump between apps is realized through openURL, and data is transferred through URL

CTMediator usesRuntime decoupling, the decoupling core method is shown as follows:

  • performTarget:action:params:shouldCacheTarget:The method is mainly righttargetNameandactionNameFault-tolerant processing, that is, processing that does not respond to the calling method.
  • This method encapsulatessafePerformAction:target:paramsMethod, enter the parameterTargetName is the object that calls the interface.ActionName is the name of the invoked method.Params are parameters.
  • And you can also see in the code that there are onlyThe object of the class that satisfies the Target_ prefixandOnly the Action_ method can be used by CTMediator. At this point, we can see the advantage of the intermediary architecture, which is conducive to unified management and can easily control the rules formulated.

So let’s focus on thatWith the actionIn the case

protocol class

Protocol matching is implemented as follows:

  • 1. TheprotocolAnd the correspondingclassforDictionary matching
  • 2. By usingProtocol for the classAgain,Dynamically creating an instance

A typical tripartite framework for Protocol is Alibaba’s BeeHive. BeeHive borrowed from the Spring Service, Apache DSO architecture concept, using AOP+ extension App life cycle API form, the business function, basic function module way to solve complex problems in large applications, and between modules in the form of Service call, complex problems will be divided, Modularize services in an AOP manner

BeeHive core ideas

  • 1.Call between modulesFrom directCall the corresponding moduleTo becomeThe form of calling a Service.Avoid direct dependencies
  • 2. Distribution of App life cycle willThe coupling is split logically in the AppDelegate, each module starts withMicro applicationThe form of exists independently.

“Advantages”

  • 1.Using an interface callTo realize parameter transferType safety
  • 2. Use it directlyThe protocol interface of the module.No need for repeated encapsulation

“Defect”

  • 1. UseFramework to create all objects, which does not support external parameter transmission
  • 2. UseOCtheruntimeCreate an object,Do not support the Swift,
  • 3. OnlyprotocolandclassThe match,More complex creation methods and dependency injection are not supported
  • 4.There is no guarantee that the protocol used must have a corresponding moduleAlso,You can't tell directlyaWhether protocol can be used to get modules

In addition to BeeHive, there is Swinject

Module registration in BeeHive

BeeHive manages each module mainly through the BHModuleManager. Only registered modules are managed in the BHModuleManager

BeeHive provides three different invocation forms, static plist, dynamic registration, and annotation. Module and Service are not associated. Each Service Module can independently implement functions of Module or Service.

Annotation registration

This way is mainly throughBeeHiveMod macroforThe Annotation tag Here for__attributeA few points need to be made

  • The first parameterused:Modify functions.Is decorated, informsIn the future, even thoughThe function is not referencedIn theReleaseAlso underIt's not optimized. ifWithout this embellishment, thenRelease environment linkerunderRemove sections that are not referenced.
  • Through the use of__attribute__((section("name")))toSpecify which paragraph.The data is tagged with __attribute__((used)).Linker preventionwillOptimize the deletion of unused segmentsAnd thenInject modulestoIn the __DATA

Now that the Module has been stored in a special section of the Mach-O file, how do I get it?

  • The BHReadConfiguration method is displayed, mainlyThrough the Mach - OfindstoragetheData segment.Take out put in arrayIn the

Read the local Pilst file

  • First of all, you need toSet up a path

  • createplistFile,plistThe file format is also an array containing multiple dictionaries. There are two keys in the dictionary, one is"moduleLevel"And the other one is"moduleClass". Pay attention toThe rootThe name of the array is"moduleClasses".

  • Go to the loadLocalModules method and basically get the array from the PList and add the array to the BHModuleInfos array

Load method registration

The methodTo register the ModuleIs in theThe load methodinsideRegister Module classes

  • Enter theregisterDynamicModuleimplementation

The bottom layer is the same as the first one, and it will eventually go toaddModuleFromObject:shouldTriggerInitEvent:In the method

  • The load method can also be usedBH_EXPORT_MODULE macroInstead of

The BH_EXPORT_MODULE macro can pass in a parameter that indicates whether the Module is loaded asynchronously, if YES, or synchronously if NO.

BeeHive module event

BeeHive provides life cycle events for each module to interact with the BeeHive host environment and sense changes in the module’s life cycle.

BeeHiveEach module receives events. inBHModuleManagerAll of themThe eventbeDefined astheBHModuleEventType enumeration. As you can see below, there are two special events, one isBHMInitEvent, one isBHMTearDownEvent There are three main types

  • 1.System events: Mainly refers toApplication life cycle events

The general practice isAppDelegateInstead ofInherited from BHAppDelegate

  • 2.Application events: Official flow chart, whichModSetup, modInitCan be used forEncoding the implementation of each plug-in moduletheSetup and initialization.

  • 3. Customize events

All of the above events can be calledBHModuleManager的triggerEvent:To deal with.As can be seen from the above code, removeBHMInitEvent Indicates the initialization eventandBHMTearDownEvent Event that a Module is removedAll events except these two special events are calledhandleModuleEvent:Method, whose internal implementation is mainlyIterate through the BHModules instance array, the callperformSelector:withObject:Method implements the corresponding method call

Note: all modules here must be BHModuleProtocol compliant or they will not receive messages for these events.

The BeeHive module is called

In BeeHive, the BHServiceManager manages each Protocol. BHServiceManager manages only registered protocols.

There are three ways to register the Protocol, which correspond to the Module registration mentioned above

Annotation registration

Read the local PList file

  • First, as with Module, you need to set the path first

  • Set the plist file

  • Also register services in setContext

Protocol registration

It’s basically callingBeeHiveThe inside of thecreateService:completeprotocolThe registration of createServiceWill firstCheck whether the Protocol is registeredBefore. Then fetch the corresponding Class in the dictionary, if implementedshareInstanceMethod, thenCreate a singleton objectIf not, create oneInstance objects. If you stillImplementing the singleton, can be furtherimplInstanceandserviceStrLambda plus lambdaBHContexttheservicesByNameThe dictionaryThe cacheTo get up. This can then be passed with context

  • Enter theserviceImplClassImplementation, as you can see hereprotocolAnd the class is passedThe dictionaryThe binding,protocolAs akey.ServiceImp (the name of the class) as value

Module & Protocol

Here’s a summary:

  • forModule:An array of storage
  • forProtocolThrough:The dictionarywillprotocolwithclassforThe binding.keyforprotocol.valueforserviceImpThe name of the class

Auxiliary class

  • BHConfigClass: YesThe singletonAnd there’s one insideNSMutableDictionaryThe type ofThe config attributeThis property maintains a number of dynamic environment variables asBHContextSupplementary existence of
  • BHContextClass: is a singleton with two internal instancesNSMutableDictionaryProperties of, respectivelymodulesByNameandservicesByName. This class is mainly used to store context information. Such as:application:didFinishLaunchingWithOptions:A large amount of context information can be initialized

  • BHTimeProfilerClass: used to performComputational time performanceIn terms ofProfiler
  • BHWatchDogClass: used to start a thread,Listen for the main thread to block

Related articles recommended links

  • BeeHive – an elegant but still improving decoupling framework
  • BeeHive, an iOS module decouple practice
  • Good mobile iOS componentized (modular) architecture design practice

The last

Several months later, I stayed up late to write a lot of articles about the bottom of OC. In this process, I got a new understanding of OC. The content research of OC is now in the end! Later, I will share some ideas of encapsulation and architecture that I think are better in the actual development. I will continue to explore the bottom of Swift, and will continue to update the article. I hope we can communicate with each other and make progress together. Thank you very much!