这儿每天同享一个 iOS 的新知识,快来重视我吧

前言

swift 中有一些比较奇怪的规划,其间切片的索引问题就经常被诟病,今天来具体讲讲。

首要来猜测以下代码输出什么内容:

vararr=[1,2,3,4]
varsubArr=arr[1..<3]
print(subArr[0])

切片索引并非都从 0 开端

发布成果,以上代码会产生越界溃散

有些人看到这个成果会比较奇怪,subArr = arr[1..<3] 的成果分明是 [2, 3],那 subArr[0] 应该是 2 啊,为什么会越界呢?

其实经过 arr[1..<3] 这种办法获得的是一个 ArraySlice<Element> 类型,也叫数组切片。

看下这个函数的声明:

publicsubscript(bounds:Range<Int>)->ArraySlice<Element>

依照苹果官方文档的说法,这个 ArraySlice 和原数组同享内存,一起也同享索引,这样做的意图一方面是能够节省内存,另一方面能够进步大数组的操作功率。

因而我们上边的比如中 subArr 有用的索引应该为 1、2(同享父数组索引)。这点能够经过打印索引看出来:

vararr=[1,2,3,4]
varsubArr=arr[1..<3]
//打印索引
print(subArr.indices)//打印1..<3

得出这个结论后,我们再测验获取 subArr 的第一个元素,应该直接取下标 1:


vararr=[1,2,3,4]
varsubArr=arr[1..<3]
print(subArr[1])//打印:2

怎么处理这个隐患

这种规划难以用正常思想理解,我查看了一些论坛中的讨论,关于这个规划也不太容易修改掉,由于在调集及其子序列之间同享索引是 Swift 调集算法规划的重要组成部分(说白了就是积重难返了)。

要避免这个坑也有一些办法,比如,我们能够在 ArraySlice 的扩展中写一个新的下标办法来做一层维护(避免溃散):

extensionArraySlice{
subscript(`safe`index:Index)->Element?{
ifindices.contains(index){
returnself[index]
}else{
returnnil
}
}
}

此类办法在之前的文章避免数组越界中也说到过。

其实苹果官方有说到,要安全地引用切片的开端和结束索引,始终运用 startIndexendIndex 特点而不是特定值,也就是说,索引的开端位置纷歧定为 0,而是 startIndex,因而也能够在扩展中增加另一个办法,兼容这种状况:

extensionArraySlice{
subscript(safeOffsetoffset:Int)->Element?{
letindex=startIndex+offset
returnindices.contains(index)?self[index]:nil
}
}

这样的话,外界就能够默许切片的索引是从 0 开端的了,运用的时候:

vararr=[1,2,3,4]
varsubArr=arr[1..<3]
ifletfirst=subArr[safeOffset:0]{
print(first)//打印:2
}

这儿每天同享一个 iOS 的新知识,快来重视我吧

本文同步自微信公众号 “iOS新知”,每天准时同享一个新知识,这儿只是同步,想要及时学到就来重视我吧!