zoukankan      html  css  js  c++  java
  • 第31月第17天 resolveInstanceMethod

    1.

    #import "UIView+Test.h"
    #import <objc/runtime.h>
    
    @implementation UIView (Test)
    
    + (BOOL)resolveInstanceMethod:(SEL)sel {
        return NO;
    }
    
    - (id)forwardingTargetForSelector:(SEL)aSelector {
    //    NSString *sel = NSStringFromSelector(aSelector);
        
        {
    
            //2
            Class class = objc_allocateClassPair(NSClassFromString(@"NSObject"),"AvoidCrashTarget",0);
            class_addMethod(class, aSelector, class_getMethodImplementation([self class], @selector(avoidCrashAction)), "@@:");
            
            id tempObject = [[class alloc] init];
            return tempObject;
        }
        
        return [super forwardingTargetForSelector:aSelector];
    }
    
    - (NSObject *)avoidCrashAction {
        return nil;
    }
    
    @end

    在Objective-C中,在调用对象的某个方法时,其实是在向这个对象发送消息。系统会查看这个对象能否接收该消息,如果不能,则会进行消息转发,消息转发最多三个步骤(注:如果前一步成功处理了消息,那么就不会走到下一步):

    1. 调用resolveInstanceMethod:resolveClassMethod:来决定是否动态添加方法。如果动态添加,则消息得到处理,消息转发结束;否则,进入下一步。

    2. 调用forwardingTargetForSelector:来确定能不能把这条消息转给其他接收者处理,如果返回一个非self的对象,则会把消息发送给该对象,消息转发结束;否则,进入下一步。

    3. 通过methodSignatureForSelector:方法获取签名,如果签名为nil,则消息无法处理,抛出异常;否则,调用forwardInvocation:方法,调用成功则消息转发结束,调用失败则消息无法处理,抛出异常。

    https://github.com/mytcer/ios-docs-cn/blob/384b8a4aba5956fe20bb290a283757274f2a5ba6/Articles/runtime/message_forwarding.md

    id GetterName(id self, SEL cmd) {
        return objc_getAssociatedObject(self, cmd);
    }
    
    void SetterName(id self, SEL cmd, NSString *value) {
        NSString *sel = NSStringFromSelector(cmd);
        NSString *key = [sel substringWithRange:NSMakeRange(3, sel.length - 4)].lowercaseString;
        objc_setAssociatedObject(self, NSSelectorFromString(key), value, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    
        if (sel == @selector(name)) {
            // "@@:"的意思:
            // 第一个字符表示函数的返回值类型,"@"表示GetterName函数的返回值类型为id
            // 后面的字符表示函数的参数类型,"@:"表示GetterName函数接收两个参数,
            // "@"表示参数类型为id,":"表示参数类型为SEL
            class_addMethod(self, sel, (IMP)GetterName, "@@:");
            return YES;
        }
        if (sel == @selector(setName:)) {
            // "v@:@"的意思:
            // "v"表示SetterName函数的返回值类型为void
            // "@:@"参见上面
            class_addMethod(self, sel, (IMP)SetterName, "v@:@");
            return YES;
        }

    2.

    给`NSNull`创建一个分类,并在.m中实现:
    
    #import "NSNull+safe.h"
    @implementation NSNull (safe)
    #define pLog
    #define JsonObjects @[@"",@0,@{},@[]]
    - (id)forwardingTargetForSelector:(SEL)aSelector {
        for (id jsonObj in JsonObjects) {
            if ([jsonObj respondsToSelector:aSelector]) {
    #ifdef pLog
                NSLog(@"NULL出现啦!这个对象应该是是_%@",[jsonObj class]);
    #endif
                return jsonObj;
            }
        }
        return [super forwardingTargetForSelector:aSelector];
    }

    https://www.jianshu.com/p/c5bdd6f7a68c

  • 相关阅读:
    开源微信管家平台——JeeWx 捷微4.0 微服务版本发布,全新架构,全新UI,提供强大的图文编辑器
    JeeWx全新版本发布!捷微二代微信活动平台1.0发布!活动插件持续开源更新!
    JEECG 3.7.8 新版表单校验提示风格使用&升级方法(validform 新风格漂亮,布局简单)
    Java快速开发平台——JEECG 3.7.8 版本发布!我们的目标是有鱼丸也有粗面
    企业如何快速搭建小程序官网
    如何玩转小程序+公众号?手把手教你JeeWx小程序CMS与公众号关联
    deepClone deepCompare
    fiddler
    spy-debugger
    队列
  • 原文地址:https://www.cnblogs.com/javastart/p/10722143.html
Copyright © 2011-2022 走看看