iOS 面试题 Objective-C

2017-12-05  本文已影响0人  th先生
  1. 请说明并比较以下关键词:strong,weak, assign, copy
  1. 请说明并比较以下关键词:__weak__block
  1. 请说明并比较以下关键词:atomatic, nonatomic
  1. 什么是ARC?
  1. 什么情况下会出现循环引用?
    循环引用是指2个或以上对象互相强引用,导致所有对象无法释放的现象。这是内存泄漏的一种情况。举个例子:
class Father
@interface Father: NSObject
@property (strong, nonatomic) Son *son;
@end
class Son
@interface Son: NSObject
@property (strong, nonatomic) Father *father; 
@end

上述代码有两个类,分别为爸爸和儿子。爸爸对儿子强引用,儿子对爸爸强引用。这样释放儿子必须先释放爸爸,要释放爸爸必须先释放儿子。如此一来,两个对象都无法释放。

解决方法是将Father中的Son对象属性从strong改为weak。

内存泄漏可以用Xcode中的Debug Memory Graph去检查,同时Xcode也会在runtime中自动汇报内存泄漏的问题。

  1. 下面代码中有什么bug?
- (void)viewDidLoad {
  UILabel *alertLabel = [[UILabel alloc] initWithFrame:CGRectMake(100,100,100,100)];
  alertLabel.text = @"Wait 4 seconds...";
  [self.view addSubview:alertLabel];
  NSOperationQueue *backgroundQueue = [[NSOperationQueue alloc] init];
  [backgroundQueue addOperationWithBlock:^{
    [NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:4]];
    alertLabel.text = @"Ready to go!”
  }];
}

Bug在于,在等了4秒之后,alertLabel并不会更新为Ready to Go。

原因是,所有UI的相关操作应该在主线程进行。当我们可以在一个后台线程中等待4秒,但是一定要在主线程中更新alertLabel。

最简单的修正如下:

- (void)viewDidLoad {
  UILabel *alertLabel = [[UILabel alloc] initWithFrame:CGRectMake(100,100,100,100)];
  alertLabel.text = @"Wait 4 seconds...";
  [self.view addSubview:alertLabel];
  NSOperationQueue *backgroundQueue = [[NSOperationQueue alloc] init];
  [backgroundQueue addOperationWithBlock:^{
    [NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:4]];
      [[NSOperationQueue mainQueue] addOperationWithBlock:^{
         alertLabel.text = @"Ready to go!”
      }];
  }];
}
  1. 以scheduledTimerWithTimeInterval的方式触发的timer,在滑动页面上的列表时,timer会暂停,为什么?该如何解决?
    原因在于滑动时当前线程的runloop切换了mode用于列表滑动,导致timer暂停。

runloop中的mode主要用来指定事件在runloop中的优先级,有以下几种:

解决方法其一是将timer加入到NSRunloopCommonModes中。其二是将timer放到另一个线程中,然后开启另一个线程的runloop,这样可以保证与主线程互不干扰,而现在主线程正在处理页面滑动。示例代码如下:

// 方法1
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
// 方法2
dispatch_async(dispatch_get_global_queue(0, 0), ^{
    timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(repeat:) userInfo:nil repeats:true];
    [[NSRunLoop currentRunLoop] run];
});
上一篇 下一篇

猜你喜欢

热点阅读