热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

iOS类簇及越界处理

 估计做iOS开发的朋友都遇到多一个问题,就是数组越界,-[__NSArray0objectAtIndex:]:index1beyondboundsforemptyNSArray’

 估计做iOS开发的朋友都遇到多一个问题,就是数组越界,

-[__NSArray0 objectAtIndex:]: index 1 beyond bounds for empty NSArray’

-[__NSArrayI objectAtIndex:]: index 1 beyond bounds [0 .. 0]’

-[__NSArrayM objectAtIndex:]: index 1 beyond bounds for empty array’

-[__NSArrayM objectAtIndex:]: index 1 beyond bounds [0 .. 0]’  

曾经也许你想过,那我是否可以重写objectAtIndex方法,然后判断下是否越界,大概就这样:

– (ObjectType)objectAtIndex:(NSUInteger)index
{
    if(self.count <= index) return nil;
    return [super objectAtIndex:index];
}
又或则这样:通过运行时的方法交换,来达到这个目的
&#8211; (ObjectType)new_objectAtIndex:(NSUInteger)index
{
    if(self.count <= index) return nil;
    return [self new_objectAtIndex:index];
}


继承重写的话,是可以达到目的的,但是我项目都写完了,你叫我一个个的去修改之前的数组初始化类方法为子类么?那得多麻烦啊。

方法交换的话,想想很不错哦,一劳永逸,但是,如果你真的去试试,你发现,天哪,这都什么鬼,根本没有用啊,

其实,NSArray只是的抽象的类罢了,其实具体是神马类,我们先看下下面这张图:


《iOS 类簇及越界处理》

从这张图应该能至少看出:
1、arr1和arr2类名叫_NSArray0,地址还相等;
2、未init的arr8,类名叫做_NSPlaceHolderArray;
3、初始化后的可变数组类名都叫_NSArrayM;
4、初始化后的不可变数组类名都叫_NSArrayI.

那现在我们回到方法交换那里,现在假设你对NSAarry进行方法交换。交换的方法就是 objectAtIndex: 那么交换的就是NSAarry的方法,它本身就是抽象的父类,也就是说其实都是空的实现,而实际运行时,是执行实际子类的objectAtIndex方法,所以这个交换并没起到什么用处。那怎么办呢,那我们去交换子类的实现即可。

+ (void)load

{

    static dispatch_once_t onceToken;

    dispatch_once(&onceToken, ^{

        @autoreleasepool

        {
    /*   这是错误的交换方法

            [objc_getClass(&#8220;__NSArrayI&#8221;swizzleMethod:@selector(objectAtIndex:) withMethod:@selector(swizzleObjectAtIndex:) error:nil];//交换不可变数组

           [objc_getClass(&#8220;__NSArrayM&#8221;swizzleMethod:@selector(objectAtIndex:) withMethod:@selector(swizzleObjectAtIndex:) error:nil];//交换不可变数组

错误原因:假设3个人各有1个球,序号分别为1、2、3,那么如果1和3交换后,2又和3交换,那么最终三个人拿到的球的序号就是:3、1、2;但是,在上面交换的时候,我们注意,其实人员1、和人2都想要一个球3,实际我们想要得到的结果是3、3、X;  因此运行结果肯定不符合我们的预期,甚至崩溃,当可变数组调用objextAtIndex的时候,就会进入死循环。

    */ 
  /*
    下面的是正确的做法,将球3复制一份,因此,人员3就有2个球,人员1和第三个人的第一个球换,人员2和人员3的第二个球交换,结果就是3 3 X 了
    */ 

            [objc_getClass(&#8220;__NSArrayI&#8221;swizzleMethod:@selector(objectAtIndex:) withMethod:@selector(swizzleObjectAtIndexI:) error:nil];//交换不可变数组

           [objc_getClass(&#8220;__NSArrayM&#8221;swizzleMethod:@selector(objectAtIndex:) withMethod:@selector(swizzleObjectAtIndexM:) error:nil];//交换不可变数组

        };

    });

}

然后。。。。我们貌似离题了,其实我们要讨论的是叫类簇啊。。。,其实在解决完上面的问题,我们就已经发现,类簇也就是抽象工厂模式。

什么叫工厂模式?下面看下百度百科里的描述:
抽象工厂模式可以向客户端提供一个接口,使客户端在不必指定产品的具体的情况下,创建多个产品族中的产品对象。,工厂类负责创建抽象产品的具体子类的实例。
 
具体干啥的我不知啊,我就负责生产出来,然后产品的性能是啥,你用了你就知道啊。。。。 

恩,如果不清楚的人,也许会问:这个模式貌似有啥用呢? 我继承不就行啦&#8230;..为啥要有个抽象父类


那我们来看下一个场景,就拿系统的NSNumber来说话吧,char、int、long、double、bool&#8230;,你的思路是,创建一个父类NSNumber,然后NSCharNumber、NSIntNumber&#8230;..,到这里倒没错,因为系统其实也有这些子类,但是:
你给NSCharNumber一个初始化方法叫,initWithChar:,给NSIntNumber初始化方法叫initWithInt:&#8230;.
好吧,你一个一个的也写完了,提交给其他程序员用。。。一个类里,我得import所有的头,我得记住所有的子类名&#8230;.到这里,你自己应该也烦了吧,相比,这个工厂模式就体现了优势了。

写到这里,就完了么?
还没有,我们最开始那里,说到所有空的不可变数组,地址是一样一样的,好奇怪啊。。。不是alloc了就分配了一个地址么。。。
看这里:

    NSArray * x =[NSArray alloc];

    NSArray * x2 = [NSArray alloc];

    NSMutableArray *y =[NSMutableArray alloc];

    NSMutableArray *y2=[NSMutableArray alloc];

    NSLog(@&#8221;%p %p %p %p&#8221;,x,x2,y,y2);


猜猜怎么着?x==x2,y==y2
而且,不init的话,出来的数组是NSPlaceholderArray类型的啊,
那我们可以猜想下,里面的alloc里是不是静态方法实现的获取placeholderArray,然后再根据不同的类型进行init再生成对应的子类。


推荐阅读
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • 本文介绍了使用Java实现大数乘法的分治算法,包括输入数据的处理、普通大数乘法的结果和Karatsuba大数乘法的结果。通过改变long类型可以适应不同范围的大数乘法计算。 ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • C语言注释工具及快捷键,删除C语言注释工具的实现思路
    本文介绍了C语言中注释的两种方式以及注释的作用,提供了删除C语言注释的工具实现思路,并分享了C语言中注释的快捷键操作方法。 ... [详细]
  • 本文介绍了如何在给定的有序字符序列中插入新字符,并保持序列的有序性。通过示例代码演示了插入过程,以及插入后的字符序列。 ... [详细]
  • 动态规划算法的基本步骤及最长递增子序列问题详解
    本文详细介绍了动态规划算法的基本步骤,包括划分阶段、选择状态、决策和状态转移方程,并以最长递增子序列问题为例进行了详细解析。动态规划算法的有效性依赖于问题本身所具有的最优子结构性质和子问题重叠性质。通过将子问题的解保存在一个表中,在以后尽可能多地利用这些子问题的解,从而提高算法的效率。 ... [详细]
  • 本文详细介绍了Java中vector的使用方法和相关知识,包括vector类的功能、构造方法和使用注意事项。通过使用vector类,可以方便地实现动态数组的功能,并且可以随意插入不同类型的对象,进行查找、插入和删除操作。这篇文章对于需要频繁进行查找、插入和删除操作的情况下,使用vector类是一个很好的选择。 ... [详细]
  • 猜字母游戏
    猜字母游戏猜字母游戏——设计数据结构猜字母游戏——设计程序结构猜字母游戏——实现字母生成方法猜字母游戏——实现字母检测方法猜字母游戏——实现主方法1猜字母游戏——设计数据结构1.1 ... [详细]
  • 前景:当UI一个查询条件为多项选择,或录入多个条件的时候,比如查询所有名称里面包含以下动态条件,需要模糊查询里面每一项时比如是这样一个数组条件:newstring[]{兴业银行, ... [详细]
  • 本文介绍了iOS数据库Sqlite的SQL语句分类和常见约束关键字。SQL语句分为DDL、DML和DQL三种类型,其中DDL语句用于定义、删除和修改数据表,关键字包括create、drop和alter。常见约束关键字包括if not exists、if exists、primary key、autoincrement、not null和default。此外,还介绍了常见的数据库数据类型,包括integer、text和real。 ... [详细]
  • 本文记录了在vue cli 3.x中移除console的一些采坑经验,通过使用uglifyjs-webpack-plugin插件,在vue.config.js中进行相关配置,包括设置minimizer、UglifyJsPlugin和compress等参数,最终成功移除了console。同时,还包括了一些可能出现的报错情况和解决方法。 ... [详细]
  • SpringMVC接收请求参数的方式总结
    本文总结了在SpringMVC开发中处理控制器参数的各种方式,包括处理使用@RequestParam注解的参数、MultipartFile类型参数和Simple类型参数的RequestParamMethodArgumentResolver,处理@RequestBody注解的参数的RequestResponseBodyMethodProcessor,以及PathVariableMapMethodArgumentResol等子类。 ... [详细]
  • 本文介绍了OpenStack的逻辑概念以及其构成简介,包括了软件开源项目、基础设施资源管理平台、三大核心组件等内容。同时还介绍了Horizon(UI模块)等相关信息。 ... [详细]
author-avatar
梦春情初开
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有