热门标签 | 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再生成对应的子类。


推荐阅读
  • 本文详细探讨了KMP算法中next数组的构建及其应用,重点分析了未改良和改良后的next数组在字符串匹配中的作用。通过具体实例和代码实现,帮助读者更好地理解KMP算法的核心原理。 ... [详细]
  • 题目描述:给定n个半开区间[a, b),要求使用两个互不重叠的记录器,求最多可以记录多少个区间。解决方案采用贪心算法,通过排序和遍历实现最优解。 ... [详细]
  • 本文探讨了 C++ 中普通数组和标准库类型 vector 的初始化方法。普通数组具有固定长度,而 vector 是一种可扩展的容器,允许动态调整大小。文章详细介绍了不同初始化方式及其应用场景,并提供了代码示例以加深理解。 ... [详细]
  • 毕业设计:基于机器学习与深度学习的垃圾邮件(短信)分类算法实现
    本文详细介绍了如何使用机器学习和深度学习技术对垃圾邮件和短信进行分类。内容涵盖从数据集介绍、预处理、特征提取到模型训练与评估的完整流程,并提供了具体的代码示例和实验结果。 ... [详细]
  • 使用Numpy实现无外部库依赖的双线性插值图像缩放
    本文介绍如何仅使用Numpy库,通过双线性插值方法实现图像的高效缩放,避免了对OpenCV等图像处理库的依赖。文中详细解释了算法原理,并提供了完整的代码示例。 ... [详细]
  • 本文将介绍如何使用 Go 语言编写和运行一个简单的“Hello, World!”程序。内容涵盖开发环境配置、代码结构解析及执行步骤。 ... [详细]
  • C++实现经典排序算法
    本文详细介绍了七种经典的排序算法及其性能分析。每种算法的平均、最坏和最好情况的时间复杂度、辅助空间需求以及稳定性都被列出,帮助读者全面了解这些排序方法的特点。 ... [详细]
  • 本文介绍了Java并发库中的阻塞队列(BlockingQueue)及其典型应用场景。通过具体实例,展示了如何利用LinkedBlockingQueue实现线程间高效、安全的数据传递,并结合线程池和原子类优化性能。 ... [详细]
  • 深入理解C++中的KMP算法:高效字符串匹配的利器
    本文详细介绍C++中实现KMP算法的方法,探讨其在字符串匹配问题上的优势。通过对比暴力匹配(BF)算法,展示KMP算法如何利用前缀表优化匹配过程,显著提升效率。 ... [详细]
  • 本文详细介绍了Java编程语言中的核心概念和常见面试问题,包括集合类、数据结构、线程处理、Java虚拟机(JVM)、HTTP协议以及Git操作等方面的内容。通过深入分析每个主题,帮助读者更好地理解Java的关键特性和最佳实践。 ... [详细]
  • 在金融和会计领域,准确无误地填写票据和结算凭证至关重要。这些文件不仅是支付结算和现金收付的重要依据,还直接关系到交易的安全性和准确性。本文介绍了一种使用C语言实现小写金额转换为大写金额的方法,确保数据的标准化和规范化。 ... [详细]
  • 本文探讨了如何在给定整数N的情况下,找到两个不同的整数a和b,使得它们的和最大,并且满足特定的数学条件。 ... [详细]
  • 题目Link题目学习link1题目学习link2题目学习link3%%%受益匪浅!-----&# ... [详细]
  • 并发编程:深入理解设计原理与优化
    本文探讨了并发编程中的关键设计原则,特别是Java内存模型(JMM)的happens-before规则及其对多线程编程的影响。文章详细介绍了DCL双重检查锁定模式的问题及解决方案,并总结了不同处理器和内存模型之间的关系,旨在为程序员提供更深入的理解和最佳实践。 ... [详细]
  • 探索1000以内的完美数:因数和等于自身
    本文探讨了如何在1000以内找到所有完美数,即一个数的因数(不包括自身)之和等于该数本身。例如,6是一个完美数,因为1 + 2 + 3 = 6。通过编程实现这一过程,可以更好地理解完美数的特性。 ... [详细]
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社区 版权所有