From a79c69a5f1b357e73a4c628402a71856e87895df Mon Sep 17 00:00:00 2001 From: Adlai Holler Date: Sun, 24 Jul 2016 15:31:09 -0700 Subject: [PATCH] [ASWeakSet] Refactor to use NSHashTable (#1976) [ASWeakSet] Tweak it [ASWeakSet] Simplify --- AsyncDisplayKit/Private/ASWeakSet.h | 5 ++-- AsyncDisplayKit/Private/ASWeakSet.m | 42 ++++++++++------------------- 2 files changed, 16 insertions(+), 31 deletions(-) diff --git a/AsyncDisplayKit/Private/ASWeakSet.h b/AsyncDisplayKit/Private/ASWeakSet.h index e44e68a1a5..9a8707eb84 100644 --- a/AsyncDisplayKit/Private/ASWeakSet.h +++ b/AsyncDisplayKit/Private/ASWeakSet.h @@ -35,10 +35,9 @@ NS_ASSUME_NONNULL_BEGIN - (NSArray *)allObjects; /** - How many objects are contained in this set. + * How many objects are contained in this set. - NOTE: This method is O(N). Consider using the `empty` - property. + * NOTE: This computed property is O(N). Consider using the `empty` property. */ @property (nonatomic, readonly) NSUInteger count; diff --git a/AsyncDisplayKit/Private/ASWeakSet.m b/AsyncDisplayKit/Private/ASWeakSet.m index 773af682fd..c68b730db9 100644 --- a/AsyncDisplayKit/Private/ASWeakSet.m +++ b/AsyncDisplayKit/Private/ASWeakSet.m @@ -13,7 +13,7 @@ #import "ASWeakSet.h" @interface ASWeakSet<__covariant ObjectType> () -@property (nonatomic, strong, readonly) NSMapTable *mapTable; +@property (nonatomic, strong, readonly) NSHashTable *hashTable; @end @implementation ASWeakSet @@ -22,59 +22,45 @@ { self = [super init]; if (self) { - _mapTable = [NSMapTable weakToStrongObjectsMapTable]; + _hashTable = [NSHashTable weakObjectsHashTable]; } return self; } - (void)addObject:(id)object { - [_mapTable setObject:(NSNull *)kCFNull forKey:object]; + [_hashTable addObject:object]; } - (void)removeObject:(id)object { - [_mapTable removeObjectForKey:object]; + [_hashTable removeObject:object]; } - (void)removeAllObjects { - [_mapTable removeAllObjects]; + [_hashTable removeAllObjects]; } - (NSArray *)allObjects { - // We use keys instead of values in the map table for efficiency and better characteristics when the keys are deallocated. - // Documentation is currently unclear on whether -keyEnumerator retains its values, but does imply that modifying a - // mutable collection is still not safe while enumerating that way - which is one of the main uses for this method. - // A helper function called NSAllMapTableKeys() might do exactly what we want and should be more efficient, but unfortunately - // is throwing a strange compiler error and may not be available in practice on the latest iOS version. - // Lastly, even -dictionaryRepresentation and then -allKeys won't work, because it attempts to copy the values of each key, - // which may not support copying (such as ASRangeControllers). - NSMutableArray *allObjects = [NSMutableArray array]; - for (id object in _mapTable) { - [allObjects addObject:object]; - } - return allObjects; + return _hashTable.allObjects; } - (BOOL)containsObject:(id)object { - return [_mapTable objectForKey:object] != nil; + return [_hashTable containsObject:object]; } - (BOOL)isEmpty { - for (__unused id object in _mapTable) { - return NO; - } - return YES; + return [_hashTable anyObject] == nil; } /** - Note: The `count` property of NSMapTable is unreliable - in the case of weak-to-strong map tables because entries - whose keys have been deallocated are not removed immediately. + Note: The `count` property of NSHashTable is unreliable + in the case of weak-object hash tables because entries + that have been deallocated are not removed immediately. In order to get the true count we have to fall back to using fast enumeration. @@ -82,7 +68,7 @@ - (NSUInteger)count { NSUInteger count = 0; - for (__unused id object in _mapTable) { + for (__unused id object in _hashTable) { count += 1; } return count; @@ -90,12 +76,12 @@ - (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(__unsafe_unretained id _Nonnull *)buffer count:(NSUInteger)len { - return [_mapTable countByEnumeratingWithState:state objects:buffer count:len]; + return [_hashTable countByEnumeratingWithState:state objects:buffer count:len]; } - (NSString *)description { - return [[super description] stringByAppendingFormat:@" count: %lu, contents: %@", (unsigned long)self.count, _mapTable]; + return [[super description] stringByAppendingFormat:@" count: %tu, contents: %@", self.count, _hashTable]; } @end