iOS 符号解析重构之路

Posted 字节跳动终端技术

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了iOS 符号解析重构之路相关的知识,希望对你有一定的参考价值。


的 Segment, 下面包含 可展示(DIE) 来以统一的形式描述这些信息,每个 DIE 包含:
  • 分别代表函数的起始/结束 PC 地址。
  • 描述函数的名字为 +[SSZipArchive _dateWithMSDOSFormat:]。
  • 指的是这个函数在.../SSZipArchive.m 文件中声明。
  • 描述的机器码地址不等价于程序在运行时的地址,我们可以称之为 file_address。操作系统基于安全因素的考虑,会应用一种地址空间布局随机化的技术 ASLR,加载可执行文件到内存时,会做一个随机偏移(下文中用 load_address 代指),我们获取到偏移后还需要加上指的是当前编译单元对应的行号信息在section 中的偏移,在下一小结中我们再详细介绍。
  • 这里分别代表编译单元包含的所有section 中的偏移地址都保存在section 中。
    面向全球范围招聘!一起来用技术改变世界,感兴趣请联系 chenxuwei.cxw@bytedance.com,邮件主题 简历-姓名-求职意向-期望城市-电话

    iOS之深入解析AppDelegate的重构

    一、Massive AppDelegate

    • AppDelegate 是应用程序的根对象,它连接应用程序和系统,确保应用程序与系统以及其他应用程序正确的交互,通常被认为是每个 iOS 项目的核心。随着开发的迭代升级,不断增加新的功能和业务,它的代码量也不断增长,最终导致了 Massive AppDelegate。
    • 在复杂 AppDelegate 里修改任何东西的成本都是很高的,因为它将会影响整个 APP,一不留神产生 bug。毫无疑问,保持 AppDelegate 的简洁和清晰对于健康的 iOS 架构来说是至关重要的。
    • AppDelegate 常见的业务代码如下:
      • 日志埋点统计数据分析;
      • 初始化数据存储系统;
      • 配置 UIAppearance;
      • 管理 App Badge 数字;
      • 管理通知:请求权限,存储令牌,处理自定义操作,将通知传播到应用程序的其余部分;
      • 管理 UI 堆栈配置:选择初始视图控制器,执行根视图控制器转换;
      • 管理 UserDefaults:设置首先启动标志,保存和加载数据;
      • 管理后台任务;
      • 管理设备方向;
      • 更新位置信息;
      • 初始化第三方库(如分享、日志、第三方登陆、支付)。
    • 这些臃肿的代码是反模式的,导致难于维护,显然支持扩展和测试这样的类非常复杂且容易出错。Massive AppDelegates 与我们经常谈的 Massive ViewController 的症状非常类似。可以运用相应的解决方案来重构 AppDelegate,但这些 Recipe(方案)需要遵循“单一职责、易于扩展、易于测试”原则。

    二、命令模式 Command Design Pattern

    • 命令模式是一种数据驱动的设计模式,属于行为型模式。请求以命令的形式包裹在对象中,并传给调用对象。调用对象寻找可以处理该命令的合适的对象,并把该命令传给相应的对象,该对象执行命令。因此命令的调用者无需关心命令做了什么以及响应者是谁。
    • 可以为 AppDelegate 的每一个职责定义一个命令,这个命令的名字自行指定:
    	// 命令协议
    	@protocol Command <NSObject>
    	- (void)execute;
    	@end
    	
    	// 初始化第三方库
    	@interface InitializeThirdPartiesCommand : NSObject <Command>
    	
    	@end
    	
    	// 初始化主视图
    	@interface InitializeRootViewControllerCommand : NSObject <Command>
    	@property (nonatomic, strong) UIWindow *keyWindow;
    	@end
    	
    	// 初始化视图全局配置
    	@interface InitializeAppearanceCommand : NSObject <Command>
    	
    	@end
    	
    	// ...
    
    • 然后定义一个统一调用的类 StartupCommandsBuilder 来封装如何创建命令的详细信息,AppDelegate 调用这个 builder 去初始化命令并执行这些命令:
    	@implementation StartupCommandsBuilder
    	
    	// 返回数组,元素为遵守 Command 协议的对象
    	- (NSArray<id<Command>> *)build {
    	    return @[ [InitializeAppearanceCommand new], 
    	              [InitializeRootViewControllerCommand new], 
    	              [InitializeThirdPartiesCommand new]];
    	}
    	
    	@end
    
    	- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {    
    	    [[[[StartupCommandsBuilder alloc] init] build] enumerateObjectsUsingBlock:^(id<Command> _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
    	        [obj execute];
    	    }];
    	    return YES;
    	}
    
    • 如果 AppDelegate 需要添加新的职责,则可以创建新的命令,然后把命令添加到 Builder 里而无需去改变 AppDelegate。解决方案满足单一职责、易于扩展、易于测试原则。

    三、组合设计模式 Composite Design Pattern

    • 组合模式又叫部分整体模式,用于把一组相似的对象当作一个单一的对象。组合模式依据树形结构来组合对象,用来表示部分以及整体层次。这种类型的设计模式属于结构型模式,它创建了对象组的树形结构。一个很明显的例子就是 iOS 里的 UIView 以及它的 subviews。
    • 这个想法主要是有一个组装类和叶子类,每个叶子类负责一个职责,而组装类负责调用所有叶子类的方法:
    	// 组装类
    	@interface CompositeAppDelegate : UIResponder <UIApplicationDelegate>
    	+ (instancetype)makeDefault;
    	@end
    	
    	@implementation CompositeAppDelegate
    	
    	+ (instancetype)makeDefault {
    	    // 这里要实现单例
    	    return [[CompositeAppDelegate alloc] init];
    	}
    	
    	- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    	    [[PushNotificationAppDelegate new] application:application didFinishLaunchingWithOptions:launchOptions];
    	    [[ThirdPartiesConfiguratorAppDelegate new] application:application didFinishLaunchingWithOptions:launchOptions];
    	
    	    return YES;
    	}
    	
    	@end
    
    • 实现执行具体职责的叶子类:
    	// 叶子类:推送消息处理
    	@interface PushNotificationAppDelegate : UIResponder <UIApplicationDelegate>
    	
    	@end
    	
    	// 叶子类:初始化第三方库
    	@interface ThirdPartiesConfiguratorAppDelegate : UIResponder <UIApplicationDelegate>
    	
    	@end
    	
    	
    	@implementation PushNotificationAppDelegate
    	
    	- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    	    NSLog(@"PushNotificationAppDelegate");
    	    
    	    return YES;
    	}
    	
    	@end
    	
    	
    	@implementation ThirdPartiesConfiguratorAppDelegate
    	
    	- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    	    NSLog(@"ThirdPartiesConfiguratorAppDelegate");
    	    return YES;
    	}
    	
    	@end
    
    • 在 AppDelegate 通过工厂方法创建组装类,然后通过它去调用所有的方法:
    	- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    	    [[CompositeAppDelegate makeDefault] application:application didFinishLaunchingWithOptions:launchOptions];    
    	    return YES;
    	}
    
    • 它满足我们在开始时提出的所有要求,如果要添加一个新的功能,很容易添加一个叶子类,无需改变 AppDelegate,解决方案满足单一职责、易于扩展、易于测试原则。

    四、中介者模式 Mediator Design Pattern

    • 中介者模式是用来降低多个对象和类之间的通信复杂性。这种模式提供了一个中介类,该类通常处理不同类之间的通信,并支持松耦合,使代码易于维护。中介者模式属于行为型模式。
    • 让我们定义 AppLifecycleMediator 将 UIApplication 的生命周期通知底下的监听者,这些监听者必须遵循AppLifecycleListener 协议,如果需要监听者要能扩展新的方法。
    	@interface APPLifeCycleMediator : NSObject
    	
    	+ (instancetype)makeDefaultMediator;
    	
    	@end
    	
    	
    	@implementation APPLifeCycleMediator {
    	    @private
    	        NSArray<id<AppLifeCycleListener>> * _listeners;
    	}
    	- (void)dealloc {
    	    [[NSNotificationCenter defaultCenter] removeObserver:self];
    	}
    	
    	- (instancetype)initWithListeners:(NSArray<id<AppLifeCycleListener>> *)listeners {
    	    if (self = [super init]) {
    	        
    	        _listeners = listeners;
    	        
    	        // 通知
    	        [[NSNotificationCenter defaultCenter] addObserver:self
    	                                                 selector:@selector(onAppWillEnterForeground)
    	                                                     name:UIApplicationWillEnterForegroundNotification
    	                                                   object:nil];
    	        [[NSNotificationCenter defaultCenter] addObserver:self
    	                                                 selector:@selector(onAppDidEnterBackgroud)
    	                                                     name:UIApplicationDidEnterBackgroundNotification
    	                                                   object:nil];
    	        [[NSNotificationCenter defaultCenter] addObserver:self
    	                                                 selector:@selector(onAppDidFinishLaunching)
    	                                                     name:UIApplicationDidFinishLaunchingNotification
    	                                                   object:nil];
    	    }
    	    
    	    return self;
    	}
    	
    	// 定义好静态类方法,初始化所有监听者
    	+ (instancetype)makeDefaultMediator {
    	    static APPLifeCycleMediator * mediator;
    	    static dispatch_once_t onceToken;
    	    dispatch_once(&onceToken, ^{
    	        mediator = [[APPLifeCycleMediator alloc] initWithListeners:@[[VideoListener new], [SocketListener new]]];
    	    });
    	    return mediator;
    	}
    	
    	- (void)onAppWillEnterForeground {
    	    [_listeners[1] onAppWillEnterForeground];
    	}
    	
    	- (void)onAppDidEnterBackgroud {
    	    [_listeners[0] onAppDidEnterBackgroud];
    	}
    	
    	- (void)onAppDidFinishLaunching {
    	
    	}
    	
    	@end
    
    • 定义 AppLifecycleListener 协议,以及协议的的实现者:
    	// 监听协议
    	@protocol AppLifeCycleListener <NSObject>
    	@optional
    	- (void)onAppWillEnterForeground;
    	- (void)onAppDidEnterBackgroud;
    	- (void)onAppDidFinishLaunching;
    	
    	@end
    	
    	@interface VideoListener : NSObject <AppLifeCycleListener>
    	
    	@end
    	
    	
    	@interface SocketListener : NSObject <AppLifeCycleListener>
    	
    	@end
    	
    	
    	@implementation VideoListener
    	
    	- (void)onAppDidEnterBackgroud {
    	    NSLog(@"停止视频播放");
    	}
    	
    	@end
    	
    	@implementation SocketListener
    	
    	- (void)onAppWillEnterForeground {
    	    NSLog(@"开启长链接");
    	}
    	
    	@end
    
    • 加入到 AppDelegate 中:
    	- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    	    [APPLifeCycleMediator makeDefaultMediator];
    	    
    	    return YES;
    	}
    
    • 这个中介者自动订阅了所有的事件。AppDelegate 仅仅需要初始化它一次,就能让它正常工作。每个监听者都有一个单一职责,很容易添加一个监听者,而无需改变 Appdelgate 的内容,每个监听者以及中介者能够容易的被单独测试。

    五、总结

    • 大多数 AppDelegates 的设计都不太合理,过于复杂并且职责过多,我们称这样的类为 Massive App Delegates。
    • 通过应用软件设计模式,Massive App Delegate 可以分成几个单独的类,每个类都有单一的责任,可以单独测试。这样的代码很容易更改维护,因为它不会在应用程序中产生一连串的更改。它非常灵活,可以在将来提取和重用。

    以上是关于iOS 符号解析重构之路的主要内容,如果未能解决你的问题,请参考以下文章

    寻求合作 - 求职 - 创业 / 有意向的来这里交流一下

    boss直聘上老板能看到以前提交的意向职位吗

    SSH进阶之路一步步重构容器实现Spring框架——彻底封装,实现简单灵活的Spring框架

    从0到阿里

    iOS之深入解析AppDelegate的重构

    求职之路(持续更新)

    (c)2006-2024 SYSTEM All Rights Reserved IT常识