Foundation Collection Classes

Foundation Collection Classes

Talk give at the AltTechTalks Berlin (http://alt-tech-talks.com) that summarizes my talk in objc.io Issue 7: http://objc.io/issue-7/collections.html

832ece085bfe2c7c5b0ed6be62d7e675?s=128

Peter Steinberger
PRO

December 11, 2013
Tweet

Transcript

  1. Foundation Collection Classes Peter Steinberger @steipete

  2. Object Collection NSCat

  3. None
  4. PSPDFKit iOS PDF Framework

  5. Array NS

  6. Mutability

  7. Your API should never expose mutable collections.

  8. NSArray NSSet NSPointerArray NSOrderedSet NSHashTable NSDictionary NSMapTable NSCache NSIndexSet

  9. @property (nonatomic, copy) NSArray *altTechTalkBerlinPeople;

  10. lastObject firstObject indexOfObjectIdenticalTo: containsObject:

  11. NSMutableArray *mutableObjects = [array mutableCopy] ?: [NSMutableArray array]; NSMutableArray *mutableObjects

    = [NSMutableArray arrayWithArray:array];
  12. [@[] mutableCopy] [NSMutableArray array]

  13. array.reverseObjectEnumerator.allObjects

  14. Performance

  15. Big O Notation

  16. Performance Object Access usual: O(1) worst case: O(lg N) Insertion/Deletion

    usual: O(N) worst case: O(N*lg N) Linear Search O(N*lg N)
  17. Sorting

  18. NSArray *array = @[@"John Appleseed", @"Tim Cook", @"Hair Force One",

    @"Michael Jurewitz”]; ! NSArray *sortedArray = [array sortedArrayUsingSelector: @selector(localizedCaseInsensitiveCompare:)];
  19. NSArray *numbers = @[@9, @5, @11, @3, @1]; ! NSArray

    *sortedNumbers = [numbers sortedArrayUsingSelector:@selector(compare:)];
  20. - (NSArray *)sortedArrayUsingFunction:(NSInteger (*)(id, id, void *))comparator context:(void *)context hint:(NSData

    *)hint; ! - (NSData *)sortedArrayHint;
  21. - (NSArray *)sortedArrayUsingComparator:(NSComparator)cmptr; ! - (NSArray *)sortedArrayWithOptions:(NSSortOptions)opts usingComparator:(NSComparator)cmptr; typedef NSComparisonResult

    (^NSComparator)(id obj1, id obj2);
  22. sortedArrayUsingSelector: 4947.90 [ms] sortedArrayUsingComparator: 5082.98 [ms] sortedArrayUsingFunction:context: 5618.93 [ms] Sorting

    1.000.000 strings
  23. Binary Search containsObject: indexOfObject:

  24. typedef NS_OPTIONS(NSUInteger, NSBinarySearchingOptions) { NSBinarySearchingFirstEqual = (1UL << 8), NSBinarySearchingLastEqual

    = (1UL << 9), NSBinarySearchingInsertionIndex = (1UL << 10), }; ! - (NSUInteger)indexOfObject:(id)obj inSortedRange:(NSRange)r options:(NSBinarySearchingOptions)opts usingComparator:(NSComparator)cmp;
  25. indexOfObject: 54130.38 [ms] indexOfObject:inSortedRange: options:usingComparator: 7.62 [ms] NSOrderedSet 0.23 [ms]

    Time to search for 1000 entries within 1.000.000 objects
  26. Merge Sort O(N*lg N)

  27. typedef NS_OPTIONS(NSUInteger, NSBinarySearchingOptions) { NSBinarySearchingFirstEqual = (1UL << 8), NSBinarySearchingLastEqual

    = (1UL << 9), NSBinarySearchingInsertionIndex = (1UL << 10), }; ! - (NSUInteger)indexOfObject:(id)obj inSortedRange:(NSRange)r options:(NSBinarySearchingOptions)opts usingComparator:(NSComparator)cmp;
  28. Enumeration & Filtering

  29. NSMutableArray *mutableArray = [NSMutableArray array]; for (NSUInteger idx = 0;

    idx < randomArray.count; idx++) { id obj = randomArray[idx]; if (testObj(obj)) { [mutableArray addObject:obj]; } }
  30. NSMutableArray *mutableArray = [NSMutableArray array]; NSEnumerator *enumerator = [randomArray objectEnumerator];

    id obj = nil; while ((obj = [enumerator nextObject]) != nil) { if (testObj(obj)) { [mutableArray addObject:obj]; } }
  31. NSMutableArray *mutableArray = [NSMutableArray array]; for (id obj in randomArray)

    { if (testObj(obj)) { [mutableArray addObject:obj]; } }
  32. NSMutableArray *mutableArray = [NSMutableArray array]; [randomArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx,

    BOOL *stop) { if (testObj(obj)) { [mutableArray addObject:obj]; } }];
  33. NSIndexSet *indexes = [randomArray indexesOfObjectsWithOptions:NSEnumerationConcurrent passingTest:^BOOL(id obj, NSUInteger idx, BOOL

    *stop) { return testObj(obj); }]; __unused NSArray *filteredArray1 = [randomArray objectsAtIndexes:indexes];
  34. NSArray *filteredArray = [randomArray filteredArrayUsingPredicate: [NSPredicate predicateWithBlock:^BOOL(id obj, NSDictionary *bindings)

    { return testObj(obj); }]];
  35. indexesOfObjects: (concurrent) 1844.73 [ms] NSFastEnumeration 3223.45 [ms] indexesOfObjects: 4221.23 [ms]

    objectAtIndex: 5282.67 [ms] enumerateObjectsUsingBlock: 5459.43 [ms] NSEnumeration 5566.92 [ms] filteredArrayUsingPredicate: 6466.95 [ms] Enumerating + Filtering 10.000.000 elements
  36. Bonus Question Should I use arrayWithCapacity:?

  37. Dictionary NS

  38. [NSDictionary dictionaryWithObjectsAndKeys:object, key, nil] @{key : object, ...}

  39. - (void)setObject:(id)obj forKeyedSubscript:(id <NSCopying>)key NS_AVAILABLE(10_8, 6_0);

  40. CFDictionary CFDictionarySetValue() [setObject:forKey:]

  41. Subclassing

  42. Performance Object Access often: O(1) worst case: O(N) Insertion/Deletion often:

    O(1) worst case: O(N*N)
  43. Enumeration

  44. NSMutableDictionary *mutableDictionary = [NSMutableDictionary dictionary]; for (id key in randomDict)

    { id obj = randomDict[key]; if (testObj(obj)) { mutableDictionary[key] = obj; } }
  45. NSMutableDictionary *mutableDictionary = [NSMutableDictionary dictionary]; [randomDict enumerateKeysAndObjectsUsingBlock:^(id key, id obj,

    BOOL *stop) { if (testObj(obj)) { mutableDictionary[key] = obj; } }];
  46. NSArray *keys = [randomDict keysOfEntriesWithOptions:NSEnumerationConcurrent passingTest:^BOOL(id key, id obj, BOOL

    *stop) { return testObj(obj); }].allObjects; ! NSDictionary *filteredDictionary = [NSDictionary dictionaryWithObjects:[randomDict objectsForKeys:keys notFoundMarker:NSNull.null] forKeys:keys];
  47. NSMutableDictionary *mutableDictionary = [NSMutableDictionary dictionary]; id __unsafe_unretained *objects = (id

    __unsafe_unretained *)malloc(sizeof(id) * entries); id __unsafe_unretained *keys = (id __unsafe_unretained *)(malloc(sizeof(id) * entries)); [randomDict getObjects:objects andKeys:keys]; for (int i = 0; i < entries; i++) { id obj = objects[i]; id key = keys[i]; if (testObj(obj)) { mutableDictionary[key] = obj; } } free(objects); free(keys);
  48. keysOfEntriesWithOptions:(concurrent) 425.24 [ms] getObjects:andKeys: 798.49 [ms] keysOfEntriesWithOptions: 856.93 [ms] enumerateKeysAndObjectsUsingBlock:

    882.93 [ms] NSFastEnumeration 1043.42 [ms] NSEnumeration 1113.08 [ms] Enumerating + Filtering 1.000.000 elements
  49. Bonus Question Should I use dictionaryWithCapacity:?

  50. Shared Keys

  51. id sharedKeySet = [NSDictionary sharedKeySetForKeys:@[@1, @2, @3]]; // NSSharedKeySet NSMutableDictionary

    *test = [NSMutableDictionary dictionaryWithSharedKeySet:sharedKeySet]; NSDictionary *iAmStillAMutableObject = [test copy]; test[@4] = @"Works";
  52. NSPointerArray - (void)setCount:(NSUInteger)count;

  53. Set NS

  54. Set A Set B [a intersectSet:b] ———— [a unionSet:b] ————

    [a minusSet:b] [b minusSet:a]
  55. NSOrderedSet set array

  56. NSMutableOrderedSet (adding) 3190.52 [ms] NSMutableSet (adding) 2511.96 [ms] NSMutableArray (adding)

    1423.26 [ms] NSMutableOrderedSet (random access) 10.74 [ms] NSMutableSet (random access) 4.47 [ms] NSMutableArray (random access) 8.08 [ms] Adding + Random Accessing 1.000.000 elements
  57. Bonus Que… Should I use setWithCapacity:?

  58. NSHashTable

  59. NSPointerFunctions NSPointerFunctionsStrongMemory NSPointerFunctionsWeakMemory NSPointerFunctionsCopyIn NSPointerFunctionsObjectPersonality NSPointerFunctionsObjectPointerPersonality weakObjectsHashTable

  60. NSMapTable strongToStrongObjectsMapTable weakToStrongObjectsMapTable strongToWeakObjectsMapTable weakToWeakObjectsMapTable

  61. None
  62. Thanks! Peter Steinberger @steipete