区块链技术博客
www.b2bchain.cn

iOS面试题目解析09 – 循环引用求职学习资料

本文介绍了iOS面试题目解析09 – 循环引用求职学习资料,有助于帮助完成毕业设计以及求职,是一篇很好的资料。

对技术面试,学习经验等有一些体会,在此分享。

iOS 中哪些情况会导致循环引用?

  • Block 中
  • delegate 使用 strong
  • NSTimer

Block 中的循环引用

由于block在copy时都会对block内部用到的对象进行强引用,比如下面的代码:

@property (nonatomic, copy) TestBlock testBlock;  self.testObject.testBlock = ^{    [self doSomething];  };

由于将 block 作为 self 的属性,self 持有这个 block,同时在block内部访问量 self,在 ARC 下会将 block copy到堆上,由于block在copy时都会对block内部用到的对象进行强引用,所以 block 也持有了 self,就循环引用了。

解决办法:使用 __weak

@property (nonatomic, copy) TestBlock testBlock;   __weak typeof(self) weakSelf = self;  self.testObject.testBlock = ^{    [weakSelf doSomething];  };

delegate 使用 strong 的循环引用

使用代理的时候,如果用 strong , 则该对象强引用 delegate,外界不能销毁 delegate 对象,会导致循环引用。

解决办法:使用 weak 关键字:。

@property (nonatomic, weak) id <MyDelegate> delegate;

NSTimer 中的循环引用

由于 self 强引用了 timer,同时 timertarget 设置成 self,则 timer 也强引用了 self,所以循环引用造成 dealloc 方法根本不会走,selftimer 都不会被释放,造成内存泄漏。比如下面的代码:

@interface ViewController ()  @property (nonatomic, strong) NSTimer *timer;  @end  @implementation ViewController  - (void)viewDidLoad {     [super viewDidLoad];      self.timer = [NSTimer scheduledTimerWithTimeInterval:1                                                   target:self                                                 selector:@selector(timerAction)                                                 userInfo:nil                                                  repeats:YES]; }  - (void)timerAction {     NSLog(@"timer log"); }  - (void)dealloc {     [self.timer invalidate];     self.timer = nil; }   @end

解决办法

1.合适的时机释放 timer

比如在 viewDidDisappear: 中手动释放 timer,但是不通用,并且很容易忘记。

- (void)viewDidDisappear:(BOOL)animated {     [super viewDidDisappear:animated];      [self.timer invalidate];     self.timer = nil; }

2.timer 使用 block 方式添加 Target-Action
NSTimer 添加分类,通过 block 的方式获取 action,实际的 target 设置为 self,即 NSTimer 类。这样在使用 timer 时,由于 target 的改变,就不再有循环引用了。

其实在 iOS 10 之后,Apple 也提供了以 Block 的方式添加定时器任务的 API,原理是一致的:

+ (NSTimer *)timerWithTimeInterval:(NSTimeInterval)interval repeats:(BOOL)repeats block:(void (^)(NSTimer *timer))block API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));

“`objc
@implementation NSTimer (BlcokTimer)

  • (NSTimer *)bl_scheduledTimerWithTimeInterval:(NSTimeInterval)interval block:(void (^)(void))block repeats:(BOOL)repeats {
    return [self scheduledTimerWithTimeInterval:interval
    target:self
    selector:@selector(bl_blockSelector:)
    userInfo:[block copy]
    repeats:repeats];

iOS 中哪些情况会导致循环引用?

  • Block 中
  • delegate 使用 strong
  • NSTimer

Block 中的循环引用

由于block在copy时都会对block内部用到的对象进行强引用,比如下面的代码:

@property (nonatomic, copy) TestBlock testBlock;  self.testObject.testBlock = ^{    [self doSomething];  };

由于将 block 作为 self 的属性,self 持有这个 block,同时在block内部访问量 self,在 ARC 下会将 block copy到堆上,由于block在copy时都会对block内部用到的对象进行强引用,所以 block 也持有了 self,就循环引用了。

解决办法:使用 __weak

@property (nonatomic, copy) TestBlock testBlock;   __weak typeof(self) weakSelf = self;  self.testObject.testBlock = ^{    [weakSelf doSomething];  };

delegate 使用 strong 的循环引用

使用代理的时候,如果用 strong , 则该对象强引用 delegate,外界不能销毁 delegate 对象,会导致循环引用。

解决办法:使用 weak 关键字:。

@property (nonatomic, weak) id <MyDelegate> delegate;

NSTimer 中的循环引用

由于 self 强引用了 timer,同时 timertarget 设置成 self,则 timer 也强引用了 self,所以循环引用造成 dealloc 方法根本不会走,selftimer 都不会被释放,造成内存泄漏。比如下面的代码:

@interface ViewController ()  @property (nonatomic, strong) NSTimer *timer;  @end  @implementation ViewController  - (void)viewDidLoad {     [super viewDidLoad];      self.timer = [NSTimer scheduledTimerWithTimeInterval:1                                                   target:self                                                 selector:@selector(timerAction)                                                 userInfo:nil                                                  repeats:YES]; }  - (void)timerAction {     NSLog(@"timer log"); }  - (void)dealloc {     [self.timer invalidate];     self.timer = nil; }   @end

解决办法

1.合适的时机释放 timer

比如在 viewDidDisappear: 中手动释放 timer,但是不通用,并且很容易忘记。

- (void)viewDidDisappear:(BOOL)animated {     [super viewDidDisappear:animated];      [self.timer invalidate];     self.timer = nil; }

2.timer 使用 block 方式添加 Target-Action
NSTimer 添加分类,通过 block 的方式获取 action,实际的 target 设置为 self,即 NSTimer 类。这样在使用 timer 时,由于 target 的改变,就不再有循环引用了。

其实在 iOS 10 之后,Apple 也提供了以 Block 的方式添加定时器任务的 API,原理是一致的:

+ (NSTimer *)timerWithTimeInterval:(NSTimeInterval)interval repeats:(BOOL)repeats block:(void (^)(NSTimer *timer))block API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));

“`objc
@implementation NSTimer (BlcokTimer)

  • (NSTimer *)bl_scheduledTimerWithTimeInterval:(NSTimeInterval)interval block:(void (^)(void))block repeats:(BOOL)repeats {
    return [self scheduledTimerWithTimeInterval:interval
    target:self
    selector:@selector(bl_blockSelector:)
    userInfo:[block copy]
    repeats:repeats];

iOS 中哪些情况会导致循环引用?

  • Block 中
  • delegate 使用 strong
  • NSTimer

Block 中的循环引用

由于block在copy时都会对block内部用到的对象进行强引用,比如下面的代码:

@property (nonatomic, copy) TestBlock testBlock;  self.testObject.testBlock = ^{    [self doSomething];  };

由于将 block 作为 self 的属性,self 持有这个 block,同时在block内部访问量 self,在 ARC 下会将 block copy到堆上,由于block在copy时都会对block内部用到的对象进行强引用,所以 block 也持有了 self,就循环引用了。

解决办法:使用 __weak

@property (nonatomic, copy) TestBlock testBlock;   __weak typeof(self) weakSelf = self;  self.testObject.testBlock = ^{    [weakSelf doSomething];  };

delegate 使用 strong 的循环引用

使用代理的时候,如果用 strong , 则该对象强引用 delegate,外界不能销毁 delegate 对象,会导致循环引用。

解决办法:使用 weak 关键字:。

@property (nonatomic, weak) id <MyDelegate> delegate;

NSTimer 中的循环引用

由于 self 强引用了 timer,同时 timertarget 设置成 self,则 timer 也强引用了 self,所以循环引用造成 dealloc 方法根本不会走,selftimer 都不会被释放,造成内存泄漏。比如下面的代码:

@interface ViewController ()  @property (nonatomic, strong) NSTimer *timer;  @end  @implementation ViewController  - (void)viewDidLoad {     [super viewDidLoad];      self.timer = [NSTimer scheduledTimerWithTimeInterval:1                                                   target:self                                                 selector:@selector(timerAction)                                                 userInfo:nil                                                  repeats:YES]; }  - (void)timerAction {     NSLog(@"timer log"); }  - (void)dealloc {     [self.timer invalidate];     self.timer = nil; }   @end

解决办法

1.合适的时机释放 timer

比如在 viewDidDisappear: 中手动释放 timer,但是不通用,并且很容易忘记。

- (void)viewDidDisappear:(BOOL)animated {     [super viewDidDisappear:animated];      [self.timer invalidate];     self.timer = nil; }

2.timer 使用 block 方式添加 Target-Action
NSTimer 添加分类,通过 block 的方式获取 action,实际的 target 设置为 self,即 NSTimer 类。这样在使用 timer 时,由于 target 的改变,就不再有循环引用了。

其实在 iOS 10 之后,Apple 也提供了以 Block 的方式添加定时器任务的 API,原理是一致的:

+ (NSTimer *)timerWithTimeInterval:(NSTimeInterval)interval repeats:(BOOL)repeats block:(void (^)(NSTimer *timer))block API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));

“`objc
@implementation NSTimer (BlcokTimer)

  • (NSTimer *)bl_scheduledTimerWithTimeInterval:(NSTimeInterval)interval block:(void (^)(void))block repeats:(BOOL)repeats {
    return [self scheduledTimerWithTimeInterval:interval
    target:self
    selector:@selector(bl_blockSelector:)
    userInfo:[block copy]
    repeats:repeats];

部分转自互联网,侵权删除联系

赞(0) 打赏
部分文章转自网络,侵权联系删除b2bchain区块链学习技术社区 » iOS面试题目解析09 – 循环引用求职学习资料
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

b2b链

联系我们联系我们