SoFunction
Updated on 2025-04-12

Dynamic ideas for the application of iOS Lotusoot modular tool

The following is written as Swift dependencies

OC library, no namespace

Key points of componentization - agreement

Personally think

For example, the registration of URL routes means passing on the agreed information. As a service.

Lotusoot contains service calls, short chain registration and calls

The following focuses on service calls, short links are a little bit

Scene

project has two dependencies: A (protocol) and B (the implementer of the protocol, providing services)

project reference A, know the protocol information

project does not reference B, project knows nothing about B

In this way, the project removes B and compiles faster

B depends on A, references A, implements A's protocol and provides services

Calling the service

        // Get the key        let lotus = s()
        // kv obtains an example of providing services        let accountModule: AccountLotus = (lotus: lotus) as! AccountLotus
        // Call service        (username: "zhoulingyu", password: "wow") { (error) in
            print(error ?? "1234")
        }

Step 3: Calling the service is very simple

Step 2 is very exciting, making full use of the static features of Swift compile time

The protocol method is determined at compile time

Several parameters are required, and what type of parameters can generally be used explicitly

Don't see a parameter dictionary, ah, what's this

// Step 2.  Take from below// Key-value pair, value is the object that provides the servicevar lotusootMap: Dictionary = Dictionary<String, Any>()

Step 1: Get the key

Here is the protocol name as key

// Use generics to describe// Agreement, transfer the agreement namepublic extension String {
    init<Subject>(_ instance: Subject) {
        (describing: instance)
    }
}
/// Quickly get strings with Subjectpublic func s<Subject>(_ instance: Subject) -> String {
    return String(instance)
}

Register Service

1. Project does not have import B (providing services). How to use the function of B?

public static func registerAll(serviceMap: Dictionary<String, String>) {
        for (lotus, lotusootName) in serviceMap {
            // lotus, protocol name            // lotusootName, package name. Class name            let classStringName = lotusootName
            // Reflect, produce class            // The class that provides services must be a subclass of NSObject and has an init method (this is a convention)            let classType = NSClassFromString(classStringName) as? 
            if let type = classType {
                // Generate the corresponding instance and force it to comply with the agreement,                let lotusoot = ()
                register(lotusoot: lotusoot, lotusName: lotus)
            }
        }
    }

2. Here we use python script to register. The information is obtained during compilation. Protocol name: package name. Class name

By agreement, mark

// @NameSpace(ZLYAccountModule)
// @Lotusoot(AccountLotusoot)
// @Lotus(AccountLotus)
class AccountLotusoot: NSObject, AccountLotus {}

Python scripts find out marks, integrate, and put them inplistIn the file

1, script entry

lotusootSuffix = 'Lotusoot'
length = len()
if length != 3 and length != 4:
    print 'parameter error'
    os._exit(1)
if length == 4:
    lotusootSuffix = [3]
    lotusootFiles = findLotusoots(scanPath, lotusootSuffix + '.swift')
else:
    // Go here    lotusootFiles = findAmbiguityLotusoots(scanPath)

Go through every swift file

def findAmbiguityLotusoots(path):
    list = []
    for root, subFolders, files in (path):
        # Ignore 'Target Support Files' and ''
         // No processing is required        if 'Target Support Files' in subFolders:
            ('Target Support Files')
        // No processing is required,        if '' in subFolders:
            ('')
        // Every file        for f in files:
             // Every Swift file            if ('.swift'):
                // Get the tag configuration                tup = getLotusootConfig((root, f))
                if tup[0] and tup[1] and tup[2]:
                    // All three are satisfied, and the file path is added                    (f)
    return list

Scan every line,

Get the configuration, the package name and namespace you see above

@NameSpace(ZLYAccountModule)

The class name seen above

@Lotusoot(AccountLotusoot)

The key (protocol name) seen above

@Lotus(AccountLotus)

def getLotusootConfig(file):
    lotus = ''
    lotusoot = ''
    namespace = ''
    // Flip through every line of the file    for line in open(file):
        // The key seen above        if getLotus(line):
            lotus = getLotus(line)
         // The class name seen above        if getLotusoot(line):
            lotusoot = getLotusoot(line)
        // The package name, namespace seen above        if getNameSpace(line):
            namespace = getNameSpace(line)
    return (lotus, lotusoot, namespace)

... There are many more,

Logic is to get the configuration and write a plist

When running, start

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [ : Any]? = nil) -> Bool {
        ()
        return true
    }

Registration means reading the plist just written as a dictionary of [Protocol name: package name.class name],

@objc public static func registerAll() {
        let lotusPlistPath = (forResource: "Lotusoot", ofType: "plist")
        if let lotusPlistPath = lotusPlistPath {
            let map = NSDictionary(contentsOfFile: lotusPlistPath)
            registerAll(serviceMap:  map as! Dictionary<String, String>)
        }
    }

Echoing the above

Dynamic ideas

Enter the dynamic idea and register KV dynamically (Protocol name: Service library name. Class name)

There is an impression above, just know the scene

Writing a long text,

How to reflect my 10 years of work experience?

No, insist on getting the word count

1. Project gets the key (protocol name), yes

2. project gets all dependency information

With MachO you can

3. project gets the name of the service class

Make sure module B's class name = key (protocol) + Cls

MachOGet the names of all dependency libraries, each + "." + key (Protocol) + Cls=MachOGet the names of all dependency libraries, each + "." + module B's class name

Then, see if it can be instantiated.

Can be instantiated, just OK

After trying it, it cannot be instantiated, so it will be an error

Probably depend on B, not added

It may depend on B's class name, and it was written incorrectly

project gets the name of the service class, elegant

Make sure module B's class name = key (protocol) + Cls,

Hard code is not good

Rely on A (to put protocol), add a protocol

public protocol Maid{
    var name: String{ get }
}

In module B, there must be a class called key (protocol) + C

This category, comply withMaidprotocol.

Through the protocol attribute, return the name of the service class in B

class AccountLotusC: NSObject, Maid{
    var name: String{
        return String(reflecting: )
    }
}

This process is more consistent with the design of the modular utilization protocol above.

The agreement is to implement the service module of the agreement.

There must be a key + C class

Name of the service class

Hard coded, relatively minor

Code implementation

1. MachO obtains namespace

import MachO
lazy var moduleNames: [String] = { () -&gt; [String] in
        // Find the project name and remove it later        let mainNameTmp = NSStringFromClass()
        guard let mainName = (separatedBy: ".").first else{
            fatalError("emptyMainProject")
        }
        var result = [String]()
        let cnt = _dyld_image_count()
        // Process all packages, system, and user's         for i in 0..&lt;cnt{
             if let tmp = _dyld_get_image_name(i){
                 let name = String(validatingUTF8: tmp)
                 // System, don't worry                 if let candidate = name, ("/Users"){
                     if let tmp = (separatedBy: "/").last{
                         // Remove project                         if tmp != mainName{
                             // Get user dependencies                             (tmp)
                         }
                     }
                 }
             }
         }
         return result
    }()

The above, the emulator is OK, I haven't tried it in real machine (no development certificate at hand)

2. Verification of package name + class name

@objc public static func lotusoot(lotus: String) -&gt; Any? {
        // It has been cached        if let val = [lotus]{
            return val
        }
        else{
            var i = 0
            let names = 
            let cnt = 
            // traversal, user package            while i &lt; cnt{
                // As agreed, try to create assistants                let classType = NSClassFromString(names[i] + "." + lotus + "C") as? 
                if let type = classType {
                    // Instantiation, helper class                    let assist = ()
                    if let maid = assist as? Maid{
                         // Get the name of the service class that module B                        let classType = NSClassFromString() as? 
                        if let type = classType {
                            // Instantiate the service class of module B                            let lotusoot = ()
                            register(lotusoot: lotusoot, lotusName: lotus)
                        }
                        // The default is a module and a service class.                        // Exclude user classes that have been used                        (at: i)
                        break
                    }
                }
                i+=1
            }
            if let val = [lotus]{
                return val
            }
            else{
                fatalError("name Module of" + lotus)
            }
        }
    }

GitHub repo

This is the end of this article about the dynamic ideas of the application of iOS Lotusoot modular tools. For more related iOS Lotusoot modular content, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!