Skip to content

Latest commit

 

History

History
128 lines (85 loc) · 3.44 KB

Crash in Cocoa.md

File metadata and controls

128 lines (85 loc) · 3.44 KB

Crash in Cocoa

Cocoa中会导致Crash的地方:

##Exceptions类型 ##1. 集合类越界或插入Nil:

  • 数组类型

    越界访问会crash

  • 字典类型

    查询时:

     - (nullable ObjectType)objectForKey:(KeyType)aKey;

    当key为nil。能够正常运行。

    插入时:

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

    插入时object和key任一为nil,都会crash

  • 字符串类型

    获取substring时,越界访问会crash.

    包括:

     - (NSString *)substringFromIndex:(NSUInteger)from;
     - (NSString *)substringToIndex:(NSUInteger)to;
     - (NSString *)substringWithRange:(NSRange)range;  

##2. 访问悬挂指针(Dangling pointer)

悬挂指针,通常也被称为野指针。野指针,指的是指向不正确内存的指针。如果我们访问了不正确的内存,则会导致Crash。

那么什么情况下会导致野指针呢?

  • 访问了已被release,但尚未置空的指针

    在MRC时代,如果我们提前释放了对象,并且没有把对象置空,再访问这个对象,则会Crash。

     Person *mango = [[Person alloc]init];
     [mango release]; //object此时为野指针
     [mango setName:@"mango"]; // Crash:访问了野指针
     
     //正确做法
     Person *mango = [[Person alloc]init];
     [mango release] //object此时为野指针
     mango = nil;
     [mango setName:@"mango"]; //向nil发送消息,没有问题

    在ARC时代,编译器会我们进行引用计数的管理。声明为strong,weak的属性,在对象引用计数为零后,自动释放内存,同时将指针置为nil。

    那是否就万事大吉了呢。

    事实上由于历史原因,UIKit等官方框架里,许多delegate还是声明为assgin而不是weak。(Apple:其实是我懒得改了 :)

    声明为assgin和unsafe_unretained的对象,内存被释放后,编译器不会自动将指针置为nil。

    NSNetServices的delegate,官方的头文件是这样:

     @property (assign) id <NSNetServiceBrowserDelegate> delegate;

    类似这样声明的delegate,如果delegate提前被释放,但是我们没有帮助官方的类将delegate置空,如果此时官方的类需要调用到delegate,则同样会造成Crash。

    解决方案:

    遇到这种旧时代的官方delegate,为了安全起见,我们在dealloc将delegate置为nil

     - (void)setService:(NSNetService *)service
     {
         _service = service;
         
         self.service.delegate = self;
         [self.service resolveWithTimeout:5];
     }
     
     - (void)dealloc
     {
         // 避免悬挂指针
         self.service.delegate = nil;
     }

##3. 为不可为空的函数参数赋值nil

例如:

- (NSString *)stringByAppendingString:(NSString *)aString
//aString:
//The string to append to the receiver. This value must not be nil

//NSNotificationCenter
- (void)postNotification:(NSNotification * _Nonnull)notification
//notification
//The notification to post. This value must not be nil.

等等......

这种情况在Swift中已经不会再发生。Swift中Optional机制的引入。让我们不会因为忘记判空而导致Crash。

let cool = testStr.stringByAppendingString(nil)
//error: nil is not compatible with expected argument type 'String'



参考:

Understanding and Analyzing iOS Application Crash Reports

iOS Crash文件的解析