IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Object-c 反射技术 -> 正文阅读

[移动开发]Object-c 反射技术

Object-c?反射技术

背景:

App?随着迭代的发展,需要把c++与一些算法进行解耦,这样oc runtime的 反射可以利用,这样当app如果集成了算法组件,通过查找是否有对应class,从而可以动态判断方法是否可用。

在正式代码之前,先看下几个方法对应的含义

objc_getClass

这个是反射的核心,通过一个字符串构查找?类对象

C++
Class objc_getClass(const?char?*aClassName)
{
????if?(!aClassName)?return?Nil;
?
????// NO unconnected, YES class handler
????return?look_up_class(aClassName,?NO,?YES);
}
?
?。。。。
?
?
/***********************************************************************
* look_up_class
* Look up a class by name, and realize it.
* Locking: acquires runtimeLock
**********************************************************************/
static?BOOL?empty_getClass(const?char?*name, Class *outClass)
{
????*outClass =?nil;
????return?NO;
}
?
static?ChainedHookFunction<objc_hook_getClass> GetClassHook{empty_getClass};
?
void?objc_setHook_getClass(objc_hook_getClass newValue,
???????????????????????????objc_hook_getClass *outOldValue)
{
????GetClassHook.set(newValue, outOldValue);
}
?
Class?
look_up_class(const?char?*name,?
??????????????bool?includeUnconnected?__attribute__((unused)),?
??????????????bool?includeClassHandler?__attribute__((unused)))
{
????if?(!name)?return?nil;
?
????Class result;
????bool?unrealized;
????{
????????runtimeLock.lock();
????????result = getClassExceptSomeSwift(name);
????????unrealized = result ?&& ?!result->isRealized();
????????if?(unrealized) {
????????????result = realizeClassMaybeSwiftAndUnlock(result, runtimeLock);
????????????// runtimeLock is now unlocked
????????}?else?{
????????????runtimeLock.unlock();
????????}
????}
?
????if?(!result) {
????????// Ask Swift about its un-instantiated classes.
?
????????// We use thread-local storage to prevent infinite recursion
????????// if the hook function provokes another lookup of the same name
????????// (for example, if the hook calls objc_allocateClassPair)
?
????????auto?*tls = _objc_fetch_pthread_data(true);
?
????????// Stop if this thread is already looking up this name.
????????for?(unsigned?i = 0; i < tls->classNameLookupsUsed; i++) {
????????????if?(0 == strcmp(name, tls->classNameLookups[i])) {
????????????????return?nil;
????????????}
????????}
?
????????// Save this lookup in tls.
????????if?(tls->classNameLookupsUsed == tls->classNameLookupsAllocated) {
????????????tls->classNameLookupsAllocated =
????????????????(tls->classNameLookupsAllocated * 2 ?: 1);
????????????size_t size = tls->classNameLookupsAllocated *
????????????????sizeof(tls->classNameLookups[0]);
????????????tls->classNameLookups = (const?char?**)
????????????????realloc(tls->classNameLookups, size);
????????}
????????tls->classNameLookups[tls->classNameLookupsUsed++] = name;
?
????????// Call the hook.
????????Class swiftcls =?nil;
????????if?(GetClassHook.get()(name, &swiftcls)) {
????????????ASSERT(swiftcls->isRealized());
????????????result = swiftcls;
????????}
?
????????// Erase the name from tls.
????????unsigned?slot = --tls->classNameLookupsUsed;
????????ASSERT(slot >= 0 ?&& ?slot < tls->classNameLookupsAllocated);
????????ASSERT(name == tls->classNameLookups[slot]);
????????tls->classNameLookups[slot] =?nil;
????}
?
????return?result;
}
?

能看的出来?会从tls(Thread?Local?Storage),classNameLookups,查找对应的class

class_getClassMethod

C++
?OBJC_EXPORT Method?_Nullable
class_getClassMethod(Class?_Nullable?cls,?SEL?_Nonnull?name)

?。。。。。
?NEVER_INLINE
IMP?lookUpImpOrForward(id?inst,?SEL?sel, Class cls,?int?behavior)
{
????const?IMP?forward_imp = (IMP)_objc_msgForward_impcache;
????IMP?imp =?nil;
????Class curClass;
?
????runtimeLock.assertUnlocked();
?
????if?(slowpath(!cls->isInitialized())) {
????????// The first message sent to a class is often +new or +alloc, or +self
????????// which goes through objc_opt_* or various optimized entry points.
????????//
????????// However, the class isn't realized/initialized yet at this point,
????????// and the optimized entry points fall down through objc_msgSend,
????????// which ends up here.
????????//
????????// We really want to avoid caching these, as it can cause IMP caches
????????// to be made with a single entry forever.
????????//
????????// Note that this check is racy as several threads might try to
????????// message a given class for the first time at the same time,
????????// in which case we might cache anyway.
????????behavior |= LOOKUP_NOCACHE;
????}
?
????// runtimeLock is held during isRealized and isInitialized checking
????// to prevent races against concurrent realization.
?
????// runtimeLock is held during method search to make
????// method-lookup + cache-fill atomic with respect to method addition.
????// Otherwise, a category could be added but ignored indefinitely because
????// the cache was re-filled with the old value after the cache flush on
????// behalf of the category.
?
????runtimeLock.lock();
?
????// We don't want people to be able to craft a binary blob that looks like
????// a class but really isn't one and do a CFI attack.
????//
????// To make these harder we want to make sure this is a class that was
????// either built into the binary or legitimately registered through
????// objc_duplicateClass, objc_initializeClassPair or objc_allocateClassPair.
????checkIsKnownClass(cls);
?
????cls = realizeAndInitializeIfNeeded_locked(inst, cls, behavior & LOOKUP_INITIALIZE);
????// runtimeLock may have been dropped but is now locked again
????runtimeLock.assertLocked();
????curClass = cls;
?
????// The code used to lookup the class's cache again right after
????// we take the lock but for the vast majority of the cases
????// evidence shows this is a miss most of the time, hence a time loss.
????//
????// The only codepath calling into this without having performed some
????// kind of cache lookup is class_getInstanceMethod().
?
????for?(unsigned?attempts = unreasonableClassCount();;) {
????????if?(curClass->cache.isConstantOptimizedCache(/* strict */true)) {
#if CONFIG_USE_PREOPT_CACHES
????????????imp = cache_getImp(curClass, sel);
????????????if?(imp)?goto?done_unlock;
????????????curClass = curClass->cache.preoptFallbackClass();
#endif
????????}?else?{
????????????// curClass method list.
????????????Method meth = getMethodNoSuper_nolock(curClass, sel);
????????????if?(meth) {
????????????????imp = meth->imp(false);
????????????????goto?done;
????????????}
?
????????????if?(slowpath((curClass = curClass->getSuperclass()) ==?nil)) {
????????????????// No implementation found, and method resolver didn't help.
????????????????// Use forwarding.
????????????????imp = forward_imp;
????????????????break;
????????????}
????????}
?
????????// Halt if there is a cycle in the superclass chain.
????????if?(slowpath(--attempts == 0)) {
????????????_objc_fatal("Memory corruption in class list.");
????????}
?
????????// Superclass cache.
????????imp = cache_getImp(curClass, sel);
????????if?(slowpath(imp == forward_imp)) {
????????????// Found a forward:: entry in a superclass.
????????????// Stop searching, but don't cache yet; call method
????????????// resolver for this class first.
????????????break;
????????}
????????if?(fastpath(imp)) {
????????????// Found the method in a superclass. Cache it in this class.
????????????goto?done;
????????}
????}
?
????// No implementation found. Try method resolver once.
?
????if?(slowpath(behavior & LOOKUP_RESOLVER)) {
????????behavior ^= LOOKUP_RESOLVER;
????????return?resolveMethod_locked(inst, sel, cls, behavior);
????}
?
?done:
????if?(fastpath((behavior & LOOKUP_NOCACHE) == 0)) {
#if CONFIG_USE_PREOPT_CACHES
????????while?(cls->cache.isConstantOptimizedCache(/* strict */true)) {
????????????cls = cls->cache.preoptFallbackClass();
????????}
#endif
????????log_and_fill_cache(cls, imp, sel, inst, curClass);
????}
?done_unlock:
????runtimeLock.unlock();
????if?(slowpath((behavior & LOOKUP_NIL) && imp == forward_imp)) {
????????return?nil;
????}
????return?imp;
}

lookUpImpOrForward?网上有很多资料介绍这个方法,这个是整个反射的核心,通过Class找到对应的方法,具体过程可以参考其他的网上资料,核心无非先从cache找有无方法,没有在从class的方法列表找,还没有可以看下能否进行消息转发等等,最终就是找到这个methed

有了class method?就可以提取方法的函数指针,有了函数指针就可以反射调用了

实例方法反射

C++
?{
????????????Class cls = objc_getClass("NSString");
????????????NSObject *pObject = [cls alloc];
????????????Method thmod= ?class_getInstanceMethod(cls,?@selector(init));
????????????IMP?funPtr = ??method_getImplementation(thmod);
????????????NSString *pS = ?((id(*)(id,?SEL))funPtr)(pObject,?@selector(init));
????????????
??}

Oc?方法转成c?后默认前边都会id,?SEL,就像c++类方法,默认会有this指针

类方法反射

C++
?Class metaCls = objc_getMetaClass("NSString");
if?(metaCls)
{
???Method thmod = ?class_getClassMethod(cls,?@selector(string));
???IMP?funPtr = ??method_getImplementation(thmod);
???NSString *pS = ?((id(*)(id,?SEL))funPtr)(cls,?@selector(string));

}

class_getClassMethod

C++
Method class_getClassMethod(Class cls,?SEL?sel)
{
????if?(!cls ?|| ?!sel)?return?nil;
?
????return?class_getInstanceMethod(cls->getMeta(), sel);
}
?????Class getMeta() {
????????if?(isMetaClassMaybeUnrealized())?return?(Class)this;
????????else?return?this->ISA();
????}

可以看的出来?如果cls是类对象,则会直接去ISA找到类对象,元类对象直接返回

所以类方法反射的时候可以穿metaClass,也可以Class

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-09-04 01:23:00  更:2022-09-04 01:25:31 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 4:52:39-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码