本帖最后由 竹林风 于 2018-12-24 14:57 编辑
仅是个人意见,如有问题,欢迎指正,谢谢。
1.block循环引用
情景:
[Objective-C] 纯文本查看 复制代码 self.animations = ^{
self.testArray= @[@"test"];
};
分析:
在上面的代码中:self对animations这个block强引用,block捕获了testArray对象,同样也对testArray持有强引用,而self对testArray也持有强引用。三者之间的引用:self -> animations -> testArray -> self。三者之间相互引用,引用计数无法变为0,导致内存泄漏。
解决方法:
1.最常用的方法是使用对self使用__weak修饰,__weak typeof(self)weakSelf = self,代码如下
[Objective-C] 纯文本查看 复制代码 __weak typeof (self) weakSelf = self;
self.animations = ^{
weakSelf.testArray= @[@"test"];
};
weakSelf也还是万能的,如果在多线程下,在某一个线程中,对str做了一次release操作了,内存被销毁了,但是指针还没有设置nil。由于是多线程,在销毁的瞬间,同时又有其他线程在访问str这个对象导致crash。(如果没有出现crash,可以加大循环的次数,改成1000)。
[Objective-C] 纯文本查看 复制代码 __weak MyViewController *wself = self; self.completionHandler = ^(NSInteger result) { [wself.property removeObserver: wself forKeyPath:@"pathName"];};
但是使用__strongtypeof(weakSelf)strongSelf = weakSelf;这样一来,self所指向对象的引用计数变成2,即使主线程中的self因为超出作用域而释放,对象的引用计数依然为1,避免了对象的销毁。
[Objective-C] 纯文本查看 复制代码 __weak MyViewController *wself =self; self.completionHandler = ^(NSIntegerresult) { __strong typeof(wself) sself = wself;// 强引用一次 [sself.property removeObserver: sself forKeyPath:@"pathName"];};
2.delegate循环引用
情景:
控制器a,视图b是控制器a的子视图。b.delegate = a。
分析:
视图b是控制器a的子视图,a对b强引用,而b对delegate强引用。b.delegate = a,delegate对控制器a强引用。引用关系:a -> b -> delegate -> a。
解决方法:
b的delegate使用weak修饰:@property(nonatomic,weak)id<BDelegate> delegate;
注意:不能使用assign代理weak,assign是修饰数值类型的变量的,因为基本数值类型是存在栈的,不需要手动管理内存。如果拿assign去修饰一个对象,会导致内存被销毁了,但是指针没有被置为nil,这个对象就会变成野指针,下次访问这个野指针的时候,谁也无法知道这个野指针是访问 了什么样的内存,导致crash。
3.NSTimer没有销毁
[Objective-C] 纯文本查看 复制代码 [NSTimer timerWithTimeInterval:1 target:self selector:@selector(viewDidLoad) userInfo:nil repeats:YES];
系统为了保证定时器能够正常运行,会对target一直强引用,知道定时器结束。所以即使页面已经pop了,但是页面并没有被销毁。即使使用__weak typeof(self) weakSelf = self;target传weakSelf也没有用,因为系统会一直对这个target强引用。苹果的官方文档是这么说的:
那要怎么销毁呢?在不需要定时器的时候,关闭定时器,把定时器置nil
[_timer invalidate];//关闭定时器 _timer = nil;//把定时器置nil 注意:不要在dealloc里面写着两句代码,因为_timer被循环引用着,压根就不会走到dealloc方法来。 4.非OC对象内存处理,没有手动释放 对于一些非OC对象,使用完毕后其内存仍需要我们手动释放。 比如,获取图片的像素点方法中: [Objective-C] 纯文本查看 复制代码 - (uint32_t*)pixelBRGABytesFromImageRef:(CGImageRef)imageRef { NSUInteger iWidth = CGImageGetWidth(imageRef); NSUInteger iHeight = CGImageGetHeight(imageRef); NSUIntegeriBytesPerPixel = 4; NSUIntegeriBytesPerRow = iBytesPerPixel * iWidth; NSUIntegeriBitsPerComponent = 8; uint32_t*pixels = (uint32_t*)malloc(iWidth * iHeight *sizeof(uint32_t)); memset(pixels,0, iWidth * iHeight *sizeof(uint32_t)); CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB(); CGContextRef context = CGBitmapContextCreate(pixels, iWidth, iHeight, iBitsPerComponent, iBytesPerRow, colorspace, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst); CGRectrect =CGRectMake(0 , 0 , iWidth , iHeight); CGContextDrawImage(context , rect ,imageRef); CGColorSpaceRelease(colorspace); CGContextRelease(context); CGImageRelease(imageRef); return pixels;}
在如上代码中的CGImageRef类型变量非OC对象,其需要手动执行释放操作CGImageRelease(imageRef) CGColorSpaceRelease(colorspace); CGContextRelease(context),否则会造成大量的内存泄漏导致程序崩溃。其他的对于CoreFoundation框架下的某些对象或变量需要手动释放、C语言代码中的malloc等需要对应free等都需要注意。
|