研究SDWebImage原理重新认识NSMapTable

NSMutableDictionary分析

我们都知道NSMutableDictionary/NSMutableArray,也会经常使用。大部分都知道NSMutableDictionary/NSMutableArray对里面的对象是强引用的。
我们先看官方文档怎么说?

- (void)setObject:(ObjectType)anObject forKey:(KeyType <NSCopying>)aKey;

官方文档的大概意思是我们在NSMutableDictionary的时候,key必须要遵循NSCopying协议。
因此NSMutableDictionary的key,实现NSCoping协议,相当于Key对象被copy一份后存入,那么对应的anObject则会被强引用。
我们看一下代码:

 NSMutableDictionary *aDictionary = [[NSMutableDictionary alloc] initWithCapacity:0];
    {
        NSString *aKey = @"key";
        NSObject *aObject = [[NSObject alloc] init];
        [aDictionary setObject:aObject forKey:aKey];
    }
    NSLog(@"dictionary: %@", aDictionary);

控制台输出结果:

dictionary: {
    key = "<NSObject: 0x600000b18fa0>";
}

如果不是强引用,那么作用域结束后,key变量指向NSString(也就是key)和aObject指向的NSObject应该被自动释放。但是aDictionary持有一份aObject对象的强引用,所以aDictionary对象不为空。

但是有时候我们希望不被强引用。那么我们的NSMapTable就出来了。

NSMapTable分析

NSMapTable继承自NSObject,自iOS6.0开始使用,NSMapTable是可变的。

API_AVAILABLE(macos(10.5), ios(6.0), watchos(2.0), tvos(9.0))
@interface NSMapTable<KeyType, ObjectType> : NSObject <NSCopying, NSSecureCoding, NSFastEnumeration>

初始化方法如下:

//指定初始化
- (instancetype)initWithKeyOptions:(NSPointerFunctionsOptions)keyOptions valueOptions:(NSPointerFunctionsOptions)valueOptions capacity:(NSUInteger)initialCapacity NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithKeyPointerFunctions:(NSPointerFunctions *)keyFunctions valuePointerFunctions:(NSPointerFunctions *)valueFunctions capacity:(NSUInteger)initialCapacity NS_DESIGNATED_INITIALIZER;
//便捷初始化
+ (NSMapTable<KeyType, ObjectType> *)mapTableWithKeyOptions:(NSPointerFunctionsOptions)keyOptions valueOptions:(NSPointerFunctionsOptions)valueOptions;

初始化方法方法中有两个参数keyOptions和valueOptions,都是NSPointerFunctionsOptions类型,NSPointerFunctionsOptions是一个枚举类型,

 // Memory options are mutually exclusive
    
    // default is strong
    NSPointerFunctionsStrongMemory API_AVAILABLE(macos(10.5), ios(6.0), watchos(2.0), tvos(9.0)) = (0UL << 0),       // use strong write-barrier to backing store; use GC memory on copyIn
    NSPointerFunctionsZeroingWeakMemory API_DEPRECATED("GC no longer supported", macos(10.5, 10.8)) API_UNAVAILABLE(ios, watchos, tvos) = (1UL << 0),  // deprecated; uses GC weak read and write barriers, and dangling pointer behavior otherwise
    NSPointerFunctionsOpaqueMemory API_AVAILABLE(macos(10.5), ios(6.0), watchos(2.0), tvos(9.0)) = (2UL << 0),
    NSPointerFunctionsMallocMemory API_AVAILABLE(macos(10.5), ios(6.0), watchos(2.0), tvos(9.0)) = (3UL << 0),       // free() will be called on removal, calloc on copyIn
    NSPointerFunctionsMachVirtualMemory API_AVAILABLE(macos(10.5), ios(6.0), watchos(2.0), tvos(9.0)) = (4UL << 0),
    NSPointerFunctionsWeakMemory API_AVAILABLE(macos(10.8), ios(6.0), watchos(2.0), tvos(9.0)) = (5UL << 0),         // uses weak read and write barriers appropriate for ARC
    
    // Personalities are mutually exclusive
    // default is object.  As a special case, 'strong' memory used for Objects will do retain/release under non-GC
    NSPointerFunctionsObjectPersonality API_AVAILABLE(macos(10.5), ios(6.0), watchos(2.0), tvos(9.0)) = (0UL << 8),         // use -hash and -isEqual, object description
    NSPointerFunctionsOpaquePersonality API_AVAILABLE(macos(10.5), ios(6.0), watchos(2.0), tvos(9.0)) = (1UL << 8),         // use shifted pointer hash and direct equality
    NSPointerFunctionsObjectPointerPersonality API_AVAILABLE(macos(10.5), ios(6.0), watchos(2.0), tvos(9.0)) = (2UL << 8),  // use shifted pointer hash and direct equality, object description
    NSPointerFunctionsCStringPersonality API_AVAILABLE(macos(10.5), ios(6.0), watchos(2.0), tvos(9.0)) = (3UL << 8),        // use a string hash and strcmp, description assumes UTF-8 contents; recommended for UTF-8 (or ASCII, which is a subset) only cstrings
    NSPointerFunctionsStructPersonality API_AVAILABLE(macos(10.5), ios(6.0), watchos(2.0), tvos(9.0)) = (4UL << 8),         // use a memory hash and memcmp (using size function you must set)
    NSPointerFunctionsIntegerPersonality API_AVAILABLE(macos(10.5), ios(6.0), watchos(2.0), tvos(9.0)) = (5UL << 8),        // use unshifted value as hash & equality

    NSPointerFunctionsCopyIn API_AVAILABLE(macos(10.5), ios(6.0), watchos(2.0), tvos(9.0)) = (1UL << 16),   

常用的枚举值:
NSPointerFunctionsStrongMemory: 强引用存储对象
NSPointerFunctionsWeakMemory: 弱引用存储对象
NSPointerFunctionsCopyIn copy存储对象

那么NSMapTable的初始化

NSMapTable *aMapTable = [[NSMapTable alloc] initWithKeyOptions:NSPointerFunctionsCopyIn valueOptions:NSPointerFunctionsStrongMemory capacity:0];

就等同于

NSMutableDictionary *aDictionary = [[NSMutableDictionary alloc] initWithCapacity:0];

如果想要对应的值自动释放,我们可以这么做

NSMapTable *aMapTable = [NSMapTable mapTableWithKeyOptions:NSPointerFunctionsStrongMemory valueOptions:NSPointerFunctionsWeakMemory];
{
    NSObject *keyObject = [[NSObject alloc] init];
    NSObject *valueObject = [[NSObject alloc] init];
    [aMapTable setObject:valueObject forKey:keyObject];
    NSLog(@"NSMapTable:%@", aMapTable);
}
NSLog(@"NSMapTable:%@", aMapTable);
NSMapTable:NSMapTable {
[0] <NSObject: 0x600000b18f00> -> <NSObject: 0x600000b18f90>
}
NSMapTable:NSMapTable {
}

第一个NSLog打印出了key-value值,等到object对象指向的NSObject对象超出作用域,释放该对象,由于aMapTable弱引用object对象,aMapTable的中的key-value值会被安全的删除,第二个NSLog打印出的值为空。

NSMapTable与NSMutableDictionary比较

1、NSMutableDictionary是可变类型,NSMapTable没有可变类型,它本身就是可变的
2、NSMutableDictionary中对于key和value的内存管理方法唯一,即对key进行copy,对value进行强引用,而NSMapTable没有限制
3、NSMutableDictionary中对key值进行copy,不可改变,通常用字符串作为key值,只是key->object的映射,而NSMapTable的key是可变的对象,既可以实现key->object的映射,又可以实现object->object的映射

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值