• Stars
    star
    113
  • Rank 308,555 (Top 7 %)
  • Language
    Objective-C
  • License
    MIT License
  • Created about 9 years ago
  • Updated about 8 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

An elegant solution to common crash of NSArray, NSMutableArray & NSMutableDictonary ...

##XTSafeCollection

CI Status Version License Platform

###背景 NSArray``NSMutableArray``NSDictionary``NSMutableDictionary是我们的在iOS开发中非常常用的类。当然,在享受这些类的便利的同时,它们也给我们带来一些困扰。粗心我们可能会调用addObject传入一个nil, 也有可能是会objectAtIndex传入一个越界的index。尤其是在数据基本依赖于服务端返回的的情况,这种crash大幅增加。最近项目上经常出现NSDictionarysetObject:forKey:nil object的崩溃。 ###解决方案 ####函数包装 我们希望能够用一个统一的方法解决粗心的程序员可能传入的nil object。我们最先想到的想法是对这些函数进行一个包装,比如objectAtIndex,我们写一个如下的函数

- (id)safeObjectAtIndex:(NSUInteger)index
{	
	if (index >= self.count)
	{
		return nil;
	}
	return [self objectAtIndex:index];
}

以后所有调用objectAtIndex的地方统统替换为safeObjectAtIndex。 不过,这显然不是我想要的,我不希望改变现有的调用方式,大家可能是通过[]objectAtIndex(不推荐)的方式获取数组元素,如果要做替换的话改动势必非常大,而且不便于以后的移植。我们希望代码调用objectAtIndex的时候,能够被我们先捕获到,进行处理之后再调用Cocoa的这个方法。Objective-C作为一门动态语言,有强大的动态加载的能力,提供了Method swizzling实现这样的功能。现在,黑魔法起飞。 ####Method swizzling 关于Method swizzling的具体实现,不打算多说,这里谈一下我遇到的问题。最初在做Method swizzling的时候,我尝试去替换NSArratobjectAtIndex:,但我始终没有办法替换掉这个方法。后来,搞了半天才发现,我们使用的NSAarray或者NSMutableArray并不是我们所看到样子,它们是class clusterobjectAtIndex:并不是他们的方法,而是他们背后的concrete class: __NSArrayI __NSArrayM的方法。解决了这个问题,剩下的就很简单了。 ###使用 直接把XTSafeCollection.h``XTSafeCollection.m拖入工程,NSArray``NSMutableArray``NSDictionary``NSMutableDictionary这些类的API以前是怎么调用的,还怎么写,完全不用修改。Demo里,我全部以传统的会引起crash的方式调用代码,以下是我的Demo的代码和输出

NSArray *array = @[@"a", @"b"];
NSMutableArray *mutableArray = [@[@"aa", @"bb"] mutableCopy];
    
// Object at index
NSLog(@"%@", array[10]);
NSLog(@"%@", mutableArray[100]);
    
// add object
[mutableArray addObject:nil];
    
// Insert object
[mutableArray insertObject:nil atIndex:0];
[mutableArray insertObject:@"cc" atIndex:10];
    
// Replace object
[mutableArray replaceObjectAtIndex:0 withObject:nil];
[mutableArray replaceObjectAtIndex:10 withObject:@"cc"];
    
// Dictionary
NSMutableDictionary *mutableDictionary = [NSMutableDictionary dictionary];
mutableDictionary[nil] = @"1";
mutableDictionary[@"1"] = nil;
2015-08-25 18:10:23.932 XTSafeCollection[29067:443479] [__NSArrayI objectAtIndex:] index {10} beyond bounds [0...1]
2015-08-25 18:10:23.933 XTSafeCollection[29067:443479] (null)
2015-08-25 18:10:23.933 XTSafeCollection[29067:443479] [__NSArrayM objectAtIndex:] index {100} beyond bounds [0...1]
2015-08-25 18:10:23.933 XTSafeCollection[29067:443479] (null)
2015-08-25 18:10:23.934 XTSafeCollection[29067:443479] [__NSArrayM addObject:], NIL object.
2015-08-25 18:10:23.934 XTSafeCollection[29067:443479] [__NSArrayM insertObject:atIndex:] NIL object.
2015-08-25 18:10:23.934 XTSafeCollection[29067:443479] [__NSArrayM insertObject:atIndex:] index {10} beyond bounds [0...1].
2015-08-25 18:10:23.934 XTSafeCollection[29067:443479] [__NSArrayM replaceObjectAtIndex:withObject:] NIL object.
2015-08-25 18:10:23.934 XTSafeCollection[29067:443479] [__NSArrayM replaceObjectAtIndex:withObject:] index {10} beyond bounds [0...1].
2015-08-25 18:10:23.934 XTSafeCollection[29067:443479] [__NSDictionaryM setObject:forKey:] NIL key.
2015-08-25 18:10:23.934 XTSafeCollection[29067:443479] [__NSDictionaryM setObject:forKey:] NIL object.

###版本:

  • 1.0.0
NSArray:
- (id)objectAtIndex:(NSUInteger)index;

NSMutableArray:
- (id)objectAtIndex:(NSUInteger)index;
- (void)insertObject:(id)anObject atIndex:(NSUInteger)index;
- (void)addObject:(id)object;
- (void)replaceObjectAtIndex:(NSUInteger)index withObject:(id)anObject;

NSMutableDictionary:
- (void)setObject:(id)anObject forKey:(id <NSCopying>)aKey;
  • 1.0.2
NSArray:
+ (instancetype)arrayWithObjects:(const id [])objects count:(NSUInteger)cnt; ( @[] )

NSDictionary:
+ (instancetype)dictionaryWithObjects:(const id [])objects forKeys:(const id <NSCopying> [])keys count:(NSUInteger)cnt; ( @{} )

###安装 pod "XTSafeCollection"

###TODO 兼容更多的crash情况

###Known Issues 替换NSMuatbelArrayobjectAtIndex:引起键盘展示状态态切换后台的崩溃,抛出

*** -[UIKeyboardLayoutStar release]: message sent to deallocated instance 0x7f883beac9c0

在这里 http://huang.sh/2015/02/%E4%B8%80%E4%B8%AA%E5%A5%87%E6%80%AA%E7%9A%84crash-uikeyboardlayoutstar-release/找到了解决方法 issue image