iOS面试总结 - 初级篇

个人博客地址

1,为什么说Object-C 是一门动态语言?

主要设计两个概念: 运行时与多态,即:对象类型,以及调用对象方法是在运行时决定;可以从三个方面描述,如下:

  • 动态类型

    对象类型的确定是在运行期间,

    如:id类型,可以赋不同类型的对象,在运行时决定具体类型;

    如:NSData *test = [[NSString alloc] init],编译时为NSData类型,运行时为NSString类型;

    如:父类指针指向子类对象,编译时为类型为父类,运行时为具体子类(简单工厂模式)

  • 动态绑定

    在运行时决定方法的调用,用于消息发送机制,向某个对象传递消息,就会使用动态绑定机制来决定需要调用的方法;
    objc_msgSend 会根据接收者选择子的类型,在接收者内搜索方法列表,如果找到就响应,本类找不到就沿着继承向上找,最后没有响应会执行消息转发机制;

    如:多态中的子类重写父类方法,在运行时确定确定调用方法;

    如:在.h文件声明方法,在.m不实现方法,让外界调用,编译时不报错,运行时报错;

  • 动态加载

    程序在运行时根据需要在加载可执行的代码和资源;

    如:利用runtime动态添加属性,添加方法,替换方法;

    如:不同机型适配,@2x,@3x资源的加载;

2,说说Object-C内存管理

OC内存管理分为MRC(手动引用计数),ARC(自动引用计数),遵循谁创建,谁释放,谁retain谁release原则;

  • MRC

    需要程序员自己管理内存,使用alloc, copy, retain 使引用计数加一,对应的要使用release引用计数减一,或者autorealease 标记释放;

  • ARC

    由系统自动管理内存,在合适的时间释放已经失去作用的内存空间.

  • 引用计数

    引用计数就是管理对象生命周期的的方式,当我们创建一个新对象的时候,它的引用计数为1,当有一个新的指针指向这个对象时,其引用计数加一,当某个指针不指向这个对象的时候,其引用计数减一,当对象的引用计数变为0时,说明对象不再被任何指针指向了,这时候就可以将对象销毁,回收内存;

3,属性的实质是什么?包括哪几个部分?属性默认的关键字有哪些?@dynamic关键字和@synthesize关键字是
做什么的?

  • 属性的本质

    属性的本质就是: 成员变量+存取方法 即: ivar+setter+getter

  • 属性关键字

    strongassginweakunsafe_unretaindnonatomicatomic, readwritereadonly,等等,各自作用不一一赘述
    注意:循环引用中常使用weak解决, IBOutlet使用weak,因为父空间在可视化操作时已经强引用了
    assign可用于非OC对象,而weak必须用于OC对象,并且对象销毁时,会自动置为nil

  • @dynamic与@synthesize

    使用@dynamic关键字,需要手动添加getter、setter方法,@synthesize自动生成setter、getter方法

4,说说代理,Block,通知

  • delegate

    1,一对一的通讯交互,防止循环引用, 用weak,释放自动置为nil.

    2,需要@protocol 定义协议方法,指定代理,代理对象需要实现协议方法.

    3,更注重过程,类似tableView的代理方法,需要设置行数,设置cell 等,通讯较多推荐delegate

  • Block(闭包)

    1,一对一的通讯交互,防止循环引用,用copy, 栈区拷贝到堆区.

    2,写法简洁,注重结果,如尾随闭包,回调结果,适用于通讯单一.

    3,__block作用:将外部变量的传递形式由值传递,变为指针传递,从而可以获取并修改外部变量的值

  • NotificationCenter

    1,一对多的通讯,通讯对象之间不需要建立关系,发送通知,注册通知,接收通知后,注意移除通知;

    2,代码可读性差.

5,可变集合类 和 不可变集合类的 copy 和 mutablecopy有什么区别

copy返回的都是不可变对象(调用可变对象方法会crash),mutableCopy返回的是可变对象

只有对不可变的对象进行copy,是浅拷贝,其他情况都是深拷贝

  • 浅拷贝

    浅拷贝是指针拷贝,不生成新的指针地址

  • 深拷贝

    深拷贝是内容拷贝,开辟新内存,会生成行的指针地址,修改拷贝对象对原对象没有影响

  • copy 与 mutablecopy

    不可变集合类(NSArray) 进行copy 是浅拷贝,指针复制, 进行mutableCopy是深拷贝

    可变集合类(NSMutableArray) 进行copy,mutableCopy都是深拷贝

6,如何使自己写的对象具有拷贝功能

  • 遵守NSCopying,NSMutableCopying协议

  • 实现协议方法

    - (id)copyWithZone:(NSZone *)zone

    - (id)mutableCopyWithZone:(nullable NSZone *)zone

7,Category,Extension,继承的作用,区别

  • Category

不需要创建子类就能为现有类(系统类,自定义类)添加新方法;

  • 作用

    1,可以将类的实现分散到多个不同的文件中.

    2,创建对私有方法的向前引用(类别中的声明方法未实现,编译器不会产生警告)

    3,向对象添加非正式协议

  • 局限

    1,类别中只能添加方法,不能添加属性,(可以通过runtime添加)

    2,方法名冲突,类别中方法名,与原始类方法名相同时,类别具有更高的优先级,先调用类别方法,覆盖原始类方法

  • Extension

extension是延展,匿名分类,一般用于声明私有属性,成员变量,私有方法.

  • Category的区别

    1,extension可以添加属性,而Categary不可以添加属性(可以通过runtime添加)

    2,extension不能单独存在,必须寄生于类的.m中,即:需要源码,而categary可以单独存在,不需要源码.

    3,extension在编译器决议,它是类的一部分,而categary,是在运行期决议.

  • 继承

继承是面向对象语言的特性,子类可以继承父类的属性与方法,如BaseController

  • 使用条件

    1,当需要扩展的方法与原方法同名时,并且需要调用父类的同名方法,则需要继承。若此时使用分类,则分类的方法的实现 会覆盖原方法的实现,不会访问到原方法。

    2,当需要扩展属性时。

8,Object-C的反射机制

OC的反射机制分为Class反射和SEL反射

  • class反射

    通过类名字符串获取类

    Student *stu = [[NSClassFromString(@"Student") alloc]init]

    将类名,转化成字符串

    NSString *stuString = NSStringFromClass([Student class])

  • SEL反射

    通过方法字符串,实例化方法

    [stu performSelector:NSSelectorFromString(@"setName") withObject:nil]

    将方法变成字符串

    NSStringFromSelector(@selector*(setName:))

9,常见的系统单利类有哪些?如何实现完整的单利?

  • 系统单利类

    1,应用程序实例 [UIApplication sharedApplication]

    2,消息中心 [NSNotificationCenter defaultCenter]

    3,文件管理 [NSFileManager defaultManager]

    4,应用程序设置 [NSUserDefaults standardUserDefaults]

    5,应用程序cookies池 [NSHTTPCookieStorage sharedHTTPCookieStorage]

  • 完整的单利类

    实现了单例的初始化之后,一定要重写三个方法

    +(id) allocWithZone:(struct _NSZone *)zone

    -(id) copyWithZone:(NSZone *)zone

    -(id) mutablecopyWithZone:(NSZone *)zone

10,NSTimer一定准确么?怎么解决

  • 主线程

    NSTimer添加在主线程中,模式是NSDefaultRunLoopMode, 主线程处理所有添加在主线程中的事件,例如UI界面的刷新,复杂的运算,等等,过多主线程事件的处理,导致线程阻塞;当滑动ScrollView的时候,Runlop会将Model切换到TrackingRunLoopMode,这时候的NSTimer事件就不会回调,所以不准

    解决:将NSTimer添加到runloop的特定NSRunLoopCommonModes模式中

    [[NSRunLoop currentRunLoop] addTimer:timer1 forMode:NSRunLoopCommonModes];

  • 子线程

    子线程RunLoop默认关闭,需手动开启,否则定时器不准,

    [[NSRunLoop currentRunLoop] addTimer:_timer forMode:NSDefaultRunLoopMode];
    [[NSRunLoop currentRunLoop] run];
    

    子线程定时器结束的时候,需要干掉,否则会造成资源的浪费

    [_timer invalidate];
    _timer = nil;
    

你可能感兴趣的:(iOS面试总结 - 初级篇)