2018年杭州面试总结

经过了20天的左右的面试,现在总结一下面试的经验以及不足。

一.面试经验总结

1.总体来说是面试有25家,+10家(第二次找工作,有笔试也有机试)

只面人事3家

比较不靠谱的有3家

笔试的有6家

其余的是面试

另外值得关注的是有2家是用swift开发,另外5,5s,se 的机型适配有一部分公司并不看重!

2.自己对自己的定位不是很准,另外就是要准备一下面试题。

不能停留在对这题的印象层面,要理解,不能说不清楚,一知半解不行。

最重要的是面试要有自信,要让面试官觉得你可以完成公司的任务,简历黑白的就可以了。

二.面试题总结

1.控制器的生命周期

 init - loadView - viewDidLoad - viewWillApper - viewDidApper - viewWillDissapper

- viewDidDisapper - viewWillUnload - viewDidUnload - dealloc

2. MVC 和MVVM的理解

MVC 逻辑,视图,数据模型 进行分层解耦.

MVVM model -View- viewmode    视图 视图模型 模型 低耦合 可重用性 可测试性

3.代理使用什么修饰 block用什么修饰

代理使用weak 修饰  block 用copy修饰

4. copy和 strong的理解及使用

copy 不可变类型

strong 可变类型

5.RunLoop 里有几个 Mode 举例说明

kCFRunLoopDefaultMode 和 UITrackingRunLoopMode

和NSRunLoopCommonModes

eg:NSTimerNSTimermain runloopmodeUIself.timer = [NSTimer timerWithTimeInterval:1 target:self selector:@selector(showTime) userInfo:nil repeats:YES];

[[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];

eg:  运用UIScrollView,pageControl与NSTimer对轮播图进行了封装,并将响应事件加入到RunLoop的CommonModes中;

6.本地持久化,怎么使用

沙盒

plist文件(属性列表)

preference(偏好设置)

NSKeyedArchiver(归档)

SQLite 3

CoreData

7. get请求与post请求的区别

1.get是向服务器发索取数据的一种请求,而post是向服务器提交数据的一种请求

2.get没有请求体,post有请求体

3.get请求的数据会暴露在地址栏中,而post请求不会,所以post请求的安全性比get请求号

4.get请求对url长度有限制,而post请求对url长度理论上是不会收限制的,但是实际上各个服务器会规定对post提交数据大小进行限制

8.#import跟 #include 有什么区别,@class呢,#import<> 跟 #import””有什么区别?

1). #import是Objective-C导入头文件的关键字,#include是C/C++导入头文件的关键字,使用#import头文件会自动只导入一次,不会重复导入。

2). @class告诉编译器某个类的声明,当执行时,才去查看类的实现文件,可以解决头文件的相互包含。

3). #import<>用来包含系统的头文件,#import””用来包含用户头文件。

9. 什么情况使用 weak 关键字,相比 assign 有什么不同?

1.在 ARC 中,在有可能出现循环引用的时候,往往要通过让其中一端使用 weak 来解决,比如: delegate 代理属性。

2.自身已经对它进行一次强引用,没有必要再强引用一次,此时也会使用 weak,自定义 IBOutlet 控件属性一般也使用 weak;当然,也可以使用strong。

 

IBOutlet连出来的视图属性为什么可以被设置成weak?

因为父控件的subViews数组已经对它有一个强引用。

 

不同点:

assign 可以用非 OC 对象,而 weak 必须用于 OC 对象。

weak 表明该属性定义了一种“非拥有关系”。在属性所指的对象销毁时,属性值会自动清空(nil)。

10. 怎么用 copy 关键字?

 用途:

 1. NSString、NSArray、NSDictionary 等等经常使用copy关键字,是因为他们有对应的可变类型:NSMutableString、NSMutableArray、NSMutableDictionary;

 2. block 也经常使用 copy 关键字。

 

 说明:

 block 使用 copy 是从 MRC 遗留下来的“传统”,在 MRC 中,方法内部的 block 是在栈区的,使用 copy 可以把它放到堆区.在 ARC 中写不写都行:对于 block 使用 copy 还是 strong 效果是一样的,但写上 copy 也无伤大雅,还能时刻提醒我们:编译器自动对 block 进行了 copy 操作。如果不写 copy ,该类的调用者有可能会忘记或者根本不知道“编译器会自动对 block 进行了 copy 操作”,他们有可能会在调用之前自行拷贝属性值。这种操作多余而低效。

11. 如何对iOS设备进行性能测试?

答: Profile-> Instruments ->Time Profiler

12. 开发项目时你是怎么检查内存泄露?

1). 静态分析 analyze。

2). instruments工具里面有个leak可以动态分析。

13. 如何访问并修改一个类的私有属性?

1). 一种是通过KVC获取。

2). 通过runtime访问并修改私有属性。

14. delegate 和 notification 的区别

1). 二者都用于传递消息,不同之处主要在于一个是一对一的,另一个是一对多的。

2). notification通过维护一个array,实现一对多消息的转发。

3). delegate需要两者之间必须建立联系,不然没法调用代理的方法;notification不需要两者之间有联系。

15. 什么是 RunLoop

从字面上讲就是运行循环,它内部就是do-while循环,在这个循环内部不断地处理各种任务。

一个线程对应一个RunLoop,基本作用就是保持程序的持续运行,处理app中的各种事件。通过runloop,有事运行,没事就休息,可以节省cpu资源,提高程序性能。

 

主线程的run loop默认是启动的。iOS的应用程序里面,程序启动后会有一个如下的main()函数

int main(int argc, char * argv[]) {

@autoreleasepool {

    return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));

}

}

16. 什么是 Runtime  ?Runtime实现的机制是什么,怎么用,一般用于干嘛?

Runtime又叫运行时,是一套底层的C语言API,其为iOS内部的核心之一,我们平时编写的OC代码,底层都是基于它来实现的。

1). 使用时需要导入的头文件 <objc/message.h> <objc/runtime.h>

2). Runtime 运行时机制,它是一套C语言库。

3). 实际上我们编写的所有OC代码,最终都是转成了runtime库的东西。

比如:

类转成了 Runtime 库里面的结构体等数据类型,

方法转成了 Runtime 库里面的C语言函数,

平时调方法都是转成了 objc_msgSend 函数(所以说OC有个消息发送机制)

// OC是动态语言,每个方法在运行时会被动态转为消息发送,即:objc_msgSend(receiver, selector)。

// [stu show];  在objc动态编译时,会被转意为:objc_msgSend(stu, @selector(show));

4). 因此,可以说 Runtime 是OC的底层实现,是OC的幕后执行者。

有了Runtime库,能做什么事情呢?

 Runtime库里面包含了跟类、成员变量、方法相关的API。

 比如:

    (1)获取类里面的所有成员变量。

    (2)为类动态添加成员变量。

    (3)动态改变类的方法实现。

    (4)为类动态添加新的方法等。

 因此,有了Runtime,想怎么改就怎么改。

17. 什么是 Method Swizzle(黑魔法),什么情况下会使用?

1). 在没有一个类的实现源码的情况下,想改变其中一个方法的实现,除了继承它重写、和借助类别重名方法暴力抢先之外,还有更加灵活的方法 Method Swizzle。

2). Method Swizzle 指的是改变一个已存在的选择器对应的实现的过程。OC中方法的调用能够在运行时通过改变,通过改变类的调度表中选择器到最终函数间的映射关系。

3). 在OC中调用一个方法,其实是向一个对象发送消息,查找消息的唯一依据是selector的名字。利用OC的动态特性,可以实现在运行时偷换selector对应的方法实现。

4). 每个类都有一个方法列表,存放着selector的名字和方法实现的映射关系。IMP有点类似函数指针,指向具体的方法实现。

5). 我们可以利用 method_exchangeImplementations 来交换2个方法中的IMP。

6). 我们可以利用 class_replaceMethod 来修改类。

7). 我们可以利用 method_setImplementation 来直接设置某个方法的IMP。

8). 归根结底,都是偷换了selector的IMP。

18. 请简单的介绍下APNS发送系统消息的机制

APNS优势:杜绝了类似安卓那种为了接受通知不停在后台唤醒程序保持长连接的行为,由iOS系统和APNS进行长连接替代。

APNS的原理:

1). 应用在通知中心注册,由iOS系统向APNS请求返回设备令牌(device Token)

2). 应用程序接收到设备令牌并发送给自己的后台服务器

3). 服务器把要推送的内容和设备发送给APNS

4). APNS根据设备令牌找到设备,再由iOS根据APPID把推送内容展示

19. AFNetworking 3.0 如何实现在多个网络请求时,顺序执行?

用GCD信号量

20. GCD编程中串行、并行、同步、异步的执行顺序

串行队列 异步任务,会创建子线程,且只创建一个子线程,异步任务执行是有序的。 

串行队列 同步任务,不创建新线程,同步任务执行是有序的。

并行队列 异步任务 创建子线程,且多个子线程,异步任务打印结果无序。 

(1)同步、异步决定是否创建子线程,同步任务不创建子线程,都是在主线程中执行,异步任务创建子线程。 

(2)串行、并行决定创建子线程的个数,串行创建一个子线程,并行创建多个子线程(具体几个由系统决定)。 

21. iphoneX  导航栏

状态栏高度由20pt变成44pt,留意这个距离就能避开“刘海”的尴尬,相应的导航栏以上变化64->88 

 49->83 tabbar高度

22. 单例模式

单例模式可能是设计模式中最简单的形式了,这一模式的意图就是使得类中的一个对象成为系统中的唯一实例。

它提供了对类的对象所提供的资源的全局访问点。因此需要用一种只允许生成对象类的唯一实例的机制

  • 可以保证的程序运行过程,一个类只有一个示例,而且该实例易于供外界访问
  • 从而方便地控制了实例个数,并节约系统资源。

23. IMP 和 SEL 区别

SEL:类成员的方法指针,不同于C中的函数指针,SEL只是一个编号。 

IMP: 函数指针,指向我们定义的函数

SEL和IMP的关系 

任何继承NSObject的类都会的得到runtime的支持,在类中有一个isa指针,指向该类定义的成员组成的结构体,这个结构体是编译时编译器为(NSObject)类创建的,在这个结构体中包含一个指向父类的指针和一个Dispatch table(分发表),这个Dispatch table 指明了SEL 和 IMP 的对应关系。

24. 你是山西的一个煤老板,你在矿区开采了有3000吨煤需要运送到市场上去卖,从你的矿区到市场有1000公里,你手里有一列烧煤的火车,这个火车最多只能装1000吨煤,且其能耗比较大——每一公里需要耗一吨煤。请问,作为一个懂编程的煤老板的你,你会怎么运送才能运最多的煤到集市?

1. 装1000吨煤,走250公里,扔下500吨煤,回矿山。
2. 装1000吨煤,走到250公里处,拿起250吨煤继续向前到500公里处,扔下500吨煤,回矿山。此时火车上还有250吨,再加上在250公里处还有250吨煤,所以,火车是可以回矿山的。
3. 装上最后1000吨煤,走到500公里处,装上那里的500吨煤,然后一直走到目的。

25. new 和alloc/init 的区别

两种方式创建对象现在基本上一样,区别就是使用new只能默认init进行初始化,alloc方式可以使用其它的init开头的方法进行初始化。

26. 有一口井,深10米,有一只青蛙在井底向上爬,每次爬上5米,又滑下来4米,像这样青蛙需要爬几次方可出井( )

[解析] 在解这类题时,考生不要被题中的枝节所纠缠。青蛙每次爬上5米又滑下4米,实际上就是每次爬上1米,如果因此认为10米花10次就可爬出井口,这就错了,因为青蛙最后一次爬出井口时不会再下滑,因此青蛙只要爬10-5+1=6次就可爬出井口。

27. 手写单例 手写block 

28. 那些情况会循环引用

1 父类与子类

2 block

3 delegate

4 NSTimer

29. 分类,扩展和继承

  1.分类        

          iOS中,当原有类的方法不够用时,这时候分类就出现了。category是在现有类的基础上添加新的方法,利用objective-c 的动态运行时分配机制,可以为现有类添加新方法。可以在分类中添加方法和成员变量,但是添加的成员变量不会自动生成setter和getter方法,需要在实现部分给出实现。

  2.扩展        

          iOS中的extension就是匿名的分类,只有头文件没有实现文件。只能扩展方法,不能添加成员变量。扩展的方法只能在原类中实现。例如你扩展NSString,那么你只能在NSString的.m实现(这是不可能的),所以尽量少用扩展。用分类就可以了。

    3.继承

     学习objective-c语言没有人是不知道继承,继承在面向对象语言是非常重要的。在iOS中继承是单继承,既只能有一个父类。在继承中,子类可以使用父类的方法和变量,当子类想对本类或者父类的变量进行初始化,那么需要重写init()方法 。父类也可以访问子类的方法和成员变量。

 

30. 如何理解面向对象

  面向对象是一种思想,是基于面向过程而言的,就是说面向对象是将功能等通过对象来实现,将功能封装进对象之中,让对象去实现具体的细节;这种思想是将数据作为第一位,而方法或者说是算法作为其次,这是对数据一种优化,操作起来更加的方便,简化了过程。面向对象有三大特征:封装性、继承性、多态性,其中封装性指的是隐藏了对象的属性和实现细节,仅对外提供公共的访问方式,这样就隔离了具体的变化,便于使用,提高了复用性和安全性。对于继承性,就是两种事物间存在着一定的所属关系,那么继承的类就可以从被继承的类中获得一些属性和方法;这就提高了代码的复用性。继承是作为多态的前提的。多态是说父类或接口的引用指向了子类对象,这就提高了程序的扩展性,也就是说只要实现或继承了同一个接口或类,那么就可以使用父类中相应的方法,提高程序扩展性,但是多态有一点不好之处在于:父类引用不能访问子类中的成员。

31.对一些三方控件的实现原理的理解

AFNetworking SDWebImage SDAutolayout MJRefresh等等

其他的问题有的是给你一段代码问你怎么执行或者是否报错或警告!这里略过。

32. 关键字const什么含义?

const int a; int const a; const int *a; int const *a; int * const a; int const * const a;

1> 前两个的作用是一样:a 是一个常整型数
2> 第三、四个意味着a 是一个指向常整型数的指针(整型数是不可修改的,但指针可以)
3> 第五个的意思:a 是一个指向整型数的常指针(指针指向的整型数是可以修改的,但指针是不可修改的)
4> 最后一个意味着:a 是一个指向常整型数的常指针(指针指向的整型数是不可修改的,同时指针也是不可修改的)

33. 线程和进程的区别?

1> 一个应用程序对应一个进程,一个进程帮助程序占据一块存储空间。也有多个进程的应用(比如浏览器,多开几个页面)
2> 要想在进程中执行任务,就必须开启线程,一条线程就代表一个任务
3> 一个进程中允许开启多条线程,也就是同时执行多个任务

34. 堆和栈的区别?

1> 堆空间的内存是动态分配的,一般存放对象,并且需要手动释放内存
2> 栈空间的内存由系统自动分配,一般存放局部变量等,不需要手动管理内存

35. 定义属性时,什么情况使用copyassignretain

1> copy:NSString、Block等类型
2> assign:非OC对象类型,基本数据类型(两个对象相互引用的时候,一端用retain,一端用assign)
3> retain:OC对象类型

36、用NSOpertion NSOpertionQueue 处理A,B,C三个线程,要求执行完A,B后才能执行C,怎么做?

// 创建队列

NSOperationQueue*queue=[[NSOperationQueue alloc] init];

 // 创建3个操作

NSOperation*a= [NSBlockOperationblockOperationWithBlock:^{ NSLog(@”operationA---“); }];

NSOperation*b=[NSBlockOperationblockOperationWithBlock:^{ NSLog(@”operationB---“); }];

NSOperation*c=[NSBlockOperationblockOperationWithBlock:^{ NSLog(@”operationC---“); }];

 // 添加依赖

[c addDependency:a];

[c addDependency:b]; 

// 执行操作

[queue addOperation:a];

[queue addOperation:b];

[queue addOperation:c];

37、列举cocoa中常见对几种多线程的实现,并谈谈多线程安全的几种解决办法及多线程安全怎么控制

1> 只在主线程刷新访问UI
2> 如果要防止资源抢夺,得用synchronized进行加锁保护
3> 如果异步操作要保证线程安全等问题, 尽量使用GCD(有些函数默认
就是安全的)

38、你用过NSOperationQueue么?如果用过或者了解的话,你为什么要使用NSOperationQueue,实现了什么?

请描述它和GCD的区别和类似的地方(提示:可以从两者的实现机制和适用范围来描述)。

1>GCD是纯C语言的API,NSOperationQueue是基于GCD的OC版本封装
2>GCD只支持FIFO的队列,NSOperationQueue可以很方便地调整执行顺
序、设置最大并发数量
3>NSOperationQueue可以在轻松在Operation间设置依赖关系,而GCD
需要写很多的代码才能实现
4>NSOperationQueue支持KVO,可以监测operation是否正在执行
(isExecuted)、是否结束(isFinished),是否取消(isCanceld)
5>GCD的执行速度比NSOperationQueue快
任务之间不太互相依赖:GCD
任务之间有依赖\或者要监听任务的执行情况:NSOperationQueue

39既然提到GCD,那么问一下在使用GCD以及block时要注意些什么?它们两是一回事儿么?blockARC中和传统的MRC中的行为和用法有没有什么区别,需要注意些什么?

Block的使用注意:
1.block的内存管理
2.防止循环retian
· 非ARC(MRC):__block
· ARC:__weak__unsafe_unretained

40SDWebImage内部实现过程

  • 1.入口setImageWithURL:placeholderImage:options: 会先把placeholderImage 显示,然后SDWebImageManager 根据URL 开始处理图片。
  • 2.进入SDWebImageManager-downloadWithURL:delegate:options:userInfo: 交给SDImageCache 从缓存查找图片是否已经下载queryDiskCacheForKey:delegate:userInfo:
  • 3.先从内存图片缓存查找是否有图片,如果内存中已经有图片缓存,SDImageCacheDelegate 回调imageCache:didFindImage:forKey:userInfo: 到SDWebImageManager。
  • 4.SDWebImageManagerDelegate 回调webImageManager:didFinishWithImage: 到UIImageView+WebCache等前端展示图片。
  • 5.如果内存缓存中没有,生成NSInvocationOperation 添加到队列开始从硬盘查找图片是否已经缓存。
  • 6.根据URLKey 在硬盘缓存目录下尝试读取图片文件。这一步是在NSOperation 进行的操作,所以回主线程进行结果回调notifyDelegate: 
  • 7.如果上一操作从硬盘读取到了图片,将图片添加到内存缓存中(如果空闲内存过小,会先清空内存缓存)。SDImageCacheDelegate回调imageCache:didFindImage:forKey:userInfo: 进而回调展示图片。
  • 8.如果从硬盘缓存目录读取不到图片,说明所有缓存都不存在该图片,需要下载图片,回调imageCache:didNotFindImageForKey:userInfo: 
  • 9.共享或重新生成一个下载器 SDWebImageDownloader 开始下载图片。
  • 10.图片下载由NSURLConnection 来做,实现相关delegate 来判断图片下载中、下载完成和下载失败。
  • 11.connection:didReceiveData: 中利用ImageIO 做了按图片下载进度加载效果。
  • 12.connectionDidFinishLoading: 数据下载完成后交给SDWebImageDecoder 做图片解码处理。
  • 13.图片解码处理在一个NSOperationQueue 完成,不会拖慢主线程UI。如果有需要对下载的图片进行二次处理,最好也在这里完成,效率会好很多。
  • 14.在主线程notifyDelegateOnMainThreadWithInfo: 宣告解码完成,imageDecoder:didFinishDecodingImage:userInfo: 回调给SDWebImageDownloader。
  • 15.imageDownloader:didFinishWithImage: 回调给SDWebImageManager 告知图片下载完成。 
  • 16.通知所有的downloadDelegates 下载完成,回调给需要的地方展示图片。
  • 17.将图片保存到SDImageCache 中,内存缓存和硬盘缓存同时保存。写文件到硬盘也在以单独NSInvocationOperation 完成,避免拖慢主线程。
  • 18.SDImageCache 在初始化的时候会注册一些消息通知,在内存警告或退到后台的时候清理内存图片缓存,应用结束的时候清理过期图片。
  • 19.SDWebImage 也提供了UIButton+WebCache 和MKAnnotationView+WebCache,方便使用。
  • 20.SDWebImagePrefetcher 可以预先下载图片,方便后续使用。

41.blockweak修饰符的区别?

__block 不管是ARC 还是MRC 模式下都可以使用,可以修饰对象,也可以修饰基本数据类型
__weak 只能在ARC 模式下使用,只能修饰对象(NSString),不能修饰基本数据类型
__block 修饰的对象可以在block中被重新赋值,中被重新赋值,__weak 修饰的对象不可以

42、怎么用copy 关键字?

NSString、NSArray、NSDictionary 等等经常使用copy 关键字,是因为他们有对应的可变类型:NSMutableString、NSMutableArray、NSMutableDictionary,为确保对象中的属性值不会无意间变动,应该在设置新属性值时拷贝一份,保护其封装性
block 也经常使用copy 关键字
block 使用copy 是从MRC 遗留下来的“传统”,在MRC 中,方法内部的block 是在栈区的,使用copy 可以把它放到堆区.
在ARC 中写不写都行:对于block 使用copy 还是strong 效果是一样的,但是建议写上copy,因为这样显示告知调用者“编译器会自动对block 进行了copy 操作”

43、用@property声明的NSString(或NSArrayNSDictionary)经常使用copy关键字,为什么?如果改用strong关键字,可能造成什么问题?

因为父类指针可以指向子类对象,使用copy 的目的是为了让本对象的属性不受外界影响,使用copy 无论给我传入是一个可变对象还是不可对象,我本身持有的就是一个不可变的副本.如果我们使用是strong,那么这个属性就有可能指向一个可变对象,如果这个可变对象在外部被修改了,那么会影响该属性.

复制详解

浅复制(shallow copy):在浅复制操作时,对于被复制对象的每一层都是指针复制。
深复制(one-level-deepcopy):在深复制操作时,对于被复制对象,至少有一层是深复制。
完全复制(real-deepcopy):在完全复制操作时,对于被复制对象的每一层都是对象复制。
非集合类对象的copy 与mutableCopy [不可变对象copy] // 浅复制
[不可变对象mutableCopy] //深复制
[可变对象copy] //深复制
[可变对象mutableCopy] //深复制

集合类对象的copy 与mutableCopy [不可变对象copy] // 浅复制
[不可变对象mutableCopy] //单层深复制
[可变对象copy] //单层深复制
[可变对象mutableCopy] //单层深复制

这里需要注意的是集合对象的内容复制仅限于对象本身,对象元素仍然是指针复制

44、这个写法会出什么问题:@property(copy) NSMutableArray *array;

因为copy 策略拷贝出来的是一个不可变对象,然而却把它当成可变对象使用,很容易造成程序奔溃。这里还有一个问题,该属性使用了同步锁,会在创建时生成一些额外的代码用于帮助编写多线程程序,这会带来性能问题,通过声明nonatomic 可以节省这些,虽然很小但是不必要额外开销,在iOS开发中应该使用nonatomic替代atomic

45.UIViewCALayer是什么关系?

UIView 显示在屏幕上归功于CALayer,通过调用drawRect 方法来渲染自身的内容,调节CALayer 属性可以调整UIView 的外观,UIView 继承自UIResponder,比起CALayer 可以响应用户事件,Xcode6 之后可以方便的通过视图调试功能查看图层之间的关系。
UIView 是iOS 系统中界面元素的基础,所有的界面元素都继承自它。它内部是由Core Animation 来实现的,它真正的绘图部分,是由一个叫CALayer(Core Animation Layer)的类来管理。UIView 本身,更像是一个CALayer 的管理器,访问它的跟绘图和坐标有关的属性,如frame,bounds 等,实际上内部都是访问它所在CALayer 的相关属性。

 

46、objc 中向一个对象发送消息[obj foo]和objc_msgSend()函数之间有什么关系?

[obj foo];在objc 动态编译时,会被转意为:objc_msgSend(obj,@selector(foo));

 

47.TCP 的三次握手

 

第一次握手:客户端发送syn 包到服务器,并进入syn_send状态,等待服务器进行确认;

第二次握手:服务器收到客户端的syn 包,必须确认客户的SYN,同时自己也发送一个SYN 包,即SYN + ACK 包,此时服务器进入SYN_RECV 状态;

第三次握手:客户收到服务器发送的SYN+ACK 包之后,向服务器发送确认包, 此包发送完毕,客户端和服务器进入ESTABLISHED 状态,完成第三次握手。

48.请简单的介绍下APNS 发送系统消息的机制

应用在通知中心注册,由iOS 系统向APNS 请求返回设备令牌(device Token)
应用程序接收到设备令牌并发送给自己的后台服务器
服务器把要推送的内容和设备发送给APNS

APNS 根据设备令牌找到设备,再由iOS 根据APPID 把推送内容展示

 

49. Swift 中struct 和class 什么区别?举个应用中的实例

struct 是值类型,class 是引用类型。

看过WWDC的人都知道,struct 是苹果推荐的,原因在于它在小数据模型传递和拷贝时比class 要更安全,在多线程和网络请求时尤其好用。

class 为类, struct 为结构体, 类是引用类型, 结构体为值类型, 结构体不可以继承

50. 什么情况使用weak 关键字,相比assign 有什么不同?

1.在ARC 中,在有可能出现循环引用的时候,往往要通过让其中一端使用weak 来解决,比如: delegate 代理属性。

2.自身已经对它进行一次强引用,没有必要再强引用一次,此时也会使用weak,自定义IBOutlet 控件属性一般也使用weak;当然,也可以使用strong。

 

IBOutlet连出来的视图属性为什么可以被设置成weak?

因为父控件的subViews数组已经对它有一个强引用。

 

不同点:

assign 可以用非OC 对象,而weak 必须用于OC 对象。

weak 表明该属性定义了一种“非拥有关系”。在属性所指的对象销毁时,属性值会自动清空(nil)。

51. 如何访问并修改一个类的私有属性?

1). 一种是通过KVC获取。

2). 通过runtime访问并修改私有属性。

52. 手写block  单例代理

void (^ block)() = ^(){ };

block();

@property (nonatomic ,copy) void(^block)();// 回调

单例

.h

@interface UserManager : NSObject

+ (instancetype)manager;

.m

static UserManager *manager = nil;

@implementation UserManager

+ (instancetype)manager{

    static dispatch_once_t onceToken;

    dispatch_once(&onceToken, ^{

        manager = [[UserManager alloc]init];

    });

    return manager;

}

代理

@protocol ShopDelegate <NSObject>

 

- (void)Shop:(NSInteger)count;

@end

@interface ShopView : UIView

@property (nonatomic,weak) id<ShopDelegate> delegate;

 

@end

- (void)shop {

if ([self.delegate respondsToSelector:@selector(Shop:)]) {

            [self.delegate Shop:10];

        }

}

53写出使用GCD方式从子线程回到主线程的方法代码

 

dispatch_sync(dispatch_get_main_queue(), ^{ });

 

54. 分类,扩展和继承

  1.分类        

          iOS中,当原有类的方法不够用时,这时候分类就出现了。category是在现有类的基础上添加新的方法,利用objective-c的动态运行时分配机制,可以为现有类添加新方法。可以在分类中添加方法和成员变量,但是添加的成员变量不会自动生成setter和getter方法,需要在实现部分给出实现。

  2.扩展       

          iOS中的extension就是匿名的分类,只有头文件没有实现文件。只能扩展方法,不能添加成员变量。扩展的方法只能在原类中实现。例如你扩展NSString,那么你只能在NSString的.m实现(这是不可能的),所以尽量少用扩展。用分类就可以了。

    3.继承

     学习objective-c语言没有人是不知道继承,继承在面向对象语言是非常重要的。在iOS中继承是单继承,既只能有一个父类。在继承中,子类可以使用父类的方法和变量,当子类想对本类或者父类的变量进行初始化,那么需要重写init()方法。父类也可以访问子类的方法和成员变量。

55.  线程死锁的情况

- (void)viewDidLoad {

    [super viewDidLoad];

    [self initUI];

   NSLog(@"=================4");

    dispatch_sync(dispatch_get_main_queue(), ^{

       NSLog(@"=================5");

    });

   NSLog(@"=================6");

}

56. 当JSON/Dictionary 中的对象类型与Model 属性不一致时怎么处理

 当JSON/Dictionary 中的对象类型与Model 属性不一致时,YYModel 将会进行自动转换。自动转换不支持的值将会被忽略,以避免各种潜在的崩溃问题。

 

57. __block和__weak修饰符的区别其实是挺明显的: 

1.__block不管是ARC还是MRC模式下都可以使用,可以修饰对象,还可以修饰基本数据类型。 
2.__weak只能在ARC模式下使用,也只能修饰对象(NSString),不能修饰基本数据类型(int)。 
3.__block对象可以在block中被重新赋值,__weak不可以。 
4.__block对象在ARC下可能会导致循环引用,非ARC下会避免循环引用,__weak只在ARC下使用,可以避免循环引用。

 

 58. MVP

MVP模式是MVC模式的一个演化版本(好像所有的模式都是出自于MVC~~),MVP全称Model-View-Presenter。顾名思义,

Model:与MVC中的model没有太大的区别。主要提供数据的存储功能,一般都是用来封装网络获取的json数据的集合。Presenter通过调用Model进行对象交互。

View:这里的View与MVC中的V又有一些小差别,这个View可以是viewcontroller、view等控件。Presenter通过向View传model数据进行交互。

Presenter:作为model和view的中间人,从model层获取数据之后传给view,使得View和model没有耦合。

说了那么多,总得来说MVP的好处就是解除view与model的耦合,使得view或model有更强的复用性

59. iOS开发多线程篇—线程安全

互斥锁使用格式

@synchronized(锁对象) { // 需要锁定的代码  }

注意:锁定1份代码只用1把锁,用多把锁是无效的

所有属性都声明为nonatomic

尽量避免多线程抢夺同一块资源

尽量将加锁、资源抢夺的业务逻辑交给服务器端处理,减小移动客户端的压力

互斥锁的原理:

每一个对象的内部都有一个锁,当有线程要进入的synchronized到代码中会先去检查对象的锁是打开还是关闭状态,默认的是打开的状态,如果线程执行到代码块的内部会先去加锁,如果锁已经关闭了,又有线程要去执行代码块就要先去等待,等锁打开之后才会再去执行。

加锁之后程序执行的效率比不加锁的时候低,因为线程先要等待上一个线程先结束把锁先打开才能再去执行。锁保证了线程同时操作全局变量的安全性。

60. int *a[10],int (*a)[10],int *a[10],int (*a)(int),int (*a[10])(int)

这样的表达式可以遵循这样的规则:从右向左,由近及远,括号优先

int a:一个数值

int *a:一个指针,指向数值

int **a:指向指针的指针

int *a[10] :数组指针。数组a里存放的是10个int型指针

int (*a)[10] :a是指针,指向一个数组。此数组有10个int型元素

int *a[10]先找到声明符a,然后向右看,有[]说明a是个数组,再向左看,是int *,说明数组中的每个元素是int *。所以这是一个存放int指针的数组。int(*a)[10]先找到声明符a,被括号括着,先看括号内的(优先级高),然后向右看,没有,向左看,是*,说明a是个指针,什么指针?在看括号外面的,先向右看,有[] 是个数组,说明a是个指向数组的指针,再向左看,是int,说明数组的每个元素是int。所以,这是一个指向存放int的数组的指针。

例int *p[10];int (*q)[10];printf( "*p[10]: %d\n ", sizeof(p));printf( "(*q)[10]: %d\n ", sizeof(q));结果是:*p[10]: 40 //说明p是一个数组名(*q)[10]: 4 //说明q是一个指针

 

int (*a)(int);表示一个内存空间,这个空间用来存放一个指针,这个指针指向一个函数,这个函数有一个类型为int的参数,并且函数的返回类型也是int。

int (*a[10])(int):从a符号开始。其右边是[10],说明a是个数组,其中存了十个元素。再看a的左边是一个*。说明数组中存的是指针。现在在看(*a[10])的右边是(int);说明所存的指针是指向有一个int形参的函数,现在看(*a[10])的左边是个int ,说明指向的函数的返回值为int 类型

61 场景:两个界面A,B(Apush到B界面)同时需要引用同一个model,并修改.

问题是:在B中如果直接用一个同类型model的属性来接受A界面传过来的Model时,在B界面修改model后,A界面对应的model也会发生变化.

希望达到的目的:A,B对相同数据的model,进行引用修改彼此不影响.

 

解决方案1:实现model拷贝功能,需要model遵循NSCopying协议,主要代码和实验如下:
@interface modelCopy : NSObject<NSCopying> 
 @property (copy, nonatomic) NSString *name; 
 @end  
-   (id)copyWithZone:(NSZone *)zone {  
   modelCopy *model = [[self class] allocWithZone:zone];     model.name = [_name copy];  
   return model;  
   }
 结果如下:可以看出model的地址已经发生变化,当然如果model中嵌套model,则嵌套的model也要对应遵循NSCopying协议以及协议方法 

 

posted @ 2018-03-20 15:29  甘林梦  阅读(469)  评论(0编辑  收藏  举报