Objective-C中不同方式实现锁(二)

移动开发 iOS
NSHashTable效仿了NSSet(NSMutableSet),但提供了比NSSet更多的操作选项,尤其是在对弱引用关系的支持上,NSHashTable在对象/内存处理时更加的灵活。相较于NSSet,NSHashTable具有以下特性:

Objective-C中不同方式实现锁(二)

NSHashTable

在看KVOController的代码时,又看到了NSHashTable这个类,所以就此整理一下。

NSHashTable效仿了NSSet(NSMutableSet),但提供了比NSSet更多的操作选项,尤其是在对弱引用关系的支持上,NSHashTable在对象/内存处理时更加的灵活。相较于NSSet,NSHashTable具有以下特性:

NSSet(NSMutableSet)持有其元素的强引用,同时这些元素是使用hash值及isEqual:方法来做hash检测及判断是否相等的。

NSHashTable是可变的,它没有不可变版本。

它可以持有元素的弱引用,而且在对象被销毁后能正确地将其移除。而这一点在NSSet是做不到的。

它的成员可以在添加时被拷贝。

它的成员可以使用指针来标识是否相等及做hash检测。

它可以包含任意指针,其成员没有限制为对象。我们可以配置一个NSHashTable实例来操作任意的指针,而不仅仅是对象。

初始化NSHashTable时,我们可以设置一个初始选项,这个选项确定了这个NSHashTable对象后面所有的行为。这个选项是由NSHashTableOptions枚举来定义的,如下所示:

  1. enum { 
  2.  
  3. // 默认行为,强引用集合中的对象,等同于NSSet 
  4. NSHashTableStrongMemory = 0
  5.  
  6. // 在将对象添加到集合之前,会拷贝对象 
  7. NSHashTableCopyIn = NSPointerFunctionsCopyIn, 
  8.  
  9. // 使用移位指针(shifted pointer)来做hash检测及确定两个对象是否相等; 
  10. // 同时使用description方法来做描述字符串 
  11. NSHashTableObjectPointerPersonality = NSPointerFunctionsObjectPointerPersonality, 
  12.  
  13. // 弱引用集合中的对象,且在对象被释放后,会被正确的移除。 
  14. NSHashTableWeakMemory = NSPointerFunctionsWeakMemory 
  15. }; 
  16. typedef NSUInteger NSHashTableOptions;

当然,我们还可以使用NSPointerFunctions来初始化,但只有使用NSHashTableOptions定义的这些值,才能确保NSHashTable的各个API可以正确的工作—包括拷贝、归档及快速枚举。

个人认为NSHashTable吸引人的地方在于可以持有元素的弱引用,而且在对象被销毁后能正确地将其移除。我们来写个示例:

  1. // 具体调用如下 
  2. @implementation TestHashAndMapTableClass { 
  3.  
  4. NSMutableDictionary *_dic; 
  5. NSSet *_set; 
  6.  
  7. NSHashTable *_hashTable; 
  8.  
  9. - (instancetype)init { 
  10.  
  11. self = [super init]; 
  12.  
  13. if (self) { 
  14.  
  15. [self testWeakMemory]; 
  16.  
  17. NSLog(@"hash table [init]: %@", _hashTable); 
  18.  
  19. return self; 
  20.  
  21. - (void)testWeakMemory { 
  22.  
  23. if (!_hashTable) { 
  24. _hashTable = [NSHashTable weakObjectsHashTable]; 
  25.  
  26. NSObject *obj = [[NSObject alloc] init]; 
  27.  
  28. [_hashTable addObject:obj]; 
  29.  
  30. NSLog(@"hash table [testWeakMemory] : %@", _hashTable); 
  31.  
  32. 这段代码的输出结果如下: 
  33.  
  34. hash table [testWeakMemory] : NSHashTable { 
  35. [6] <NSObject: 0x7fa2b1562670
  36. hash table [init]: NSHashTable { 
  37. }

可以看到,在离开testWeakMemory方法,obj对象被释放,同时对象在集合中的引用也被安全的删除。

这样看来,NSHashTable似乎比NSSet(NSMutableSet)要好啊。那是不是我们就应用都使用NSHashTable呢?Peter Steinberger在The Foundation Collection Classes给了我们一组数据,显示在添加对象的操作中,NSHashTable所有的时间差不多是NSMutableSet的2倍,而在其它操作中,性能大体相近。所以,如果我们只需要NSSet的特性,就尽量用NSSet。

另外,Mattt Thompson在NSHash​Table & NSMap​Table的结尾也写了段挺有意思的话,在此直接摘抄过来:

As always, it's important to remember that programming is not about being clever: always approach a problem from the highest viable level of abstraction. NSSet and NSDictionary are great classes. For 99% of problems, they are undoubtedly the correct tool for the job. If, however, your problem has any of the particular memory management constraints described above, then NSHashTable & NSMapTable may be worth a look.

参考

NSHashTable Class Reference

NSHash​Table & NSMap​Table

NSHashTable & NSMapTable

The Foundation Collection Classes

零碎

(一) “Unknown class XXViewController in Interface Builder file.”“ 问题处

最近在静态库中写了一个XXViewController类,然后在主工程的xib中,将xib的类指定为XXViewController,程序运行时,报了如下错误:

  1. Unknown class XXViewController in Interface Builder file. 

之前也遇到这个问题,但已记得不太清楚,所以又开始在stackoverflow上找答案。

其实这个问题与Interface Builder无关,最直接的原因还是相关的symbol没有从静态库中加载进来。这种问题的处理就是在Target的”Build Setting”–>“Other Link Flags”中加上”-all_load -ObjC”这两标识位,这样就OK了。

(二)关于Unbalanced calls to begin/end appearance transitions for …问题的处理

我们的某个业务有这么一个需求,进入一个列表后需要立马又push一个web页面,做一些活动的推广。在iOS 8上,我们的实现是一切OK的;但到了iOS 7上,就发现这个web页面push不出来了,同时控制台给了一条警告消息,即如下:

  1. Unbalanced calls to begin/end appearance transitions for ... 

在这种情况下,点击导航栏中的返回按钮时,直接显示一个黑屏。

我们到stackoverflow上查了一下,有这么一段提示:

  1. occurs when you try and display a new viewcontroller before the current view controller is finished displaying. 

意思是说在当前视图控制器完成显示之前,又试图去显示一个新的视图控制器。

于是我们去排查代码,果然发现,在viewDidLoad里面去做了次网络请求操作,且请求返回后就去push这个web活动推广页。此时,当前的视图控制器可能并未显示完成(即未完成push操作)。

  1. Basically you are trying to push two view controllers onto the stack at almost the same time.  

当几乎同时将两个视图控制器push到当前的导航控制器栈中时,或者同时pop两个不同的视图控制器,就会出现不确定的结果。所以我们应该确保同一时间,对同一个导航控制器栈只有一个操作,即便当前的视图控制器正在动画过程中,也不应该再去push或pop一个新的视图控制器。

所以***我们把web活动的数据请求放到了viewDidAppear里面,并做了些处理,这样问题就解决了。

责任编辑:chenqingxiang 来源: 南峰子的技术博客
相关推荐

2013-06-20 10:40:32

Objective-C实现截图

2013-03-26 10:35:47

Objective-C单例实现

2011-07-19 17:24:31

Objective-C 对象

2011-08-04 15:52:48

Objective-C HTML

2011-08-15 17:47:13

Objective-CisMemberOfC

2011-05-11 11:20:26

Objective-C

2011-05-11 15:58:34

Objective-C

2013-03-27 12:54:00

iOS开发Objective-C

2010-02-04 15:41:10

C++内存管理

2011-08-10 18:07:29

Objective-C反射

2011-07-27 16:18:42

Objective-c 协议

2011-08-15 17:06:01

Objective-CNSLog

2011-07-08 18:44:09

Objective-C Self Super

2011-07-20 13:34:37

Objective-C self.

2011-08-04 10:57:33

Objective-C C语言 BOOL

2011-08-04 09:35:09

Objective-C 编码规范

2011-08-03 16:55:05

Objective-C 代理

2012-06-15 09:47:48

Objective-CCategory

2014-06-25 14:02:59

Objective-CKVO

2011-07-29 16:16:30

Objective-c block
点赞
收藏

51CTO技术栈公众号