關於 iOS 集合官方文件的一份小筆記

Swants發表於2018-08-17

新增到 iOS 集合內的物件必須是物件。
作為集合,需要滿足三個基本的特性:獲取元素查詢元素遍歷元素
如果集合是可變的還需要另外支援 新增元素刪除元素

Array

關於 iOS 集合官方文件的一份小筆記

新增到 Array 內的元素都是有序的,同一物件可多次被新增到集合。和其它集合相比,Array 遍歷內部元素十分方便。

Array 內元素必須是物件 (NSPointArray 除外)。

Array 的分類

  • NSArray 初始化後元素就不可再增刪。

  • NSMuatbleArray 初始化後可以隨時新增或刪除元素物件。

  • NSPointArrayNSMuatbleArray 相似,區別是可以指定對元素的強/弱引用。也就是說 NSPointArray 內部元素為物件 或 nil

    關於 iOS 集合官方文件的一份小筆記

關於陣列的一些知識點:

  1. indexOfObjectindexOfObjectIdenticalTo 的區別?

兩個方法都是來判斷某一物件是否是 Array 集合內元素,如果是則返回該物件在集合內的索引。兩個方法的區別就在於兩個 API 判定的依據:indexOfObject 會使用 isEqualTo 方法將 Object 與集合元素進行比較。而 indexOfObjectIdenticalTo 則會比較 Object 與集合元素的指標是否相同。

  1. 關於陣列排序,單一條件的值比較排序使用 SortedArrayUsingComparatorSortedArrayUsingSelector 很容易,如果給你兩個甚至多個排序條件呢?比如對學生分數排序,排序條件為,優先按總分降序排列,總分相同再比較數學成績降序排列,數學成績也相同比較語文成績降序排列··· ··· 前面的兩個排序方法當然也能滿足我們的需求,但是現在要討論的是另一種更優雅的實現:使用 NSSortDescriptor
    Student *p1 = [[Student alloc] initWithName:@"zhonger" id:@"1" score:552 math:130 chinese:90 english:120];
    Student *p2 = [[Student alloc] initWithName:@"zhonger" id:@"1" score:552 math:130 chinese:90 english:120];
    Student *p3 = [[Student alloc] initWithName:@"zhonger" id:@"1" score:552 math:130 chinese:90 english:120];
    Student *p4 = [[Student alloc] initWithName:@"zhonger" id:@"1" score:552 math:130 chinese:90 english:120];
    Student *p5 = [[Student alloc] initWithName:@"zhonger" id:@"1" score:552 math:130 chinese:90 english:120];

    NSArray *students = @[p1, p2, p3, p4, p5];

    NSSortDescriptor *des1 = [[NSSortDescriptor alloc]initWithKey:@"score" ascending:NO];
    NSSortDescriptor *des2 = [[NSSortDescriptor alloc] initWithKey:@"math" ascending:NO];
    NSSortDescriptor *des3 = [[NSSortDescriptor alloc] initWithKey:@"chinese" ascending:NO];

    NSArray *newArray1 = [students sortedArrayUsingDescriptors:@[des1,des2,des3]];
    NSLog(@"%@",newArray1);
複製程式碼

是不是比之前的排序方法可讀性提升了很多,而且程式碼後期也更好維護。

Dictionary

關於 iOS 集合官方文件的一份小筆記

Dictionary 內部元素以 key:value 鍵值對的形式存在,新增到 Dictionary 內的鍵值對是無序的,並且具有同一 key 值的鍵值對物件重複新增會相互覆蓋。當某個鍵值對新增到 Dictionary 時,Dictionary 會對 key 進行深拷貝,而對 value 進行淺拷貝,已經新增到集合內部的鍵值對,key 值將不可更改。而 value 值為強引用,當 value 為可變物件時,修改 value 物件,字典內的 value 也會被修改。

key 為任何遵循 NSCopying 協議並實現了 hashisEqual 方法的物件。
value 為任何物件(包括集合)

key 需要很好地實現雜湊方法,否則字典的設值、查詢、獲取、增加等操作耗時將線性增加。一般我們都用 NSString 作為 key 值,是因為 NSString 很好地實現了雜湊方法。這些操作的耗時為常量。

字典可以根據 value 值對 key 進行排序,排序後得到的是一個 key 陣列。

Dictionary 的分類

  • NSDictionary 初始化後就不可再增刪鍵值對。
  • NSMutableDictionary 初始化後可以隨時新增或刪除鍵值對。
  • NSMapTable 類似 NSMutableDictionary 可以指定對 value 的強/弱引用。也就是說 NSMapTable 內部元素的 value 值可以為 nil

關於 iOS 集合官方文件的一份小筆記

關於字典的一些知識點:

我們在使用 Dictionnary 時,一般將 String 作為 key 值 ,從而可以滿足絕大部分需求。但有時也會遇到使用自定義物件作為 key 的情況。那麼作為 key 的物件都需要滿足哪些條件呢?

  1. key 必須遵循 NSCopying 協議,因為當元素漸入字典後,會對 key 進行深拷貝。
  2. key 必須實現 hashisEqual 方法。(便於快速獲取元素並保證 key 的唯一性)。

並不建議使用特別大的物件作為 key,可能會導致效能問題。

Set

關於 iOS 集合官方文件的一份小筆記

新增到 Set 內的元素都是無序的,同一物件只能被新增一次。和其它集合相比,Set 查詢內部元素十分快速。

set 集合元素要很好地實現 hash 方法(時間複雜度為O(1)),否則時間複雜度為 O(k)

Set 的分類

  • NSSet 初始化後就不可再增刪元素。
  • NSMuatbleSet 初始化後可隨時增刪元素。
  • NSCountedSet 每個元素都帶有一個計數,新增元素,計數為一。重複新增某個元素則計數加一;移除元素計數減一,計數為零則移除
  • NSHashTableNSMutableSet 類似,區別是可指定對元素的強/弱引用,內部元素可以為 nil

關於 iOS 集合官方文件的一份小筆記

Index set

關於 iOS 集合官方文件的一份小筆記

IndexSet 儲存的 Array 子集,儲存元素為 Arrayindex 索引,儲存形式為索引範圍。 eg: (0,3,4)->(NSRange(0,1),NSRange(3,2))

Index set 的分類

  • NSIndexSet 初始化後就不可再增刪元素。
  • NSMutableIndexSet 初始化後可隨時增刪元素。

使用場景一般為記錄陣列的某些元素,比如列表多選行,可以使用 NSIndexSet 來記錄選擇了哪行,而不是另外建立一個可變陣列

Index path

關於 iOS 集合官方文件的一份小筆記

儲存巢狀陣列的某個元素 path
如(0,2,0)

  • **NSIndexPath **

使用場景一般是 TableViewdataSource 代理方法。

嚴格意義上說,indexPath 並不是集合。其只是記錄巢狀陣列內某子元素的路徑位置。此處遵從官方文件將 indexPath 和集合一起討論。

深拷貝與淺拷貝

以下為官方定義,考慮到翻譯後理解可能會出現偏差,筆者並未進行翻譯,牆裂建議讀者自己閱讀加深理解。

關於 iOS 集合官方文件的一份小筆記

Shallow Copies

There are a number of ways to make a shallow copy of a collection. When you create a shallow copy, the objects in the original collection are sent a retain message and the pointers are copied to the new collection. Listing 1 shows some of the ways to create a new collection using a shallow copy.

Listing 1 Making a shallow copy

NSArray *shallowCopyArray = [someArray copyWithZone:nil];
NSDictionary *shallowCopyDict = [[NSDictionary alloc] initWithDictionary:someDictionary copyItems:NO];
複製程式碼

These techniques are not restricted to the collections shown. For example, you can copy a set with the copyWithZone: method—or the mutableCopyWithZone: method—or an array with initWithArray:copyItems: method.

Deep Copies

There are two ways to make deep copies of a collection. You can use the collection’s equivalent of initWithArray:copyItems: with YES as the second parameter. If you create a deep copy of a collection in this way, each object in the collection is sent a copyWithZone: message. If the objects in the collection have adopted the NSCopying protocol, the objects are deeply copied to the new collection, which is then the sole owner of the copied objects. If the objects do not adopt the NSCopying protocol, attempting to copy them in such a way results in a runtime error. However, copyWithZone: produces a shallow copy. This kind of copy is only capable of producing a one-level-deep copy. If you only need a one-level-deep copy, you can explicitly call for one as in Listing 2.

Listing 2 Making a deep copy

This technique applies to the other collections as well. Use the collection’s equivalent of initWithArray:copyItems: with YES as the second parameter.

If you need a true deep copy, such as when you have an array of arrays, you can archive and then unarchive the collection, provided the contents all conform to the NSCodingprotocol. An example of this technique is shown in Listing 3.

Listing 3 A true deep copy

NSArray* trueDeepCopyArray = [NSKeyedUnarchiver unarchiveObjectWithData: [NSKeyedArchiver archivedDataWithRootObject:oldArray]];  

複製程式碼

參考

官方文件連結

相關文章