Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

优化建议:registerServices 自动注册服务性能优化 #9

Closed
madaoCN opened this issue Dec 1, 2023 · 4 comments
Closed

优化建议:registerServices 自动注册服务性能优化 #9

madaoCN opened this issue Dec 1, 2023 · 4 comments

Comments

@madaoCN
Copy link

madaoCN commented Dec 1, 2023

// MARK: - 自动注册服务
    public class func registerServices() {
        
        let bundles = CFBundleGetAllBundles() as? [CFBundle]
        for bundle in bundles ?? [] {
            let identifier = CFBundleGetIdentifier(bundle);
            guard let id = identifier as? String,
                  id.hasPrefix("com.apple") == false else {
                continue
            }
            
            let execURL = CFBundleCopyExecutableURL(bundle) as NSURL
            let imageURL = execURL.fileSystemRepresentation
            let classCount = UnsafeMutablePointer<UInt32>.allocate(capacity: MemoryLayout<UInt32>.stride)
            guard let classNames = objc_copyClassNamesForImage(imageURL, classCount) else {
                continue
            }
            
            for idx in 0..<classCount.pointee {
                let currentClassName = String(cString: classNames[Int(idx)])
                guard let currentClass = NSClassFromString(currentClassName) else {
                    continue
                }
                
                if class_getInstanceMethod(currentClass, NSSelectorFromString("methodSignatureForSelector:")) != nil,
                   class_getInstanceMethod(currentClass, NSSelectorFromString("doesNotRecognizeSelector:")) != nil,
                   let cls = currentClass as? TheRouterServiceProtocol.Type {
                    
                    TheRouterServiceManager.default.registerService(named: cls.seriverName, lazyCreator: (cls as! NSObject.Type).init())
                }
            }
        }
    }

使用 objc_copyClassNamesForImage 方法查找对应的类,比 objc_getClassList 遍历效率更高

@summerHearts
Copy link
Contributor

summerHearts commented Dec 4, 2023

非常感谢,经过测试,此方案是可行的,尤其是对于大型项目而言。具体测试方式
image
新增了 org.cocoapods 过滤,考虑到组件化场景下,将会改为外部配置的方式传入。需要开发人员将自建的私有库bundleId修改为不是 org.cocoapods即可。
image
Demo测试工程数据如下:
image

过滤之后,基本为工程内的自建类。
Release环境下:
image
Debug环境下:
image

@summerHearts
Copy link
Contributor

在比较objc_copyClassNamesForImage和objc_getClassList两个函数的效率时,需要考虑它们的使用场景和目标:

objc_copyClassNamesForImage:

这个函数专门用于获取加载到特定库或框架中的所有类的名称。
如果您只对某个特定库(如动态链接库或框架)中定义的类感兴趣,这个函数会更高效,因为它只关注特定的图像(image)。
它返回的是类名字符串,而不是类对象,这可能在某些情况下会更快,特别是当您不需要类的实际元数据时。
objc_getClassList:

这个函数获取当前应用程序中所有已注册的类。
如果您的目标是获取应用程序中的所有类,无论它们属于哪个库或框架,那么objc_getClassList是更合适的选择。
由于它返回的是应用中所有类的列表,如果应用加载了大量的类,这个过程可能会相对较慢。
效率比较
针对性:如果您只对某个特定库的类感兴趣,objc_copyClassNamesForImage更高效,因为它只查找该库的类。
广泛性:如果您需要应用中所有类的信息,objc_getClassList是唯一的选择,但可能会因为类的数量多而相对较慢。
返回类型:objc_copyClassNamesForImage返回的是类名字符串数组,处理起来可能比实际的类对象更快。
总的来说,这两个函数各有优势,最佳选择取决于您的具体需求。对于更具体的场景,objc_copyClassNamesForImage可能更高效;而对于全局性的类信息检索,objc_getClassList提供了更广泛的覆盖。
image

@madaoCN
Copy link
Author

madaoCN commented Dec 29, 2023

感谢采纳意见

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants