美文网首页
NullSafe代码理解

NullSafe代码理解

作者: 李某lkb | 来源:发表于2018-03-03 10:40 被阅读113次

相信大家多NullSafe并不陌生,但是为什么就一个文件,还不用导入就能解决NULL导致的崩溃呢.

首先.不用导入是用到了runtime黑魔法.写的NULL的分类.自动生效.
具体的就看我给大家的代码解析吧.
就164行,不多.


//
//  NullSafe.m
//
//  Version 1.2.2
//
//  Created by Nick Lockwood on 19/12/2012.
//  Copyright 2012 Charcoal Design
//
//  Distributed under the permissive zlib License
//  Get the latest version from here:
//
//  https://github.com/nicklockwood/NullSafe
//
//  This software is provided 'as-is', without any express or implied
//  warranty.  In no event will the authors be held liable for any damages
//  arising from the use of this software.
//
//  Permission is granted to anyone to use this software for any purpose,
//  including commercial applications, and to alter it and redistribute it
//  freely, subject to the following restrictions:
//
//  1. The origin of this software must not be misrepresented; you must not
//  claim that you wrote the original software. If you use this software
//  in a product, an acknowledgment in the product documentation would be
//  appreciated but is not required.
//
//  2. Altered source versions must be plainly marked as such, and must not be
//  misrepresented as being the original software.
//
//  3. This notice may not be removed or altered from any source distribution.
//

#import <objc/runtime.h>
#import <Foundation/Foundation.h>


#ifndef NULLSAFE_ENABLED

#define NULLSAFE_ENABLED 1

#endif


#ifdef DEBUG

#define NULLSAFE_ENABLED 0

#endif
//屏蔽编译器警告
#pragma GCC diagnostic ignored "-Wgnu-conditional-omitted-operand"

//分类
@implementation NSNull (NullSafe)

//当我们给一个NSNull对象发送消息的话,可能会崩溃(null是有内存的),而发送给nil的话,是不会崩溃的
//
//创建一个方法缓存,这个缓存会缓存项目中类的所有类名。
//遍历缓存,寻找是否已经有可以执行此方法的类。
//
//如果有的话,返回这个NSMethodSignature。
//
//如果没有的话,返回nil,接下来会走forwardInvocation:方法。
//
//[invocation invokeWithTarget:nil];将消息转发给nil。


/*
 
 在OC中,系统如果对某个实例发送消息之后,它(及其父类)无法处理(比如,没有这个方法等),系统就会发送methodSignatureForSelector消息,如果这个方法返回非空,那么就去执行返回的方法,如果为nil,则发送forwardInvocation消息。
 
 */
//如果NULLSAFE_ENABLED 为真,执行下面的代码块.
#if NULLSAFE_ENABLED

- (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);//已分配好内存空间的数组 classes 中存放元素
                
                //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]])//属于NULL就改为nil.
            {
                signature = nil;
            }
        }
        return signature;
    }
}
//把目标对象置于nil.
- (void)forwardInvocation:(NSInvocation *)invocation
{
    invocation.target = nil;
    [invocation invoke];
}

#endif

@end


相关文章

网友评论

      本文标题:NullSafe代码理解

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