本文介绍了iOS 内存管理求职学习资料,有助于帮助完成毕业设计以及求职,是一篇很好的资料。
对技术面试,学习经验等有一些体会,在此分享。
一、Objective-C 使用引用计数来管理内存。
每个对象都有一个计数器,来表示引用该对象的个数;每次引用就加1,用完就减1;当计数为0时表示不再使用该对象,于是就销毁该对象。
多个对象之间的引用形成闭环会导致循环引用,从而不能够相互释放,造成内存泄漏。
二、ARC 自动引用计数
ARC 自动引用计数,把内存管理事宜交由编译器来处理。
使用 ARC 时,实际上引用计数还是在执行的,只不过保留操作和释放操作由 ARC 在编译时自动为你添加。
ARC 环境下特殊情况处理。
- (void)dealloc { // 移除通知中心的监听者 // 移除 KVO 监听者 // 关闭 NSTimer,并将定时器置空(nil) // 释放非 Objective-C 对象的内存,如 CFRelease(...), free(...) }
三、自动释放池
@autoreleasepool {} 自动释放池。
当向一个对象发送autorelease消息时,系统会将该对象放入到最新的自动释放池。
在自动释放池的作用域内,池子内的对象依然可以正常使用。
当自动释放池的作用域结束时,再释放池子内的对象———每个对象收到几个autorelease就进行几次release操作。
常见用途:循环内部创建大量临时对象时,没有及时释放导致内存使用急剧增加,可以使用自动释放池在每次循环结束时释放对象。
for (NSInteger i = 0; i < 100000; i++) { @autoreleasepool { NSString *str = @"Hello World"; str = [str stringByAppendingFormat:@"- %ld", i]; str = [str uppercaseString]; } }
四、@property 属性修饰符
原子性(多线程管理):atomic、nonatomic
读写属性:readwrite、readonly
setter 语意:assign、retain、copy
强弱引用:strong、weak
1、NSNumber、NSString、Block 使用 copy。
2、IBOutlet 属性、引用“引用对象”的属性(控制器引用view的子视图)、代理属性使用 weak。
3、Class、id 类型的属性使用 retain。
4、NSString 属性使用 retain 时,可能赋值一个 NSMutableString,导致值为 NSMutableString 类型。
5、NSMutableString 属性使用 copy 时,导致属性值为 NSString 类型,有可能出现未识别方法调用的异常。
atomic 只是保证了读写的线程安全,但是在多线程环境访问对象属性时,访问结果不一定符合我们的预期。
- (void)setAtomicObj:(NSObject *)atomicObj{ @synchronized(self) { if (_atomicObj != atomicObj) { [_atomicObj release]; _atomicObj = [atomicObj retain]; } } } - (NSObject *)atomicObj{ @synchronized(self) { return _atomicObj; } }
ARC下同时重写getter、setter方法时,需使用关键字@synthesize 声明变量和属性的关系。
@synthesize name = _name;
注意:@property = ivar + getter + setter;
五、定时器使用时的内存管理
通常控制器会拥有一个定时器,如果把控制器设置为定时器的 target,定时器会引用控制器,导致定时器不关闭销毁时不能释放控制器。因此,想办法不要定时器直接或者间接引用控制器即可。
定时器解决循环引用思路:
1、iOS10 以后系统提供了block 方法执行定时器操作。
[NSTimer timerWithTimeInterval:(NSTimeInterval) repeats:(BOOL) block:^(NSTimer * _Nonnull timer) { }]; [NSTimer scheduledTimerWithTimeInterval:(NSTimeInterval) repeats:(BOOL) block:^(NSTimer * _Nonnull timer) { }];
2、给 NSTimer 提供一个分类,实现自定义的 block 方法。
@interface NSTimer (BBBlocksSupport) + (NSTimer *)bb_scheduledTimerWithTimeInterval:(NSTimeInterval)interval block:(void(^)(void))block repeats:(BOOL)repeats; @end
@implementation NSTimer (BBBlocksSupport) + (NSTimer *)bb_scheduledTimerWithTimeInterval:(NSTimeInterval)interval block:(void(^)(void))block repeats:(BOOL)repeats { return [self scheduledTimerWithTimeInterval:interval target:self selector:@selector(bb_blockInvoke:) userInfo:[block copy] repeats:repeats]; } + (void)bb_blockInvoke:(NSTimer *)timer { void (^block)(void) = timer.userInfo; if (block) { block(); } } @end
3、中间件模式。
设计思路:给中间对象动态添加定时器需要执行的方法。
#import <Foundation/Foundation.h> @interface BBTimerManager : NSObject @property (weak, nonatomic) NSTimer *bb_timer; + (instancetype)bb_timerManagerWithTimeInterval:(NSTimeInterval)interval target:(id)aTarget selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)repeats; @end
#import "BBTimerManager.h" #import <objc/runtime.h> @implementation BBTimerManager + (instancetype)bb_timerManagerWithTimeInterval:(NSTimeInterval)interval target:(id)aTarget selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)repeats { Method targetMethod = class_getInstanceMethod([aTarget class], aSelector); if (!class_addMethod([BBTimerManager class], aSelector, method_getImplementation(targetMethod), method_getTypeEncoding(targetMethod))) { class_replaceMethod([BBTimerManager class], aSelector, method_getImplementation(targetMethod), method_getTypeEncoding(targetMethod)); } BBTimerManager *manager = [BBTimerManager new]; manager.bb_timer = [NSTimer scheduledTimerWithTimeInterval:interval target:manager selector:aSelector userInfo:userInfo repeats:repeats]; return manager; } @end
- (void)dealloc { [_timerManager.bb_timer invalidate]; _timerManager.bb_timer = nil; }
六、优雅使用 KVO
在需要处理属性变化事件的对象中添加观察者,并在该对象销毁时移除观察者。
@interface RootViewController () @property (retain, nonatomic) Focus *focus; @end
@implementation RootViewController - (void)viewDidLoad { [super viewDidLoad]; self.focus = [[Focus alloc] init]; [self.focus addObserver:self forKeyPath:@"number" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil]; self.focus.number = @2; } - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context { if ([keyPath isEqualToString:@"number"]) { NSLog(@"%@", change); } } - (void)dealloc { [self.focus removeObserver:self forKeyPath:@"number"]; }
七、copy 操作
对于不可变对象 NSString、NSArray、NSDictionary 表示引用加1。
对于可变对象 NSMutableString、NSMutableArray、NSMutableDictionary 表示复制对象,返回不可变对象。
mutableCopy 操作:
对于不可变对象、可变对象都是表示复制对象,返回可变对象。
自定义对象使用 copy 和 mutableCopy 需要遵守 NSCopying 和 NSMutableCopying 协议。
- (id)copyWithZone:(nullable NSZone *)zone; - (id)mutableCopyWithZone:(nullable NSZone *)zone;
一、Objective-C 使用引用计数来管理内存。
每个对象都有一个计数器,来表示引用该对象的个数;每次引用就加1,用完就减1;当计数为0时表示不再使用该对象,于是就销毁该对象。
多个对象之间的引用形成闭环会导致循环引用,从而不能够相互释放,造成内存泄漏。
二、ARC 自动引用计数
ARC 自动引用计数,把内存管理事宜交由编译器来处理。
使用 ARC 时,实际上引用计数还是在执行的,只不过保留操作和释放操作由 ARC 在编译时自动为你添加。
ARC 环境下特殊情况处理。
- (void)dealloc { // 移除通知中心的监听者 // 移除 KVO 监听者 // 关闭 NSTimer,并将定时器置空(nil) // 释放非 Objective-C 对象的内存,如 CFRelease(...), free(...) }
三、自动释放池
@autoreleasepool {} 自动释放池。
当向一个对象发送autorelease消息时,系统会将该对象放入到最新的自动释放池。
在自动释放池的作用域内,池子内的对象依然可以正常使用。
当自动释放池的作用域结束时,再释放池子内的对象———每个对象收到几个autorelease就进行几次release操作。
常见用途:循环内部创建大量临时对象时,没有及时释放导致内存使用急剧增加,可以使用自动释放池在每次循环结束时释放对象。
for (NSInteger i = 0; i < 100000; i++) { @autoreleasepool { NSString *str = @"Hello World"; str = [str stringByAppendingFormat:@"- %ld", i]; str = [str uppercaseString]; } }
四、@property 属性修饰符
原子性(多线程管理):atomic、nonatomic
读写属性:readwrite、readonly
setter 语意:assign、retain、copy
强弱引用:strong、weak
1、NSNumber、NSString、Block 使用 copy。
2、IBOutlet 属性、引用“引用对象”的属性(控制器引用view的子视图)、代理属性使用 weak。
3、Class、id 类型的属性使用 retain。
4、NSString 属性使用 retain 时,可能赋值一个 NSMutableString,导致值为 NSMutableString 类型。
5、NSMutableString 属性使用 copy 时,导致属性值为 NSString 类型,有可能出现未识别方法调用的异常。
atomic 只是保证了读写的线程安全,但是在多线程环境访问对象属性时,访问结果不一定符合我们的预期。
- (void)setAtomicObj:(NSObject *)atomicObj{ @synchronized(self) { if (_atomicObj != atomicObj) { [_atomicObj release]; _atomicObj = [atomicObj retain]; } } } - (NSObject *)atomicObj{ @synchronized(self) { return _atomicObj; } }
ARC下同时重写getter、setter方法时,需使用关键字@synthesize 声明变量和属性的关系。
@synthesize name = _name;
注意:@property = ivar + getter + setter;
五、定时器使用时的内存管理
通常控制器会拥有一个定时器,如果把控制器设置为定时器的 target,定时器会引用控制器,导致定时器不关闭销毁时不能释放控制器。因此,想办法不要定时器直接或者间接引用控制器即可。
定时器解决循环引用思路:
1、iOS10 以后系统提供了block 方法执行定时器操作。
[NSTimer timerWithTimeInterval:(NSTimeInterval) repeats:(BOOL) block:^(NSTimer * _Nonnull timer) { }]; [NSTimer scheduledTimerWithTimeInterval:(NSTimeInterval) repeats:(BOOL) block:^(NSTimer * _Nonnull timer) { }];
2、给 NSTimer 提供一个分类,实现自定义的 block 方法。
@interface NSTimer (BBBlocksSupport) + (NSTimer *)bb_scheduledTimerWithTimeInterval:(NSTimeInterval)interval block:(void(^)(void))block repeats:(BOOL)repeats; @end
@implementation NSTimer (BBBlocksSupport) + (NSTimer *)bb_scheduledTimerWithTimeInterval:(NSTimeInterval)interval block:(void(^)(void))block repeats:(BOOL)repeats { return [self scheduledTimerWithTimeInterval:interval target:self selector:@selector(bb_blockInvoke:) userInfo:[block copy] repeats:repeats]; } + (void)bb_blockInvoke:(NSTimer *)timer { void (^block)(void) = timer.userInfo; if (block) { block(); } } @end
3、中间件模式。
设计思路:给中间对象动态添加定时器需要执行的方法。
#import <Foundation/Foundation.h> @interface BBTimerManager : NSObject @property (weak, nonatomic) NSTimer *bb_timer; + (instancetype)bb_timerManagerWithTimeInterval:(NSTimeInterval)interval target:(id)aTarget selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)repeats; @end
#import "BBTimerManager.h" #import <objc/runtime.h> @implementation BBTimerManager + (instancetype)bb_timerManagerWithTimeInterval:(NSTimeInterval)interval target:(id)aTarget selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)repeats { Method targetMethod = class_getInstanceMethod([aTarget class], aSelector); if (!class_addMethod([BBTimerManager class], aSelector, method_getImplementation(targetMethod), method_getTypeEncoding(targetMethod))) { class_replaceMethod([BBTimerManager class], aSelector, method_getImplementation(targetMethod), method_getTypeEncoding(targetMethod)); } BBTimerManager *manager = [BBTimerManager new]; manager.bb_timer = [NSTimer scheduledTimerWithTimeInterval:interval target:manager selector:aSelector userInfo:userInfo repeats:repeats]; return manager; } @end
- (void)dealloc { [_timerManager.bb_timer invalidate]; _timerManager.bb_timer = nil; }
六、优雅使用 KVO
在需要处理属性变化事件的对象中添加观察者,并在该对象销毁时移除观察者。
@interface RootViewController () @property (retain, nonatomic) Focus *focus; @end
@implementation RootViewController - (void)viewDidLoad { [super viewDidLoad]; self.focus = [[Focus alloc] init]; [self.focus addObserver:self forKeyPath:@"number" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil]; self.focus.number = @2; } - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context { if ([keyPath isEqualToString:@"number"]) { NSLog(@"%@", change); } } - (void)dealloc { [self.focus removeObserver:self forKeyPath:@"number"]; }
七、copy 操作
对于不可变对象 NSString、NSArray、NSDictionary 表示引用加1。
对于可变对象 NSMutableString、NSMutableArray、NSMutableDictionary 表示复制对象,返回不可变对象。
mutableCopy 操作:
对于不可变对象、可变对象都是表示复制对象,返回可变对象。
自定义对象使用 copy 和 mutableCopy 需要遵守 NSCopying 和 NSMutableCopying 协议。
- (id)copyWithZone:(nullable NSZone *)zone; - (id)mutableCopyWithZone:(nullable NSZone *)zone;
一、Objective-C 使用引用计数来管理内存。
每个对象都有一个计数器,来表示引用该对象的个数;每次引用就加1,用完就减1;当计数为0时表示不再使用该对象,于是就销毁该对象。
多个对象之间的引用形成闭环会导致循环引用,从而不能够相互释放,造成内存泄漏。
二、ARC 自动引用计数
ARC 自动引用计数,把内存管理事宜交由编译器来处理。
使用 ARC 时,实际上引用计数还是在执行的,只不过保留操作和释放操作由 ARC 在编译时自动为你添加。
ARC 环境下特殊情况处理。
- (void)dealloc { // 移除通知中心的监听者 // 移除 KVO 监听者 // 关闭 NSTimer,并将定时器置空(nil) // 释放非 Objective-C 对象的内存,如 CFRelease(...), free(...) }
三、自动释放池
@autoreleasepool {} 自动释放池。
当向一个对象发送autorelease消息时,系统会将该对象放入到最新的自动释放池。
在自动释放池的作用域内,池子内的对象依然可以正常使用。
当自动释放池的作用域结束时,再释放池子内的对象———每个对象收到几个autorelease就进行几次release操作。
常见用途:循环内部创建大量临时对象时,没有及时释放导致内存使用急剧增加,可以使用自动释放池在每次循环结束时释放对象。
for (NSInteger i = 0; i < 100000; i++) { @autoreleasepool { NSString *str = @"Hello World"; str = [str stringByAppendingFormat:@"- %ld", i]; str = [str uppercaseString]; } }
四、@property 属性修饰符
原子性(多线程管理):atomic、nonatomic
读写属性:readwrite、readonly
setter 语意:assign、retain、copy
强弱引用:strong、weak
1、NSNumber、NSString、Block 使用 copy。
2、IBOutlet 属性、引用“引用对象”的属性(控制器引用view的子视图)、代理属性使用 weak。
3、Class、id 类型的属性使用 retain。
4、NSString 属性使用 retain 时,可能赋值一个 NSMutableString,导致值为 NSMutableString 类型。
5、NSMutableString 属性使用 copy 时,导致属性值为 NSString 类型,有可能出现未识别方法调用的异常。
atomic 只是保证了读写的线程安全,但是在多线程环境访问对象属性时,访问结果不一定符合我们的预期。
- (void)setAtomicObj:(NSObject *)atomicObj{ @synchronized(self) { if (_atomicObj != atomicObj) { [_atomicObj release]; _atomicObj = [atomicObj retain]; } } } - (NSObject *)atomicObj{ @synchronized(self) { return _atomicObj; } }
ARC下同时重写getter、setter方法时,需使用关键字@synthesize 声明变量和属性的关系。
@synthesize name = _name;
注意:@property = ivar + getter + setter;
五、定时器使用时的内存管理
通常控制器会拥有一个定时器,如果把控制器设置为定时器的 target,定时器会引用控制器,导致定时器不关闭销毁时不能释放控制器。因此,想办法不要定时器直接或者间接引用控制器即可。
定时器解决循环引用思路:
1、iOS10 以后系统提供了block 方法执行定时器操作。
[NSTimer timerWithTimeInterval:(NSTimeInterval) repeats:(BOOL) block:^(NSTimer * _Nonnull timer) { }]; [NSTimer scheduledTimerWithTimeInterval:(NSTimeInterval) repeats:(BOOL) block:^(NSTimer * _Nonnull timer) { }];
2、给 NSTimer 提供一个分类,实现自定义的 block 方法。
@interface NSTimer (BBBlocksSupport) + (NSTimer *)bb_scheduledTimerWithTimeInterval:(NSTimeInterval)interval block:(void(^)(void))block repeats:(BOOL)repeats; @end
@implementation NSTimer (BBBlocksSupport) + (NSTimer *)bb_scheduledTimerWithTimeInterval:(NSTimeInterval)interval block:(void(^)(void))block repeats:(BOOL)repeats { return [self scheduledTimerWithTimeInterval:interval target:self selector:@selector(bb_blockInvoke:) userInfo:[block copy] repeats:repeats]; } + (void)bb_blockInvoke:(NSTimer *)timer { void (^block)(void) = timer.userInfo; if (block) { block(); } } @end
3、中间件模式。
设计思路:给中间对象动态添加定时器需要执行的方法。
#import <Foundation/Foundation.h> @interface BBTimerManager : NSObject @property (weak, nonatomic) NSTimer *bb_timer; + (instancetype)bb_timerManagerWithTimeInterval:(NSTimeInterval)interval target:(id)aTarget selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)repeats; @end
#import "BBTimerManager.h" #import <objc/runtime.h> @implementation BBTimerManager + (instancetype)bb_timerManagerWithTimeInterval:(NSTimeInterval)interval target:(id)aTarget selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)repeats { Method targetMethod = class_getInstanceMethod([aTarget class], aSelector); if (!class_addMethod([BBTimerManager class], aSelector, method_getImplementation(targetMethod), method_getTypeEncoding(targetMethod))) { class_replaceMethod([BBTimerManager class], aSelector, method_getImplementation(targetMethod), method_getTypeEncoding(targetMethod)); } BBTimerManager *manager = [BBTimerManager new]; manager.bb_timer = [NSTimer scheduledTimerWithTimeInterval:interval target:manager selector:aSelector userInfo:userInfo repeats:repeats]; return manager; } @end
- (void)dealloc { [_timerManager.bb_timer invalidate]; _timerManager.bb_timer = nil; }
六、优雅使用 KVO
在需要处理属性变化事件的对象中添加观察者,并在该对象销毁时移除观察者。
@interface RootViewController () @property (retain, nonatomic) Focus *focus; @end
@implementation RootViewController - (void)viewDidLoad { [super viewDidLoad]; self.focus = [[Focus alloc] init]; [self.focus addObserver:self forKeyPath:@"number" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil]; self.focus.number = @2; } - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context { if ([keyPath isEqualToString:@"number"]) { NSLog(@"%@", change); } } - (void)dealloc { [self.focus removeObserver:self forKeyPath:@"number"]; }
七、copy 操作
对于不可变对象 NSString、NSArray、NSDictionary 表示引用加1。
对于可变对象 NSMutableString、NSMutableArray、NSMutableDictionary 表示复制对象,返回不可变对象。
mutableCopy 操作:
对于不可变对象、可变对象都是表示复制对象,返回可变对象。
自定义对象使用 copy 和 mutableCopy 需要遵守 NSCopying 和 NSMutableCopying 协议。
- (id)copyWithZone:(nullable NSZone *)zone; - (id)mutableCopyWithZone:(nullable NSZone *)zone;
部分转自互联网,侵权删除联系
最新评论