美文网首页
2022-08-08 记录一次线上崩溃 crash+[NSMet

2022-08-08 记录一次线上崩溃 crash+[NSMet

作者: 我是小胡胡123 | 来源:发表于2022-08-08 17:03 被阅读0次

IOS 13.6.1 xsmax上出现。
#43002 NSInvalidArgumentException
+[NSMethodSignature signatureWithObjCTypes:]: type signature is empty.

怀疑是下面的
NSNull+NullSafe.m 实现有问题:



#pragma GCC diagnostic ignored "-Wgnu-conditional-omitted-operand"

@implementation NSNull (NullSafe)

- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector
{
    @synchronized([self class])
    {
        //look up method signature
        NSMethodSignature *signature = [super methodSignatureForSelector:selector];
        if (!signature)
        {
            //not supported by NSNull, search other classes
            static NSMutableSet *classList = nil;
            static NSMutableDictionary *signatureCache = nil;
            if (signatureCache == nil)
            {
                classList = [[NSMutableSet alloc] init];
                signatureCache = [[NSMutableDictionary alloc] init];
                
                //get class list
                int numClasses = objc_getClassList(NULL, 0);
                Class *classes = (Class *)malloc(sizeof(Class) * (unsigned long)numClasses);
                numClasses = objc_getClassList(classes, numClasses);
                
                //add to list for checking
                NSMutableSet *excluded = [NSMutableSet set];
                for (int i = 0; i < numClasses; i++)
                {
                    //determine if class has a superclass
                    Class someClass = classes[i];
                    Class superclass = class_getSuperclass(someClass);
                    while (superclass)
                    {
                        if (superclass == [NSObject class])
                        {
                            [classList addObject:someClass];
                            break;
                        }
                        [excluded addObject:NSStringFromClass(superclass)];
                        superclass = class_getSuperclass(superclass);
                    }
                }
                
                //remove all classes that have subclasses
                for (Class someClass in excluded)
                {
                    [classList removeObject:someClass];
                }
                
                //free class list
                free(classes);
            }
            
            //check implementation cache first
            NSString *selectorString = NSStringFromSelector(selector);
            signature = signatureCache[selectorString];
            if (!signature)
            {
                //find implementation
                for (Class someClass in classList)
                {
 
                    if ([someClass instancesRespondToSelector:selector])
                    { 
                        signature = [someClass instanceMethodSignatureForSelector:selector];
                        break;
                    } 
                }
                
                //cache for next time
 
                signatureCache[selectorString] = signature ?: [NSNull null];
            }
            else if ([signature isKindOfClass:[NSNull class]])
            {
                signature = nil;
            }
        }
        return signature; 
    }
}

- (void)forwardInvocation:(NSInvocation *)invocation
{
    invocation.target = nil;
    [invocation invoke];
}
@end

3265625-4328bd5c1b0f3368.png


@implementation HelloClass

void methodNormalc(void)
{
    NSLog(@"methodNormalc");
    
}


//这里没啥用
-(BOOL)respondsToSelector:(SEL)aSelector{
    bool a= [super respondsToSelector:aSelector];
    return a;
}
//如果方法没有实现,默认返回false
//如果返回false,就会走消息转发
+(BOOL)resolveInstanceMethod:(SEL)sel{
    bool a = [super resolveInstanceMethod:sel];
    //return true;     // 不管是true 还是 false ,都会继续往下转发,why
    NSLog(@"resolveInstanceMethod");
    
    
    if (sel==@selector(methodNormalc)) {
        
        class_addMethod(self, @selector(methodNormalc), methodNormalc, "v@:");
        
        // 动态添加了。方法之后,  不会在走消息转发的调用了, 就执行执行了!!
        // 不管下面返回的是false 还是。true
        //并且,添加了之后, 下次在调用这个methodNormalc 方法, 不会在走resolveInstanceMethod,而是直接就执行了methodNormalc 函数
        //return false;
        
        return  true; //但既然添加了,最好就是返回true吧, 但是也没有说明为啥这样更好!
    }
    return a;
}
//默认返回空
//又被称为快速消息转发。
// 如果为空,走慢速消息转发,继续转发消息
-(id)forwardingTargetForSelector:(SEL)aSelector{
    id a = [super forwardingTargetForSelector:aSelector];
    NSLog(@"forwardingTargetForSelector");
    return a;
}

// 默认一般普通方法是返回空的。
// 如果是协议方法,没有实现,不会反回空。
//反回空,到这里就会崩溃了
//如果这里返回了签名,会再次调用resolveInstanceMethod:(SEL)sel判断是否实现
//如果仍然没有实现,就会走到fowardInvocation:
-(NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{
    NSMethodSignature *a =[super methodSignatureForSelector:aSelector];
    NSLog(@"methodSignatureForSelector"); //如果签名为 空, 只接崩溃
    //如果是协议方法,  这个签名还是能返回的, 不会崩溃,可以走到forwardInvocation,再然后崩溃
    return a;
}


//默认实现是崩溃
//并且不能用try-catch捕获
-(void)forwardInvocation:(NSInvocation *)anInvocation{
    [super forwardInvocation:anInvocation];
    NSLog(@"forwardInvocation");
}


- (void)doesNotRecognizeSelector:(SEL)aSelector{
    NSLog(@"doesNotRecognizeSelector");
    //父类默认是崩溃
    [super doesNotRecognizeSelector:aSelector];
    NSLog(@"doesNotRecognizeSelector");
}

@end

找到一个 nullsafe 其他实现:

发现也有人发生crash
https://github.com/nicklockwood/NullSafe/issues/24

image.png

相关文章

网友评论

      本文标题:2022-08-08 记录一次线上崩溃 crash+[NSMet

      本文链接:https://www.haomeiwen.com/subject/lvgwwrtx.html