NullSafe 的原理
问题场景
后端返回的数据中总会出现一些NSNull类型,当我们一处理程序就会崩溃,因此想到把返回的数据中的NSNull类型全部转换成@""空字符串
(1)原始的json串:后端返回的json串里面包含类型NSString,NSArray,NSDictionary,NSNull类型。
{"status":1,"service_name":null,"service_id":null,"img_url":"http:\/\/api.jgfw.me\/assets\/uploads\/files\/","price":null,"num":3,"service_info":{"service_type":null,"service_time":null,"service_detail":null,"customer_name":null,"customer_phone":null,"customer_address":"","new_jishi":"","old_jishi":null,"lat":null,"lon":null},"order_info":{"order_no":"E15031267469289848688","pay_time":null,"order_time":null,"price":0,"order_state":null}}
(2)用SBJson库:json串转换成字典
NSDictionary *jsonDic = [retString JSONValue];

"<null>" 就是NSNull 类型,直接使用会Crash.
摘要
NullSafe is a simple category on NSNull that returns nil for unrecognised messages instead of throwing an exception.
//
// 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.
// //Fix issue desc = "<null>";icon = "<null>"; #import <objc/runtime.h>
#import <Foundation/Foundation.h> #ifndef NULLSAFE_ENABLED
#define NULLSAFE_ENABLED 1
#endif #pragma GCC diagnostic ignored "-Wgnu-conditional-omitted-operand" @implementation NSNull (NullSafe) #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, );
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 = ; 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];
} #endif @end
当我们给一个NSNull对象发送消息的话,可能会崩溃(null是有内存的),而发送给nil的话,是不会崩溃的。
作者就是使用了这么一个原理,把发送给NSNull的而NSNull又无法处理的消息经过如下几步处理:
创建一个方法缓存,这个缓存会缓存项目中类的所有类名。
遍历缓存,寻找是否已经有可以执行此方法的类。
如果有的话,返回这个
NSMethodSignature。如果没有的话,返回nil,接下来会走
forwardInvocation:方法。[invocation invokeWithTarget:nil];将消息转发给nil。
那么,如何判断NSNull无法处理这个消息呢,在OC中,系统如果对某个实例发送消息之后,它(及其父类)无法处理(比如,没有这个方法等),系统就会发送methodSignatureForSelector消息,如果这个方法返回非空,那么就去执行返回的方法,如果为nil,则发送forwardInvocation消息。
这样就完成整个转发链了。
题外话:一般来说,我们不应该在我们的项目中使用NSNull类(大部分NSNull类的来源来自于接口的返回),而使用nil,在来源上,就应该堵上(要么你解析到null进行处理,要么和你的服务端说,不要给我返回null)。
reference:
1.https://segmentfault.com/q/1010000005064181
2.https://github.com/nicklockwood/NullSafe
3.http://blog.sina.com.cn/s/blog_5c91824f0102ve3c.html
NullSafe 的原理的更多相关文章
- NSNull Crash处理 (NullSafe 的原理)
问题场景 后端返回的数据中总会出现一些NSNull类型,当我们一处理程序就会崩溃,因此想到把返回的数据中的NSNull类型全部转换成@""空字符串 (1)原始的json串:后端返回 ...
- 奇异值分解(SVD)原理与在降维中的应用
奇异值分解(Singular Value Decomposition,以下简称SVD)是在机器学习领域广泛应用的算法,它不光可以用于降维算法中的特征分解,还可以用于推荐系统,以及自然语言处理等领域.是 ...
- node.js学习(三)简单的node程序&&模块简单使用&&commonJS规范&&深入理解模块原理
一.一个简单的node程序 1.新建一个txt文件 2.修改后缀 修改之后会弹出这个,点击"是" 3.运行test.js 源文件 使用node.js运行之后的. 如果该路径下没有该 ...
- 线性判别分析LDA原理总结
在主成分分析(PCA)原理总结中,我们对降维算法PCA做了总结.这里我们就对另外一种经典的降维方法线性判别分析(Linear Discriminant Analysis, 以下简称LDA)做一个总结. ...
- [原] KVM 虚拟化原理探究(1)— overview
KVM 虚拟化原理探究- overview 标签(空格分隔): KVM 写在前面的话 本文不介绍kvm和qemu的基本安装操作,希望读者具有一定的KVM实践经验.同时希望借此系列博客,能够对KVM底层 ...
- H5单页面手势滑屏切换原理
H5单页面手势滑屏切换是采用HTML5 触摸事件(Touch) 和 CSS3动画(Transform,Transition)来实现的,效果图如下所示,本文简单说一下其实现原理和主要思路. 1.实现原理 ...
- .NET Core中间件的注册和管道的构建(1)---- 注册和构建原理
.NET Core中间件的注册和管道的构建(1)---- 注册和构建原理 0x00 问题的产生 管道是.NET Core中非常关键的一个概念,很多重要的组件都以中间件的形式存在,包括权限管理.会话管理 ...
- python自动化测试(2)-自动化基本技术原理
python自动化测试(2) 自动化基本技术原理 1 概述 在之前的文章里面提到过:做自动化的首要本领就是要会 透过现象看本质 ,落实到实际的IT工作中就是 透过界面看数据. 掌握上面的这样的本领 ...
- CRC、反码求和校验 原理分析
3月份开始从客户端转后台,算是幸运的进入全栈工程师的修炼阶段.这段时间一边是老项目的客户端加服务器两边的维护和交接,一边是新项目加加加班赶工,期间最长经历了连续工作三天只睡了四五个小时的煎熬,人生也算 ...
随机推荐
- SZU:A26 Anagram
Judge Info Memory Limit: 32768KB Case Time Limit: 10000MS Time Limit: 10000MS Judger: Normal Descrip ...
- [转]loadView的用法,loadView创建基本界面,DidLoad读入数据
loadview: // 有没有nib 只要是复写了loadview loadview都会被执行 有nib文件的话加载的是nib文件的view 没有的话会按照loadview里的代码加载 ...
- SSRS 系列 - 使用带参数的 MDX 查询实现一个分组聚合功能的报表
SSRS 系列 - 使用带参数的 MDX 查询实现一个分组聚合功能的报表 SSRS 系列 - 使用带参数的 MDX 查询实现一个分组聚合功能的报表 2013-10-09 23:09 by BI Wor ...
- PHP实现一个简单url路由功能
如果一个页面的内容呈现,需要根据url上传递的参数来进行渲染.很多时候可能是这样子写:xxx.com/xx?c=x&m=x& t=..,而我们看到的url往往是这样子的(以新浪微游戏的 ...
- Cracking the Coding Interview(Trees and Graphs)
Cracking the Coding Interview(Trees and Graphs) 树和图的训练平时相对很少,还是要加强训练一些树和图的基础算法.自己对树节点的设计应该不是很合理,多多少少 ...
- IOS7学习之路三(UISpriteKit游戏开发SKNode)
ios7新添加了自己的游戏开发框架UISpriteKit ,可以用此做一些2D的小游戏, 今天学习了一下SKNode的知识做一下笔记,以便以后查阅. 1.SKNode继承自UIResponder. 2 ...
- 业务接口+UI层的设计(基于Castle实现的Repository)
业务接口+UI层的设计(基于Castle实现的Repository) Repository层设计的文章见:[http://www.cnblogs.com/yomho/p/3297042.html] ...
- jQuery跳房子插件hopscotch
插件描述 跳房子是一个框架,使开发人员可以轻松预览产品并添加到他们的网页 跳房子接受JSON对象作为输入,并提供开发人员来控制渲染巡演显示和管理的游览进度的API. 使用步骤 要使用跳房子框架上手,只 ...
- 绘制基本图形和线型(StrokeStyle)的设置详解
绘制基本图形和线型(StrokeStyle)的设置详解 目前,在博客园上,相对写得比较好的两个关于Direct2D的教程系列,分别是万一的Direct2D系列和zdd的Direct2D系列.有兴趣的网 ...
- 判断BigDecimal是否可以转为Integer或Double
一句话,BigDecimal转为字符串,匹配正则表达式,so easy; 不废话,代码: import java.math.BigDecimal; import java.util.regex.Pat ...