面试相关总结

基础篇

1.分类和扩展有什么区别?可以分别用来做什么?分类有哪些局限性?分类的结构体里面有哪些成员?

①分类中原则上只能增加方法(能添加属性的的原因只是通过runtime能添加属性的的原因只是通过runtime的objc_setAssociatedObject和objc_getAssociatedObject方法解决无setter/getter的问题而已);
②类扩展不仅可以增加方法,还可以增加实例变量(或者属性),只是该实例变量默认是@private类型的(
用范围只能在自身类,而不是子类或其他地方);
③类扩展中声明的方法没被实现,编译器会报警,但是类别中的方法没被实现编译器是不会有任何警告的。这是因为类扩展是在编译阶段被添加到类中,而类别是在运行时添加到类中。
④类扩展不能像类别那样拥有独立的实现部分(@implementation部分),也就是说,类扩展所声明的方法必须依托对应类的实现部分来实现。
⑤定义在 .m 文件中的类扩展方法为私有的,定义在 .h 文件(头文件)中的类扩展方法为公有的。类扩展是在 .m 文件中声明私有方法的非常好的方式。

最重要的还是类扩展是在编译阶段被添加到类中,而类别是在运行时添加到类中。
分类方法未实现,编译器也不会报警告。
分类方法与原类中相同会优先调用分类。

分类的结构体

typedef struct objc_category *Category;
struct objc_category {
  char *category_name                          OBJC2_UNAVAILABLE; // 分类名
  char *class_name                             OBJC2_UNAVAILABLE; // 分类所属的类名
  struct objc_method_list *instance_methods    OBJC2_UNAVAILABLE; // 实例方法列表
  struct objc_method_list *class_methods       OBJC2_UNAVAILABLE; // 类方法列表
  struct objc_protocol_list *protocols         OBJC2_UNAVAILABLE; // 分类所实现的协议列表
}

**2.nonatomic和atomic的区别?atomic是绝对的线程安全吗?为什么?如果不是,那该如何实现? **

答:区别:nonatomic和atomic用来决定编译器生成的getter和setter操作是否为原子操作;

atomic不是绝对的线程安全。atomic的本意是指属性的存取方法是线程安全的,并不保证整个对象是线程安全的。如:

声明一个NSMutableArray的原子属性stuff,此时self.stuff 和 self.stuff = otherstuff都是线程安全的。但是使用[self.stuff objectAtIndex:index]就不是线程安全的。需要用互斥锁来保证线程安全性。

如何实现线程安全:http://www.cocoachina.com/ios/20160707/16957.html

**3.为什么说Objective-C 是一门动态的语言? **

    动态类型语言是指在运行期间才去做数据类型检查的语言,静态类型语言与动态类型语言刚好相反,它的数据类型是在编译其间检查的,也就是说在写程序时要声明所有变量的数据类型,C/C++是静态类型语言的典型代表。

    Objective-C 是C 的超集,在C 语言的基础上添加了面向对象特性,并且利用Runtime 这个运行时机制,为Objective-C 增添了动态的特性;Objective-C 可以通过Runtime 这个运行时机制,在运行时动态的添加变量、方法、类等,所以说Objective-C 是一门动态的语言;Objective-C 使用的是 “消息结构” 并非 “函数调用”:使用消息结构的的语言,其运行时所应执行的代码由运行期决定;而使用函数调用的语言,则由编译器决定,总结:OC利用Runtime可以在运行的时候创建类,修改类,修改对象调用的方法。

**4.NString为什么要用copy关键字,如果用Strong 会有什么问题? **

答:https://www.jianshu.com/p/fc1408bf4e17

**5.为什么代理要用weak?代理的delegate和dataSource有什么区别?block和代理的区别? **

答:防止循环引用。例如View有一个协议,需要一个代理实现回调。一个Controller添加这个View,并且遵守协议,成为View的代理。如果不用week,用strong,Controller ->View -> delegate -> Controller,就循环引用了。

    delegate偏重于与用户交互的回调,有那些方法可以供我使用,例如UITableviewDelegate;dataSource偏重于数据的回调,view里面有什么东西,属性都是什么,例UITableviewDatasource;

block和代理的区别:https://www.jianshu.com/p/6bba9b4a25d

**6.说一下深拷贝和浅拷贝,怎么让一个对象具备copy功能 **

答:深拷贝就是拷贝出和原来仅仅是值一样,但是内存地址完全不一样的新的对象,创建后和原对象没有任何关系。浅拷贝就是拷贝指向原来对象的指针,使原对象的引用计数+1,可以理解为创建了一个指向原对象的新指针而已,并没有创建一个全新的对象

在OC中要想自定义的类具有拷贝功能(也就是能用copy方法)则类必须遵守NSCopying协议,并且实现协议中的(id)copyWithZone:(NSZone *)zone方

链接:https://www.jianshu.com/p/5135953a8230

**7.runloop 的理解和使用? **

答:https://blog.ibireme.com/2015/05/18/runloop/ 这个介绍的也很可以

**8.objc使用什么机制管理对象内存? **

答:采用retainCount引用计数器管理内存

9.KVO、Delegate、Notification、block 的优缺点及使用场景?

10.谈一下你对RunTime的理解,能否向编译后得到的类中增加实例变量?能否向运行时创建的类中添加实例变量?为什么?

答案

11.Block是如何实现的?Block对应的数据结构是什么样子的?__block的作用是什么?它对应的数据结构又是什么样子的?

block本质是一个对象,底层用struct实现。

数据结构如下:

struct Block_descriptor {
    unsigned long int reserved;
    unsigned long int size;
    void (*copy)(void *dst, void *src);
    void (*dispose)(void *);
};

struct Block_layout {
    void *isa;
    int flags;
    int reserved;
    void (*invoke)(void *, ...);
    struct Block_descriptor *descriptor;
    /* Imported variables. */
};
  • isa 指针,所有对象都有该指针,用于实现对象相关的功能。
  • flags,用于按 bit 位表示一些 block 的附加信息,本文后面介绍 block copy 的实现代码可以看到对该变量的使用。
  • reserved,保留变量。
  • invoke,函数指针,指向具体的 block 实现的函数调用地址。
  • descriptor, 表示该 block 的附加描述信息,主要是 size 大小,以及 copy 和 dispose 函数的指针。
  • variables,capture 过来的变量,block 能够访问它外部的局部变量,就是因为将这些变量(或变量的地址)复制到了结构体中。

__block的作用是让block可以捕获该变量,捕获之后的变量会进入到block内部,通过反编译的代码我们可以看到该对象是这样的

struct __Block_byref_i_0 {
    void *__isa;
    __Block_byref_i_0 *__forwarding;
    int __flags;
    int __size;
    int val; //变量名
};

Swift

1、Swift中struct和class有什么区别?

struct是值引用,更轻量,存放于栈区,class是类型引用,存放于堆区。struct无法继承,class可继承。

2、怎么理解面向协议编程?

面向对象是以对象的视角观察整体结构,万物皆为对象。

面向协议则是用协议的方式组织各个类的关系,Swift底层几乎所有类都构建在协议之上。

面向协议能够解决面向对象的菱形继承,横切关注点和动态派发的安全性等问题。

Sdwebimage

1.把一些具体的事物

1.控件是否有正在加载的任务--存放在SDoperationDictionary 中,读写的时候加了一把递归锁,来保证读写安全

2.针对 GIF,多图下载 判断是否开启 dispath_group

3.设置placeholder, diapatch_main_async_safe 宏

4.加载图片

5.查找缓存

  • 内存缓存(Memory:NSCache),URL——UIImage

    如果URL 不变,图片资源变了,如何处理?-- 设置 If-Modified-Since 和 refreshCache

  • 磁盘缓存:二进制(文件)

    1.是否需要磁盘缓存查询

    2.是否需要对加载的大图做尺寸的处理

    3.判断是同步线程查询还是异步查询,异步查询会在串行队列中,保证同时只有一个磁盘查询任务存在

    4.@autoreleasepool 添加自动缓存池,对用完的临时变量及时回收

    5.拿到缓存的图片,对NSData encod解码成 UIImage,第一个字节拿到图片格式

  • NSURLCache: 系统自带的HTTP 缓存

    • HTTP缓存

    • 不同的缓存策略

      Cache-control

      last-Modified httpResponse.allHeaderFields[@"Last-Modified"] b

      If-Modified-Since- [request setvalue:self.localLastModified forHTTPHeaderField:@"If-Modified-Since"]

6.网络请求 NSURlSession

  • 下载:缓存策略设置

7.图片的解码

8.图片获取之后

  • 根据option 是否需要自动显示图片

SDWebCache--> NCache

特点:线程安全, 可以设置最大个数

1.缓存的对象自身被释放掉了

2.手动掉用removeApi

3.当我们缓存的对象 > countLimit

4.程序进入后台

5.收到系统的内存警告

为什么要看源码?-- 学习知识点

NSURLCache

NSCache

Header

NSOpration

NSURLSession

设计模式1

设计模式2

网络

AFNetwork

你可能感兴趣的:(面试相关总结)