3. iOS面试题原理篇1

2020-11-27  本文已影响0人  越天高

runtime怎么添加属性、方法等


是否可以把比较耗时的操作放在NSNotificationCenter

runtime 如何实现 weak 属性

weak策略表明该属性定义了一种“非拥有关系” (nonowning relationship)。

为这种属性设置新值时,设置方法既不保留新值,也不释放旧值。此特质同assign类似;

然而在属性所指的对象遭到摧毁时,属性值也会清空(nil out)

那么runtime如何实现weak变量的自动置nil?

runtime对注册的类,会进行布局,会将 weak 对象放入一个 hash 表中。

用 weak 指向的对象内存地址作为 key,当此对象的引用计数为0的时候会调用对象的 dealloc 方法,

假设 weak 指向的对象内存地址是a,那么就会以a为key,在这个 weak hash表中搜索,找到所有以a为key的 weak 对象,从而设置为 nil。

weak属性需要在dealloc中置nil

// 模拟下weak的setter方法,大致如下

- (void)setObject:(NSObject *)object

{

 objc_setAssociatedObject(self, "object", object, OBJC_ASSOCIATION_ASSIGN);

 [object cyl_runAtDealloc:^{

 _object = nil;

 }];

}

一个Objective-C对象如何进行内存布局?(考虑有父类的情况)

Objective-C 对象的结构图
ISA指针
根类(NSObject)的实例变量
倒数第二层父类的实例变量
...
父类的实例变量
类的实例变量

一个objc对象的isa的指针指向什么?有什么作用?

下面的代码输出什么?

@implementation  Son : Father

- (id)init

{

 self = [super init];

 if (self) {

 NSLog(@"%@", NSStringFromClass([self class]));

 NSLog(@"%@", NSStringFromClass([super class]));

 }

  return  self;

}

@end

runtime如何通过selector找到对应的IMP地址?(分别考虑类方法和实例方法)

objc中的类方法和实例方法有什么本质区别和联系

类方法:

实例方法:

使用runtime Associate方法关联的对象,需要在主对象dealloc的时候释放么?

1.调用 -release :引用计数变为零

  1. 父类调用 -dealloc
  1. NSObject 调 -dealloc
  1. 调用 object_dispose()

_objc_msgForward函数是做什么的?直接调用它将会发生什么?

能否向编译后得到的类中增加实例变量?能否向运行时创建的类中添加实例变量?为什么?

runloop和线程有什么关系?

runloopmode作用是什么?

+scheduledTimerWithTimeInterval...的方式触发的timer,在滑动页面上的列表时,timer会暂定回调,为什么?如何解决?

猜想runloop内部是如何实现的?

• 附上RunLoop的运行图

ME. MEMOS AN.png

不手动指定autoreleasepool的前提下,一个autorealese对象在什么时刻释放?(比如在一个vcviewDidLoad中创建)

苹果是如何实现autoreleasepool的?

objc_autoreleasepoolPush

objc_autoreleasepoolPop

objc_aurorelease

GCD的队列(dispatch_queue_t)分哪两种类型?背后的线程模型是什么样的?

苹果为什么要废弃dispatch_get_current_queue

如何用GCD同步若干个异步调用?(如根据若干个url异步加载多张图片,然后在都下载完成后合成一张整图)

// 创建队列组

dispatch_group_t group = dispatch_group_create();

// 获取全局并发队列

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

// 往队列组中添加耗时操作

dispatch_group_async(group, queue, ^{

  // 执行耗时的异步操作1

});

// 往队列组中添加耗时操作

dispatch_group_async(group, queue, ^{

  // 执行耗时的异步操作2

});

// 当并发队列组中的任务执行完毕后才会执行这里的代码

dispatch_group_notify(group, queue, ^{

  // 如果这里还有基于上面两个任务的结果继续执行一些代码,建议还是放到子线程中,等代码执行完毕后在回到主线程

  // 回到主线程

 dispatch_async(group, dispatch_get_main_queue(), ^{

  // 执行相关代码...

 });

});

dispatch_barrier_async的作用是什么?

dispatch_barrier_async(dispatch_queue_t queue, dispatch_block_t block);

-(void)barrier

{

 dispatch_queue_t queue = dispatch_queue_create("12342234", DISPATCH_QUEUE_CONCURRENT);

 dispatch_async(queue, ^{

 NSLog(@"----1-----%@", [NSThread currentThread]);

 });

 dispatch_async(queue, ^{

 NSLog(@"----2-----%@", [NSThread currentThread]);

 });

  // 在它前面的任务执行结束后它才执行,在它后面的任务等它执行完成后才会执行

 dispatch_barrier_async(queue, ^{

 NSLog(@"----barrier-----%@", [NSThread currentThread]);

 });

 dispatch_async(queue, ^{

 NSLog(@"----3-----%@", [NSThread currentThread]);

 });

 dispatch_async(queue, ^{

 NSLog(@"----4-----%@", [NSThread currentThread]);

 });

}

以下代码运行结果如何?

- (void)viewDidLoad

{

 [super viewDidLoad];

 NSLog(@"1");

 dispatch_sync(dispatch_get_main_queue(), ^{

 NSLog(@"2");

 });

 NSLog(@"3");

}

*   答案:主线程死锁
上一篇 下一篇

猜你喜欢

热点阅读