代码改变世界

Objective-C 方法交换实践(三) - Aspects 源码解析

2018-06-12 19:20 by v2m, 阅读(1014) 阅读, 推荐(0) 推荐, 收藏, 编辑

一、类与变量

AspectOptions
typedef NS_OPTIONS(NSUInteger, AspectOptions) {

    AspectPositionAfter   = 0,            /// 原方法之后 (default)

    AspectPositionInstead = 1,            /// 替换原方法

    AspectPositionBefore  = 2,            /// 原方法之前

    AspectOptionAutomaticRemoval = 1 << 3 /// 执行一次后就移除

};

AspectsContainer

存储AspectIdentifier ,总共有三个数组,分别存储 上面的 After Instead Before 的各种 Aspects。

AspectIdentifier
+ (instancetype)identifierWithSelector:(SEL)selector object:(id)object options:(AspectOptions)options block:(id)block error:(NSError **)error;

从创建方法就可以看出,他是用来记录 要替换的对象object,替换的原方法selector,替换的类型options,以及执行的代码block。其中block的参数是 id<AspectInfo>类型的。

AspectInfo

一种是协议名,标记当前 NSinvocation的一些环境

@protocol AspectInfo <NSObject>

/// The instance that is currently hooked.
- (id)instance;

/// The original invocation of the hooked method.
- (NSInvocation *)originalInvocation;

/// All method arguments, boxed. This is lazily evaluated.
- (NSArray *)arguments;

@end

一种是类名,基本上就是实现上面的协议的类。

@interface AspectInfo : NSObject <AspectInfo>
- (id)initWithInstance:(__unsafe_unretained id)instance invocation:(NSInvocation *)invocation;
@property (nonatomic, unsafe_unretained, readonly) id instance;
@property (nonatomic, strong, readonly) NSArray *arguments;
@property (nonatomic, strong, readonly) NSInvocation *originalInvocation;
@end

二、具体过程

1.aspect_isSelectorAllowedAndTrack 检测是否能够swizzle

检测不能是以下方法 @"retain", @"release", @"autorelease", @"forwardInvocation:"

对于"dealloc"方法位置只能是 AspectPositionBefore

被交换的方法是否未实现

如果是metaClass,如果子类已经hook,返回;如果父类已经hook,返回。否者标记hook的 SEL,为父类标记已经hook 的 Child Class。

2.aspect_getContainerForObject

得到当前 select 对应的 AspectsContainer, 不存在就创建,通过关联对象的方式存储在类中

3.AspectIdentifier

创建 AspectIdentifier 并且添加到AspectsContainer里面去

4.aspect_prepareClassAndHookSelector 进行swizzle操作
  • 如果已经操作过,返回

  • 如果是metaClass,对metaClass 进行 A操作

  • 如果实例对象进行过 object_setClass 操作,对 class 进行A操作

  • 否则创建一个 subclass ,对其进行 object_setClass 操作,然后对这个 subclass 进行 A 操作,之后把 当前对象的 isa 指向 subclass

A操作是:

替换类的 forwardInvocation 方法为 __ASPECTS_ARE_BEING_CALLED__

为类增加 aliasSelector 指向原 selector

把原 selector 指向 _objc_msgForward 或者_objc_msgForward_stret

当然里面还有一些容错判断

5.__ASPECTS_ARE_BEING_CALLED__ 流程

取出当前对象(object)的 AspectsContainer 和 类(class)的 AspectsContainer ,调用 Before hooks 的一些方法,调用 instead 的方法,调用 after 的方法

对没有instead的情况检测是否有原方法,没有就走原 forwardInvocation方法或者走 doesNotRecognizeSelector 方法

iOS 中系统与 SDK 版本检测

2018-05-29 17:15 by v2m, 阅读(1828) 阅读, 推荐(0) 推荐, 收藏, 编辑
摘要:一、编译时检测 1. 判断 SDK 是否是某个版本或更高版本 2.判断当前需要支持的最低版本 ​ 这个宏的取值也就是 这个值,也就是你的工程支持的最低系统版本。但是最少是 __IPHONE_2_0。 3.判断最高可支持的系统版本 这个宏的值等于当前 SDK 定义的最高版本,比如 \__IPHONE_ 阅读全文

源码阅读-GlobalTimer

2018-03-17 17:29 by v2m, 阅读(790) 阅读, 推荐(0) 推荐, 收藏, 编辑
摘要:最近看到一篇文章推了一个开源项目, "GlobalTimer" 。主要是可以用一个定时器来统一管理多个定时任务,可以针对特定任务进行管理。 一、原理 1.一个公共的timer 2.封装任务到自定义个Event中,保留任务的执行代码与数据,时间信息等 3.计算所有任务间隔的最大公约数x,用这个x作为t 阅读全文

iOS 的音频播放

2018-03-15 19:15 by v2m, 阅读(1255) 阅读, 推荐(0) 推荐, 收藏, 编辑
摘要:一、Audio Toolbox 1.使用代码 import AudioServicesPlaySystemSound(1106); 2.如果想用自己的音频文件创建系统声音来播放的同学可以参考如下代码。 //Get the filename of the sound file: NSString pa 阅读全文

iOS 影音新格式 HEIF HEVC

2017-11-27 16:26 by v2m, 阅读(2376) 阅读, 推荐(0) 推荐, 收藏, 编辑
摘要:苹果在 iOS 11 的发布会上,推出了两种新的媒体格式 `HEVC`,都是为了保证画质的情况下,大大减少视频、照片的大小。 一、简介 全称 High Efficiency Video Coding(高效率视频编码),是比H.264更加优秀的一种视频压缩标准(也称为 H.265)。HEVC 在低码率 阅读全文

Objective-C 方法交换实践(二) - 方法指针交换

2017-11-21 00:49 by v2m, 阅读(1868) 阅读, 推荐(0) 推荐, 收藏, 编辑
摘要:一. 基本函数 1. 根据 sel 得到 class 的实例方法 2. 根据 sel 得到 class 的函数指针 3. 给 class 添加方法 4. 替换 class 的 sel 对应的函数指针,返回值为 sel 对应的原函数指针 5. 交换两个 method 6. 直接替换 method 的函 阅读全文

Objective-C 方法交换实践(一) - 基础知识

2017-11-20 23:54 by v2m, 阅读(1054) 阅读, 推荐(0) 推荐, 收藏, 编辑
摘要:一、Objective C 中的基本类型 首先看下 Objective C 的对象模型,每个 Objective C 对象都是一个指向 Class 的指针。Class 的结构如下: struct objc_class { Class _Nonnull isa OBJC_ISA_AVAILABILIT 阅读全文

iOS 中架构模式的浅显理解

2017-08-04 00:39 by v2m, 阅读(1296) 阅读, 推荐(0) 推荐, 收藏, 编辑
摘要:我们开发软件中应用各种模式,主要是为了 1. 职责划分:一个类只做一件事 2. 易用,可维护,方便扩展 3. 解耦,相互独立,可单独测试 各种设计模式其实都是在解决上面的问题,让我们对比看看吧。 一、如何理解MVC设计模式 在通常的定义中,MVC 是下图的结构 但是在 cocoa 体系中,苹果建议的 阅读全文

Block 在 ARC 下的拷贝

2017-07-25 16:43 by v2m, 阅读(960) 阅读, 推荐(1) 推荐, 收藏, 编辑
摘要:前言 现在有一种说法,是开启arc选项时,已经没有栈上的block了,所以所有的block都不需要copy来拷贝到堆上了。那么这个说法正确与否呢? 结论是这个说法必须是错误的,首先的一点就是arc只是编译器帮助我们给对象自动增加retain,release方法,我们不需要手动的去管理这些成对出现的内 阅读全文

Repo 的使用小结

2017-06-21 17:35 by v2m, 阅读(23989) 阅读, 推荐(0) 推荐, 收藏, 编辑
摘要:一、安装 创建目录和修改环境变量 下载repo代码 二、帮助 查询具体命令的帮助 Repo 仓库状态 状态 三、初始化 示例 这个命令会在当前文件夹创建一个 文件夹,它包含 repo/ : 其实是一个repo的python源码 manifest.xml : 工作树的主配置文件,不要编辑这个文件 pr 阅读全文
点击右上角即可分享
微信分享提示