NSDictionary是IOS中使用的一種key-value容器英融,參考cocotron的源代碼克握,NSDictionary使用NSMapTable實現(xiàn)。
NSMapTable同樣是一個key-value的容器,下面是NSMapTable的部分代碼:
typedef struct {
NSMapTable? ? ? ? *table;
NSInteger? ? ? ? ? ? ? ? i;
struct _NSMapNode *j;
} NSMapEnumerator;
上述結(jié)構(gòu)體描述了遍歷一個NSMapTable時的一個指針對象坤次,其中包含table對象自身的指針,計數(shù)值斥赋,和節(jié)點指針缰猴。
typedef struct {
NSUInteger (*hash)(NSMapTable *table,const void *);
BOOL (*isEqual)(NSMapTable *table,const void *,const void *);
void (*retain)(NSMapTable *table,const void *);
void (*release)(NSMapTable *table,void *);
NSString? *(*describe)(NSMapTable *table,const void *);
const void *notAKeyMarker;
} NSMapTableKeyCallBacks;
上述結(jié)構(gòu)體中存放的是幾個函數(shù)指針,用于計算key的hash值疤剑,判斷key是否相等滑绒,retain,release操作隘膘。
typedef struct {
void? ? ? (*retain)(NSMapTable *table,const void *);
void? ? ? (*release)(NSMapTable *table,void *);
NSString? *(*describe)(NSMapTable *table, const void *);
} NSMapTableValueCallBacks;
上述存放的三個函數(shù)指針疑故,定義在對nsmaptable插入一對key-value時,對value對象的操作棘幸。
@interface NSMapTable : NSObject {
NSMapTableKeyCallBacks? *keyCallBacks;
NSMapTableValueCallBacks *valueCallBacks;
NSUInteger? ? ? ? ? ? count;
NSUInteger? ? ? ? ? ? nBuckets;
struct _NSMapNode? **buckets;
}
上面是NSMtabtable真正的描述焰扳,可以看出來NSMapTable是一個哈希+鏈表的數(shù)據(jù)結(jié)構(gòu),因此在NSMapTable中插入或者刪除一對對象時
尋找的時間是O(1)+O(m)误续,m最壞時可能為n吨悍。
O(1):為對key進行hash得到bucket的位置
O(m):遍歷該bucket后面沖突的value,通過鏈表連接起來蹋嵌。
因此:NSDictionary中的key Value遍歷時是無序的育瓜,至如按照什么樣的順序,跟hash函數(shù)相關(guān)栽烂。NSMapTable使用NSObject的哈希函數(shù)躏仇。
-(NSUInteger)hash {
return (NSUInteger)self>>4;
}
上述是NSObject的哈希值的計算方式恋脚,簡單通過移位實現(xiàn)。右移4位焰手,左邊補0.
因為對象大多存于堆中糟描,地址相差4位應(yīng)該很正常。
@implementation NSDictionary (NSKeyValueCoding)
-(id)valueForKey:(NSString*)key;
{
if([key hasPrefix:@"@"])
return [super valueForKey:[key substringFromIndex:1]];
return [self objectForKey:key];
}
-(void)setValue:(id)value forKey:(NSString*)key
{
[NSException raise:NSInvalidArgumentException format:@"%@ called on immutable dictionary %@", NSStringFromSelector(_cmd), self];
}
@end
@implementation NSMutableDictionary (NSKeyValueCoding)
-(void)setValue:(id)value forKey:(NSString*)key
{
if(value)
[self setObject:value forKey:key];
else
[self removeObjectForKey:key];
}
@end
使用setObject:ForKey時很可能因為value或者key為空導(dǎo)致crash书妻,使用setValue:Forkey就不會船响。