面试准备——iOS基础知识

iOS基础知识

iOS的内存管理

分为ARC、MRC两种,通过引用计数来控制对象,引用计数为0的时候,释放对象。
new、alloc、copy =1,retain +1,release -1。autorelease pool 是自动释放池,池子里的对象会等到池子释放时候一并释放,只释放计数为0的。

什么情况下会出现内存的循环引用?

循环引用是只相互强引用导致无法释放内存,造成内存泄露。

  1. Timer:timer一般为某个类的成员变量,创建timer的时候需要addTarget,这样timer就强引用了类,timer处于validate状态时,引用计数为1无法释放,若不手动释放,会出现循环引用;p.s.释放要在dealloc之前释放。
  2. block:block一般为某个类的成员变量,创建block的时候会对内部对象强引用,造成循环引用;解决方法为,将block内部的对象weak了再使用。如__weak __typeof(&*self)weakself = self;
  3. delegate:delegate一般为某个类的成员变量,要用weak来修饰,否则容易出现循环引用。

block中的weak self,是任何时候都需要加的么?

在block中用到self时要加。

GCD的queue,main queue中执行的代码,一定是在main thread么?

queue不一定,main queue一定是main thread。

NSOperationQueue有哪些使用方式

  • 添加operation
  • 顺序执行operation(依赖、优先级)
  • 设置并发数
  • 取消所有operation([queue cancel]
  • 阻塞当前线程,等待queue的所有操作执行完毕 ( [queue waitUntilAllOperationsAreFinished])
  • 暂停继续queue

NSThread中的Runloop的作用,如何使用?

  1. 使程序一直运行并接收用户的输入
  2. 决定程序在何时处理哪些事件
  3. 节省CPU时间(当程序启动后,什么都没有执行的话,就不用让CPU来消耗资源来执行,直接进入睡眠状态)
    每个线程(NSThread)对象中内部都有一个run loop(NSRunLoop)对象用来循环处理输入事件,处理的事件包括两类,一是来自Input sources的异步事件,一是来自Timer sources的同步事件;

[1]run Loop在处理输入事件时会产生通知,可以通过Core Foundation向线程中添加run-loop observers来监听特定事件,以在监听的事件发生时做附加的处理工作。 主线程的Run Loop会在App运行时自动运行,子线程中需要手动运行。

Run Loop就是一个处理事件源的循环,你可以控制这个Run Loop运行多久,如果当前没有事件发生,Run Loop会让这个线程进入睡眠状态(避免再浪费CPU时间),如果有事件发生,Run Loop就处理这个事件。

如果子线程进入一个循环需要不断处理一些事件,那么设置一个Run Loop是最好的处理方式,如果需要Timer,那么Run Loop就是必须的。

开发中遇到的需要使用Run Loop的情况有:

  • 需要使用Port或者自定义Input Source与其他线程进行通讯。
  • 子线程中使用了定时器
  • 使用任何performSelector*****到子线程中运行方法
  • 使用子线程去执行周期性任务
  • NSURLConnection在子线程中发起异步请求

NSThread和runloop

.h文件中的变量,外部可以直接访问么?(注意是变量,不是property)

不可以。访问变量需要有getter,直接访问会崩溃。

讲述一下runtime的概念,message send如果寻找不到相应的对象,会如何进行后续处理 ?

  • 类:
struct objc_class {
    Class isa  OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
    Class super_class                       OBJC2_UNAVAILABLE;  // 父类
    const char *name                        OBJC2_UNAVAILABLE;  // 类名
    long version                            OBJC2_UNAVAILABLE;  // 类的版本信息,默认为0
    long info                               OBJC2_UNAVAILABLE;  // 类信息,供运行期使用的一些位标识
    long instance_size                      OBJC2_UNAVAILABLE;  // 该类的实例变量大小
    struct objc_ivar_list *ivars            OBJC2_UNAVAILABLE;  // 该类的成员变量链表
    struct objc_method_list **methodLists   OBJC2_UNAVAILABLE;  // 方法定义的链表
    struct objc_cache *cache                OBJC2_UNAVAILABLE;  // 方法缓存
    struct objc_protocol_list *protocols    OBJC2_UNAVAILABLE;  // 协议链表
#endif
} OBJC2_UNAVAILABLE;
  • 消息机制:
    [receiver message]会转化为objc_msgSend(receiver, selector)

  • 方法调用过程:
    先去缓存中找,没有去方法列表里找,再没有去父类的方法列表里找,如果找到则调用,实在找不到,动态方法解析,最后消息转发。

  • 动态方法解析:
    resolveInstanceMethod:resolveClassMethod:两种。

void dynamicMethodIMP(id self, SEL _cmd) {
    // implementation ....
}
@implementation MyClass
+ (BOOL)resolveInstanceMethod:(SEL)aSEL
{
    if (aSEL == @selector(resolveThisMethodDynamically)) {
          class_addMethod([self class], aSEL, (IMP) dynamicMethodIMP, "v@:");
          return YES;
    }
    return [super resolveInstanceMethod:aSEL];
}
@end
  • 消息转发:
    • 确定消息要发到哪里
    • 将所有的参数一起发过去
- (void)forwardInvocation:(NSInvocation *)anInvocation
{
    if ([someOtherObject respondsToSelector:[anInvocation selector]])
        [anInvocation invokeWithTarget:someOtherObject];
    else
        [super forwardInvocation:anInvocation];
}

[2]


  1. 参考自:https://www.jianshu.com/p/ac9a37567be3 ↩

  2. 参考自:https://blog.tmachc.win/ios-runtime/ ↩

你可能感兴趣的:(面试准备——iOS基础知识)