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


推荐阅读
  • 1:有如下一段程序:packagea.b.c;publicclassTest{privatestaticinti0;publicintgetNext(){return ... [详细]
  • 2023年京东Android面试真题解析与经验分享
    本文由一位拥有6年Android开发经验的工程师撰写,详细解析了京东面试中常见的技术问题。涵盖引用传递、Handler机制、ListView优化、多线程控制及ANR处理等核心知识点。 ... [详细]
  • 本文详细探讨了KMP算法中next数组的构建及其应用,重点分析了未改良和改良后的next数组在字符串匹配中的作用。通过具体实例和代码实现,帮助读者更好地理解KMP算法的核心原理。 ... [详细]
  • 优化ListView性能
    本文深入探讨了如何通过多种技术手段优化ListView的性能,包括视图复用、ViewHolder模式、分批加载数据、图片优化及内存管理等。这些方法能够显著提升应用的响应速度和用户体验。 ... [详细]
  • Explore how Matterverse is redefining the metaverse experience, creating immersive and meaningful virtual environments that foster genuine connections and economic opportunities. ... [详细]
  • Explore a common issue encountered when implementing an OAuth 1.0a API, specifically the inability to encode null objects and how to resolve it. ... [详细]
  • 本文介绍如何使用Objective-C结合dispatch库进行并发编程,以提高素数计数任务的效率。通过对比纯C代码与引入并发机制后的代码,展示dispatch库的强大功能。 ... [详细]
  • Java 中 Writer flush()方法,示例 ... [详细]
  • 技术分享:从动态网站提取站点密钥的解决方案
    本文探讨了如何从动态网站中提取站点密钥,特别是针对验证码(reCAPTCHA)的处理方法。通过结合Selenium和requests库,提供了详细的代码示例和优化建议。 ... [详细]
  • 主要用了2个类来实现的,话不多说,直接看运行结果,然后在奉上源代码1.Index.javaimportjava.awt.Color;im ... [详细]
  • 本文详细介绍了Java编程语言中的核心概念和常见面试问题,包括集合类、数据结构、线程处理、Java虚拟机(JVM)、HTTP协议以及Git操作等方面的内容。通过深入分析每个主题,帮助读者更好地理解Java的关键特性和最佳实践。 ... [详细]
  • 本文详细介绍了如何构建一个高效的UI管理系统,集中处理UI页面的打开、关闭、层级管理和页面跳转等问题。通过UIManager统一管理外部切换逻辑,实现功能逻辑分散化和代码复用,支持多人协作开发。 ... [详细]
  • 本文探讨了如何在给定整数N的情况下,找到两个不同的整数a和b,使得它们的和最大,并且满足特定的数学条件。 ... [详细]
  • 本文介绍如何使用 NSTimer 实现倒计时功能,详细讲解了初始化方法、参数配置以及具体实现步骤。通过示例代码展示如何创建和管理定时器,确保在指定时间间隔内执行特定任务。 ... [详细]
  • 本文介绍了如何通过 Maven 依赖引入 SQLiteJDBC 和 HikariCP 包,从而在 Java 应用中高效地连接和操作 SQLite 数据库。文章提供了详细的代码示例,并解释了每个步骤的实现细节。 ... [详细]
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社区 版权所有