iOS内存管理一些要点

1.CADisplayLink、NSTimer注意事项

会对target产生强引用,如果target又对它们产生强引用,那么就会引发循环引用

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timerTest) userInfo:NULL repeats:YES];
    // 第一种写法解除循环引用
    __weak typeof(self) weakSelf = self;
    self.timer = [NSTimer scheduledTimerWithTimeInterval:1 repeats:YES block:^(NSTimer * _Nonnull timer) {
        [weakSelf timerTest];
    }];
    
    // 第二种方法
    self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:[MyProxy proxyWithTargt:self] selector:@selector(timerTest) userInfo:NULL repeats:YES];
}

- (void)timerTest{
    NSLog(@"%s", __func__);
}

- (void)dealloc{
    [self.timer invalidate];
    self.timer = nil;
    NSLog(@"%s", __func__);
}

其中MyProxy代码如下

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface MyProxy : NSProxy
+ (instancetype)proxyWithTargt:(id)target;
@end

NS_ASSUME_NONNULL_END
===================================

#import "MyProxy.h"
@interface MyProxy()
@property (nonatomic, weak) id target;
@end
@implementation MyProxy
+ (instancetype)proxyWithTargt:(id)target{
    MyProxy *proxy = [MyProxy alloc];
    proxy.target = target;
    return proxy;
}

- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel{
    return [self.target methodSignatureForSelector:sel];
}

- (void)forwardInvocation:(NSInvocation *)invocation{
    [invocation invokeWithTarget:self.target];
}
@end

另外timer定时器不准受Runloop影响,如果在一个Runloop循环中有耗时操作,就会影响间隔,CADisplayLink调用频率和刷帧频率一致,一般是1秒60次。

最准的定时器还是用gcd.

2.iOS内存布局图

 3.@autoreleasepool

底层是 一个叫AutoreleasePoolPage对象来管理的,是一页一页的。数据结构用到了“栈”。一个对象是0x1000的内存空间,即4096字节。所有的AutoreleasePoolPage对象通过双向链表的形式连接在一起

可以通过以下私有函数来查看自动释放池的情况

extern void _objc_autoreleasePoolPrint(void);

我们平常写的的代码为何会自动释放?

可以通过打印

NSLog(@"%@", [NSRunLoop mainRunLoop]);

可以知道如下结果:

iOS在主线程的Runloop中注册了2个Observer 第1个Observer监听了kCFRunLoopEntry事件,会调用objc_autoreleasePoolPush() 第2个Observer 监听了kCFRunLoopBeforeWaiting事件,会调用objc_autoreleasePoolPop()、objc_autoreleasePoolPush() 监听了kCFRunLoopBeforeExit事件,会调用objc_autoreleasePoolPop()

还有一个要点就是ARC环境下,在一个方法内的对象会在方法一结束就释放。因为ARC自动在末尾插入了release方法。

4.copy和mutableCopy

其实记住一个原理就是拷贝的目的:就是为了产生一个副本,并且不影响原来的对象。

所以会产生一些深浅拷贝的理论。

自定义的对象想要copy,需要遵守NSCopying协议。

5.引用计数的存储

在64bit中,引用计数可以直接存储在优化过的isa指针中,也可能存储在SideTable类中

refcnts是一个存放着对象引用计数的散列表

dealloc

发布了96 篇原创文章 · 获赞 10 · 访问量 9万+

猜你喜欢

转载自blog.csdn.net/feifeiwuxian/article/details/103615809