今天是元宵节,祝大家元宵节快乐!在Swift中的数组和字典中下标是非常常见的,数组可以通过索引下标进行元素的查询,字典可以通过键下标来获取相应的值。在使用数组时,一个常见的致命错误就是数组越界。如果在你的应用程序中数组越界了,那么对不起,如果由着程序的性子的话是会崩溃的。为了防止崩溃呢,我们会对集合做一些安全的处理。比如对数组进行扩展,从而对数组的索引进行安全检查,保证数组的index在正常范围内。在Objective-C中也是经常对数组,字典等做一些处理操作。

  今天的博客的主要内容是先对Objective-C中常用集合的安全扩展进行介绍,由此在窥探一下Swift语言中的处理。并且还会介绍Swift中自定义下标,说白了自定义下标其实就是通过下标的形式与特定的下标值来访问一个对象。自定义下标在有些场合中是非常实用的。然后下方还会给出数组切片的概念与实用方式。废话少说进入今天的主题。

一、安全的索引集合元素

  对一个集合索引进行安全检查是很有必要的,也是经常实用的,最常见的就是对数组和字典索引的安全检查,该部分内容就是类比这Objective-C中的数组索引的安全检查来扩充Swift的数组,从而让你的Swift数组也同样具备对数组安全检查的功能。

  1. Objective-C中NSArray对索引的安全扩展

  下方这段代码是非常简单的,它是对Objective-C中的NSArray做的扩展,该方法位于NSArray相关的延展中。在你的项目中,如果添加了此段延展代码,那么你就可以通过objectAtIndexSafe:方法对数组进行安全的索引。有代码不难看出在定义该函数参数时,我们将index声明为NSUInteger,也就是正整数,这就排除了你对下标传入一个负数。紧接着又对index的合法性进行验证,如果index不在数组有效范围内,那么就返回nil。当你查找的元素不存在时,你返回nil是不会造成程序崩溃的,因为nil的地址是0x0, 这和归零若引用有些类似。

  当然下方只是NSArray安全扩展其中一个方法,还有许多扩展的安全方法,比如数组的增删改查都可以进行相应的安全扩展,扩展的方式和思路与下方这段简单代码类似,再次就不花过多的篇幅对其进行介绍了。

 - (id)objectAtIndexSafe:(NSUInteger)index {
if (index > self.count-) {
return nil;
}
return [self objectAtIndex:index];
}

  

  2.Swift中对Array的安全扩展

  上面简单的对Objective-C中的安全方法进行了简单的介绍,就算是对Swift相关内容的引子吧,下方将会给出Swift语言中类似的方法。对Swift相关方法介绍时,我会尽量的详细一些,因为毕竟本篇博客主要是关于Swift内容的。接下来将对上面Objective-C中NSArray数组索引安全验证的方法使用Swift语言进行重新。当然重写的内容也是非常容易理解的。

    (1)主要是对subscript方法进行重载,在重载的subscript方法中,对index的范围通过三目运算符进行了安全检查。如果index在0..<count这个半开区间内,那么就返回当前索引的值,如果不在该范围内就返回nil, 下方就是对Array索引的安全检查。

 extension Array {
subscript (safe index: Int) -> Element? {
return (..<count).contains(index) ? self[index] : nil
}
}

    

    (2)上面是对Swift中的Array进行了安全索引扩展,接下来就是简单的使用了,下方的代码段是对上面安全扩展函数的测试。首先创建了一个数组testArray, 然后创建了一个索引数组indexs, 然后遍历indexs中的元素值,将其作为testArray的下标,对testArray进行检索。当然检索时,使用的是我们上面定义的safe方法,并且在indexs下标数组中存在非法的下标。在这种情况下,我们来验证一下我们的安全方法。

    当然在数组遍历中,我们使用了for-in循环取出indexs中的每个index, 然后使用guard语句取出testArray中的值。使用guard语句能很好的过滤掉因为非法的index而返回的nil值。具体代码段如下所示:

    上面的代码段理解起来并不难,上述测试代码的运行结果如下所示,从运行结果可以很好的说明问题,并且在index非法时不会崩溃,并合理的给出相应的错误提示,请看下方具体运行结果。

    上面的延展也可以通过对整个集合类型,也就是CollectionType进行扩展,不过在扩展CollectionType时要对Index使用where子句进行限制,使Index必须符合Comparable协议,具体实现如下所示,不过下面的方法比较少用,因为一般是数组存在越界的情况,因为在字典中,如果你对一个不存在的键进行值的索引,会返回nil值,而不会崩溃。但是在数组中,你对不存在的index进行索引,就会抛出错误。下方是另一种处理方式,不过该方式用的比较少。

    实现下方延展后,同样可以在数组中使用safe方法。

  

二、使用多个索引下标的数组

  延展的功能是非常强大的,该部分将会给出另一个数组的延展。该延展的功能是可以通过多个索引给数组设置值,以及通过多个索引一次性获取多个数组的值。该功能是非常强大的,接下来将一步步实现该功能。

  1. 了解zip()函数以及Zip2Sequence

    在实现数组多个索引扩展时,需要使用到zip()函数,zip()函数接收两个序列,并且返回一个Zip2Sequence类型的数据。zip()函数究竟是干嘛的呢?接下来将会通过一个小的实例来搞一下zip()函数。首先看一下Apple的帮助文档上对zip()函数的介绍。具体如下所示:

    上面那句英文的意思大概就是“基于两个基本序列构建了一个序列对,在序列对中,第i对,代表着每个基本序列中的第i个元素。”在zip函数定义的过程中,我们可以看到,zip()是一个泛型函数,其接收两个SequenceType类型的参数,然后返回一个Zip2Sequence类型的数据。新创建的序列对就存在于Zip2Sequence中。说这么多还是来个小Demo实惠一些,通过一个小实例,看zip()函数的用法一目了然。

    (1) 创建两个数组zip1和zip2, 将这两个数组作为zip()函数的参数,将两个数组进行合并。具体实现如下:

    (2) 通过上面的程序可以看出,zipSum是一个Zip2Sequence<Array<Int>, Array<Int>>类型的常量,我们可以使用dump()对zipSum常量进行打印,观察其中的数据存储结构,具体结构如下所示:

    输出结果如下,由结果容易看出,在序列中有两个元素,第一个元素对应着数组zip1, 第二个元素对应着数组zip2。

    (3)接下来就是对zipSum这个序列通过for-in循环进行遍历,下方就是对zipSum进行遍历的代码。

      上面对zipSum遍历的结果如下所示,由下方输出结果可知,输出是成对遍历的,如果某个数组中的元素是多余的,那么就会被忽略掉。

  2. 数组多个索引的延展实现

    在这个将要实现的延展中,我们对Array进行了扩展,在延展中对subscript方法进行重载,使其可以接受多个下标,并且对多个下标对应的值进行索引,并把索引结果组成数组。在subscript方法中通过get方法获取索引相应的值,通过set方法为相应的索引值进行设置。下方代码段就是该延展的实现:    

 extension Array {
subscript(i1: Int, i2: Int, rest: Int...) -> [Element] {
//通过实现get方法,获取数组中相应的值
get {
var result: [Element] = [self[i1], self[i2]]
for index in rest {
result.append(self[index])
}
return result
} //通过set方法,对数组相应的索引进行设置
set (values) {
for (index, value) in zip([i1, i2] + rest, values) {
self[index] = value
}
}
}
}

    在上述延展的实现中,并没有多少困难的地方。在subs两个cript函数中,使用的是可变参数,subscript函数参数的个数是两个以上(包括两个)。然后就是通过zip()函数以及对zip()函数返回的结果集进行遍历,从而对多个下标索引进行值的设置。经过上述延展,我们就可以通过多个索引对数组进行操作了。上述延展的使用方式如下: 

三、数组切片

  数组切片在OC中也是不存在的,是Swift新引入的概念,该部分将会对数组切片进行讨论,研究一下数组切片的使用方式及其特点。下方先通过一个小Demo来看一下如何生成数组切片。下方代码段先将一个字符串通过map函数转换成一个数组arrayTest, 然后我们创建一个该数组的切片。下方代码段创建了arrayTest数组中的下标3到下标6这个范围区间中的切片,arraySlices就是数组切片变量,它是ArraySlice<String>类型的,具体代码段如下所示。

  在数组切片中有一点需要注意,数组切片的下标与原始数组中的下标保持一致。如果要取出切片arraySlices中的第一个值,我们要使用arraySlices[3], 而不是arraySlices[0], 如果使用arraySlices[0]就会报错,如下所示:

  

  因为数组是值类型,尽管切片与原数组有着对应的数组下标,但是切片是原始数组的部分拷贝,所以修改切片或者修改原数组,两者互不影响,下方示例给出了该测试,如下所示:

   

  如果把切片转换成枚举,那么切片中与原始数组对应的下标关系将不存在,下方是将切片转换成枚举序列,然后对其进行遍历,代码如下:

  上述代码段输出结果如下:

    今天博客就先写到这儿,关于数组的延展还有许多,以后有机会再讨论。其实我们还可以通过一些方式来为我们自己的对象添加下标。也就是可以通过下标来访问对象属性,这个以后在讨论吧。  

窥探Swift之数组安全索引与数组切片的更多相关文章

  1. python使用数组作为索引遍历数组

    python使用数组作为索引遍历数组 觉得有用的话,欢迎一起讨论相互学习~Follow Me python使用数组作为索引遍历数组 import numpy as np a=np.arange(0,5 ...

  2. Numpy对数组按索引查询

    Numpy对数组按索引查询 三种索引方法: 基础索引 神奇索引 布尔索引 基础索引 一维数组 和Python的List一样 二维数组 注意:切片的修改会修改原来的数组 原因:Numpy经常要处理大数组 ...

  3. 窥探Swift系列博客说明及其Swift版本间更新

    Swift到目前为止仍在更新,每次更新都会推陈出新,一些Swift旧版本中的东西在新Swift中并不适用,而且新版本的Swift会添加新的功能.到目前为止,Swift为2.1版本.去年翻译的Swift ...

  4. 《JS权威指南学习总结--第7章 数组概念、稀疏数组》

    一.数组概念 数组是值的有序结合.每个值叫做一个元素,而每个元素在数组中都有一个位置,用数字表示,称为索引. JS数组是无类型的:数组元素可以是任意对象,并且同一个数组中的不同元素也可能有不同的类型. ...

  5. 窥探Swift之数组与字典

    说到数组和字典,只要是编过程的小伙伴并不陌生.在Swift中的数组与字典也有着一些让人眼前一亮的特性,今天的博客就来窥探一下Swift中的Array和Dictionary.还是沿袭之前的风格,在介绍S ...

  6. (一)javascript中的数组index属性——获取数组的索引值

    例如:要做到这样的效果 点击每个选项时,会显示不同的div. 我们的做法:在javascript中,先把所有的div的display设置为none,然后在根据当前的数组里的索引值进行一个显示div的过 ...

  7. Knockout获取数组元素索引的2种方法,在MVC中实现

    原文:Knockout获取数组元素索引的2种方法,在MVC中实现 在遍历数组.集合的时候,通常要获取元素的索引,本篇体验使用Knockout获取索引的2种方法. 假设有这样的一个模型: namespa ...

  8. Numpy数组对象的操作-索引机制、切片和迭代方法

    前几篇博文我写了数组创建和数据运算,现在我们就来看一下数组对象的操作方法.使用索引和切片的方法选择元素,还有如何数组的迭代方法. 一.索引机制 1.一维数组 In [1]: a = np.arange ...

  9. Numpy学习二:数组的索引与切片

    1.一维数组索引与切片#创建一维数组arr1d = np.arange(10)print(arr1d) 结果:[0 1 2 3 4 5 6 7 8 9] #数组的索引从0开始,通过索引获取第三个元素a ...

随机推荐

  1. struts2中的jar包

    核心包: (后面数字是版本号,不同struts2版本,数字可能不一样.) struts2-core-2.1.8.1 struts2的核心jar包,不可缺少的 xwork-core-2.1.6 xwor ...

  2. AmazeUI 框架知识点-布局和样式整理

    1.Amaze UI 将所有元素的盒模型设置为 border-box.这下好了,妈妈再也不用担心没计算好 padding.border 而使布局破相了. 2.Amaze UI 将浏览器的基准字号设置为 ...

  3. ESLint 规则

    ESLint由 JavaScript 红宝书 作者 Nicholas C.Zakas 编写, 2013 年发布第一个版本. ESLint是一个以可扩展.每条规则独立的,被设计为完全可配置的lint工具 ...

  4. vue-cli 组件的使用

    开始项目之前,先了解如何创建项目: http://www.cnblogs.com/pearl07/p/6247389.html 1,项目目录结构(路由是后来建的,将在下一篇使用路由,此处可忽略). 2 ...

  5. HTML input小结

    一.Input表示Form表单中的一种输入对象,其又随Type类型的不同而分文本输入框,密码输入框,单选/复选框,提交/重置按钮等,下面一一介绍. 1.type=text 输入类型是text,这是我们 ...

  6. winform设置文本框宽度 根据文字数量和字体返回宽度

    _LinkLabel.Width = TextRenderer.MeasureText(_LinkLabel.Text, _LinkLabel.Font).Width;

  7. MSBuild的简单介绍与使用

    MSBuild 是 Microsoft 和 Visual Studio的生成系统.它不仅仅是一个构造工具,应该称之为拥有相当强大扩展能力的自动化平台.MSBuild平台的主要涉及到三部分:执行引擎.构 ...

  8. 解读ASP.NET 5 & MVC6系列(1):ASP.NET 5简介

    ASP.NET 5简介 ASP.NET 5是一个跨时代的改写,所有的功能和模块都进行了独立拆分,做到了彻底解耦.为了这些改写,微软也是蛮 拼的,几乎把.NET Framwrok全部改写了一遍,形成了一 ...

  9. Mac OS X上IntelliJ IDEA 13与Tomcat 8的Java Web开发环境搭建

    这标题实在有点拗口,不知道怎么写好,但看了标题也就明白文本的内容.最近几天在折腾这些玩意儿,所以写写总结.除了环境搭建,本文还是一篇入门级的上手教程. 去下载一些东西 JDK安装 Tomcat安装 T ...

  10. 玩转Windows服务系列——创建Windows服务

    创建Windows服务的项目 新建项目->C++语言->ATL->ATL项目->服务(EXE) 这样就创建了一个Windows服务项目. 生成的解决方案包含两个项目:Servi ...