• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

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

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

一、类与变量

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 方法


鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
在项目中同时使用Objective-C和Swift发布时间:2022-07-12
下一篇:
Objective-C 排序发布时间:2022-07-12
热门推荐
热门话题
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap