1、面试整理-基础相关面试题整理

323 阅读31分钟

1、为什么说OC是一门动态的语言?

  1. 动态和静态是相对的,OC通过runtime运行时机制可以做到纯静态语言做不到的事情:例如动态地增加、删除、替换ivar或者方法等
  2. Objective-C 使用的是“消息结构”并非“函数调用”:使用消息结构的的语言,其运行时所应执行的代码由运行期决定;而使用函数调用的语言,则由编译器决定

2、swift和oc的区别?

  1. 最明显的区别:OC一个类由.h和.m两个文件组成,而swift只有.swift一个文件,所以整体的文件数量比OC有一定减少。
  2. Swift更易于维护,文件分离后结构更清晰。
  3. swift与OC的主要区别就是语法区别,其他大抵相同.

3、属性的默认关键字是什么?

ARC下:

  • 基本数据类型默认关键字是 atomic,readwrite,assign
  • 其他类型默认关键字是 atomic,readwrite,strong MRC下:
  • 基本数据类型默认关键字是 atomic,readwrite,assign
  • 其他类型默认关键字是 atomic,readwrite,retain

4、如何令自己所写的对象具有拷贝功能?

  • 若想让自己所写的对象具有拷贝功能,则需实现 NSCopying 协议。如果自定义的对象分为可变版本与不可变版本,那么就要同时实现 NSCopyingNSMutableCopying 协议。
  • 要注意浅拷贝/深拷贝的不同。

5、可变集合类 和 不可变集合类的 copy 和 mutablecopy有什么区别?如果是集合内容复制的话,集合里面的元素也是内容复制么?

//不可变字符串
NSString *string = @"string";
NSString *cpString1 = [string copy];            //指针拷贝
NSString *mcpString1 = [string mutableCopy];    //内容拷贝,生成可变对象
NSMutableString *mstr = [string mutableCopy];   //同上
NSLog(@"%p %p %p %p",string,cpString1,mcpString1,mstr);
打印结果如下:
0x100001070 0x100001070 0x10051bbc0 0x100600e10

//可变字符串
NSMutableString *mstr1 = [[NSMutableString alloc]initWithString:@"abcde"];
NSMutableString *mstr2 = [mstr1 copy];          //内容拷贝,生成不可变字符串
NSString *cpstring2 = [mstr1 copy];             //同上
NSMutableString *mstr3 = [mstr1 mutableCopy];   //内容拷贝
NSLog(@"%p %p %p %p",mstr1,mstr2, cpstring2,mstr3);
打印结果如下:
0x102063110 0x656463626155 0x656463626155 0x102063160

NS* NSMutable*等集合类的copy、mutableCopy同上述一样,需要注意的是,集合里面的元素并没有内容拷贝!若集合层级很多,且需要完全内容拷贝,可以利用NSKeyedArchiver实现。

6、为什么IBOutlet修饰的UIView也适用weak关键字?

  • 防止(Retain Cycles)
  • 在storyboard或者xib中创建的UIView,本身会被它的superView强引用,以UILable为例子:
    UIViewController -> UIView -> subView -> UILable
    此时控件拖线会默认为weak属性,因为UIlable已经被UIView拥有,当UIViewController释放的时候,UIView释放,UILable才可以释放,所以正常情况下UILable和UIView的生命周期是一样的。设置成strong也没什么大问题, 但是当UILable从其父视图UIView上remove掉,UIViewController对其还有一个strong强引用,UILable无法释放,这时就比较尴尬了...

7、nonatomic和atomic的区别?atomic是绝对的线程安全么?为什么?如果不是,那应该如何实现?

  • nonatomic:表示非原子性,不安全,但是效率高。
  • atomic:表示原子性,安全,但是效率较低。
  • atomic:通过锁定机制来确保其原子性,但只是读/写安全,不能绝对保证线程的安全,当多线程同时访问的时候,会造成线程不安全。可以使用线程锁来保证线程的安全。

8、数据持久化的几个方案(fmdb用没用过)

  • plist文件
  • preference偏好设置
  • NSKeyedArchiver
  • SQLite 3
  • CoreData
  • fmdb
  • realm

9、说一下AppDelegate的几个方法?从后台到前台调用了哪些方法?第一次启动调用了哪些方法?从前台到后台调用了哪些方法?

// 当应用程序启动时(不包括已在后台的情况下转到前台),调用此回调。launchOptions是启动参数,假如用户通过点击push通知启动的应用,这个参数里会存储一些push通知的信息
– (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions NS_AVAILABLE_IOS(3_0);
– (void)applicationDidBecomeActive:(UIApplication *)application;

//应用即将从前台状态转入后台
- (void)applicationWillResignActive:(UIApplication *)application;
– (void)applicationDidEnterBackground:(UIApplication *)application NS_AVAILABLE_IOS(4_0);

//从后台到前台调用了:
– (void)applicationWillEnterForeground:(UIApplication *)application NS_AVAILABLE_IOS(4_0);
– (void)applicationDidBecomeActive:(UIApplication *)application;

10、NSCache优于NSDictionary的几点?

  • NSCache线程安全,在多线程操作时,不需要手动加锁
  • NSCache按照LRU规则,会对超出限制的数据进行自动清除,并且在系统发出低内存通知时,会自动删减缓存
  • NSCache的Key只是对对象的strong引用,对象不需要实现NSCopying协议,NSCache也不会像NSDictionary一样拷贝键。

11、简单的描述下类扩展和分类的区别?

类扩展没有名字,分类有名字
类扩展可以为某个类增加额外的属性、成员变量、方法声明;分类只能扩充方法,不能扩充成员变量,如果在分类中声明了一个属性,分类只会生成这个属性的get\set方法声明

12、简要的说明UIView的frame和bounds的区别?

  • frame表示的是控件矩形框在父控件中的位置和尺寸,是以父控件的左上角为坐标原点.
  • bounds表示的是控件矩形框的位置和尺寸,是以自己的左上角为坐标原点.

13、通过imageNamed:这个方法加载图片有什么特点?

有缓存
UIImage *image =[UIImage imageNamed:@"图片名"]
使用场合:图片比较小、使用频率比较高
建议:把需要缓存的图片放到Images.xcassets

14、instancetype和id的区别

都可以代表任意类型
instancetype只能作为返回值
id类型可以作为返回值,也可以作为参数,也可以定义变量
instancetype会类型检测,id不会进行类型检测

15、通过alloc/init或者alloc/initWithFrame创建控件会不会主动加载xib?

通过alloc/init或者alloc/initWithFrame创建控件不会主动加载xib,即使xib的名称和控件的类名一样

16、通过代码如何设置的内边距?

self.btn.contentEdgeInsets = UIEdgeInsetsMake(30, 30, 0, 0);
self.btn.titleEdgeInsets = UIEdgeInsetsMake(0, -30, 0, 0);
self.btn.imageEdgeInsets = UIEdgeInsetsMake(0, -30, 0, 0);

17、如何处理图片拉伸问题?

创建可拉伸的图片对象
 
bg = [bg resizableImageWithCapInsets:UIEdgeInsetsMake(10,10,10,10) resizingMode:..];//平铺和拉伸
UIImage *bg = ...

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

  • #import是Objective-C导入头文件的关键字,
  • #include是C/C++导入头文件的关键字,
  • 使用#import头文件会自动只导入一次,不会重复导入,相当于#include和#pragma once;
  • @class告诉编译器某个类的声明,当执行时,才去查看类的实现文件,可以解决头文件的相互包含;
  • #import<>用来包含系统的头文件,#import””用来包含用户头文件。

19、属性readwrite,readonly,assin,retain,copy,nonatomic各是什么作用,在哪种情况下用?

  • readwrite是可读可写特性;需要生成getter方法和setter方法时
  • readonly是只读特性只会生成getter方法不会生成setter方法;不希望属性在类外改变
  • assign是赋值特性,setter方法将传入参数赋值给实例变量;仅设置变量时;
  • retain表示持有特性,setter方法将传入参数先保留,再赋值,传入参数的retaincount会+1;
  • copy表示拷贝特性,setter方法将传入对象复制一份;需要完全一份新的变量时。
  • nonatomic非原子操作,决定编译器生成的setter、getter是否是原子操作,atomic表示多线程安全,一般使用nonatomic

20、你的项目什么时候选择使用GCD,什么时候选择NSOperation?

  • 项目中使用NSOperation的优点是NSOperation是对线程的高度抽象,在项目中使用它,会使项目的程序结构更好,子类化NSOperation的设计思路,是具有面向对象的优点(复用、封装),使得实现是多线程支持,而接口简单,建议在复杂项目中使用;
  • 项目中使用GCD的优点是GCD本身非常简单、易用,对于不复杂的多线程操作,会节省代码量,而Block参数的使用,会是代码更为易读,建议在简单项目中使用。

21、简述CALayer和UIView的关系

UIViewCALayer相互依赖的关系。UIView依赖与calayer提供的内容CALayer依赖uivew提供的容器来显示绘制的内容。归根到底CALayer是这一切的基础,如果没有CALayer,UIView自身也不会存在,UIView是一个特殊的CALayer实现,添加了响应事件的能力UIView来自CALayer,高于CALayer,是CALayer高层实现与封装。UIView的所有特性来源于CALayer支持。

22、程序完整启动流程

  • 1.执行Main
  • 2.执行UIApplicationMain函数.
  • 3.创建UIApplication对象,并设置UIApplicationMain对象的代理.
    UIApplication的第三个参数就是UIApplication的名称,如果指定为nil,它会默认为UIApplication.
    UIApplication的第四个参数为UIApplication的代理.
  • 4.开启一个主运行循环.保证应用程序不退出.
  • 5.加载info.plist.加载配置文件.判断一下info.plist文件当中有没有Main storyboard file base name
    里面有没有指定storyboard文件,如果有就去加载info.plist文件,如果没有,那么应用程序加载完毕.

23、makeKeyAndVisable做了哪些事情?

  • 1.让窗口成为显示状态.
  • 2.把根控制器的View添加到窗口上面.
  • 3.把当前窗口设置成应用程序的主窗口

24、initWithNibName的加载过程?

  • 1.如果没有指定名称.指定为nil,那么它就会去先加载跟它相同名称的Xib.
  • 2.如果没有跟它相同名称的Xib,那么它就会再去加载跟它相同名称去点Controller的名字的Xib.
  • 3.控制器的init方法会调用initWithNibName:方法.

25、LoadView作用以及LoadView的注意点?

  • 控制器调用loadView方法创建控制器的view.
    它的默认做法是: - 1.先去判断当前控制器是不是从StoryBoard当中加载的,如果是,那么它就会从StoryBoard当中加载控制器的View. - 2.如果不是从StoryBoard当中加载的, 那么它还会判断是不是从Xib当中创建的控制器.
    如果是,那么它就会从xib加载控制器的View. - 3.如果也不是从Xib加载的控制器.那么它就会创建一个空的UIView.设为当前控制器的View.
  • 注意点:
    • 1.一旦重写了loadView,表示需要自己创建控制器的View.
    • 2.如果控制器的View还没有赋值,就不能调用控制器View的get方法.会造成死循环.
    • 因为控制器View的get方法底层会调用loadView方法

26、控制器view的生命周期

  • loadView:加载view的时候调用
  • viewDidLoad:当控制器View加载完毕时调用
  • viewWillAppear:当控制器View即将显示时调用
  • viewWillLayoutSubviews:当控制器View即将布局子控件时调用
  • viewDidLayoutSubviews:当控制器View布局子控件完毕时调用
  • viewDidAppear:当控制器View显示完毕时调用
  • viewWillDisappear:当控制器View既将消失时调用
  • viewDidDisappear:当控制器View消失完毕时调用
  • viewDidUnload:当控制器View卸载的时候调用

27、沙盒目录结构

  • Documents:保存应用运行时生成的需要持久化的数据,iTunes同步设备的时候会备份该目录
  • tmp:保存应用运行时所需要的临时数据,使用完毕后再将相应的文件从该目录删除。应用没有运行时,系统也可能会清除该目录下的文件。
  • Library
    • Caches:保存应用运行时生成的需要持久化的数据,iTunes同步设备时不会备份该目录
    • Preference:保存应用的所有偏好设置,ios的setting设置应用会在该目录中查找应用的设置信息

28、如何获取沙盒目录?

  • NSDocumentDirectory:查找哪一个文件夹
  • NSUserDomainMask:在什么范围下查找
  • expandTilde:是否展开路径
  • NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES)[0]

29、initWithCoder,什么时候调用?与awakeFromNib的区别?

  • initWithCoder:当开始解析一个文件的时候调用,如果一个view是从xib当中加载,当开始解析xib时会调用这个方法,在调用这个方法的时候,里面的子控件都还没有创建
  • awakeFromNib:当前对象从nib文件当中加载完结时调用,awakeFromNib调用时,说明xib加载完结了,view的大小和里面子控件的尺寸都已经知道了

30、事件的传递过程?

  • 当发生一个触摸事件后,系统会将该事件加入到一个由UIApplication管理的事件队列中
  • UIApplication会从事件队列中取出最前面的事件,交给主窗口
  • 主窗口会在视图层次结构中找到一个最合适的视图来处理触摸事件
  • 触摸事件的传递是从父控件传递到子控件
  • 如果一个父控件不能接收事件,那么它里面的子控件也不能够接收事件

31、一个控件什么情况下不接收事件?

  • 不接收用户交互时不能够处理事件
    • userInteractionEnabled NO
  • 当一个控件隐藏的时候不能够接收事件
    • hidden YES
  • 当一个控件为透明的时候,也不能够接收事件
  • 注意:UIImageView的userInteractionEnabled默认就是NO,因此UIImageView已经它的子控件默认是不能够接收触摸事件的

32、如何寻找最适合的view?

  • 先判断自己是否能够接收触摸事件,如果能再继续往下判断
  • 再判断触摸的当前点在不在自己身上
  • 如果在自己身上,它会从后往前遍历子控件,遍历出每一个子控件后,重复前面的两个步骤
  • 如果没有符合条件的子控件,那么他自己就是最适合的view

33、事件的响应过程

  • 用户点击屏幕后产生的一个触摸事件,经过一系列的传递过程后,会找到最合适的视图控件来处理这个事件
  • 找到最适合的视图控件后,会调用控件的touches方法来做具体的事件处理
  • 这些touches的默认做法是将事件顺着响应者链条向上传递,将事件交给上一个响应者进行处理

34、如何寻找上一个响应者

  • 如果当前view是控制器的view,那么控制器就是上一个响应者
  • 如果当前的view不是控制器的view,那么他的父控件就是上一个响应者
  • 在视图层次结构的最顶级视图,如果也不能处理收到的事件或消息,则其将事件或者消息传递给window对象进行处理
  • 如果window对象也不处理,则其将事件或消息传递给UIApplication对象
  • 如果UIApplication也不能处理该事件或消息,则将其丢弃

35、hitTest:方法的作用以及什么时候调用

  • 作用:寻找最适合的view
  • 参数:当前手指所在的点,产生的事件
  • 返回值:返回谁,谁就是最适合的view
  • 什么时候调用,只要一个事件,传递给一个控件的时候,就会调用这个控件的hitTest方法

36、pointInSide方法的作用以及有什么注意点?

  • 作用:判断point在不在方法调用者上
  • point:必须是方法调用者的坐标系
  • 什么时候调用:hitTest方法底层会调用这个方法,判断点在不在控件上

37、如何自定义UIView,步骤是什么?

  • 首先得要有上下文,有了上下文才能决定把绘制的东西显示到哪个地方去.
  • 其次就是这个上下文必须得和View相关联.才能将内容绘制到View上面.
  • 步骤:
    • 1.要先自定定UIView
    • 2.实现DrawRect方法
    • 3.在DrawRect方法中取得跟View相关联的上下文.
    • 4.绘制路径(描述路径长什么样).
    • 5.把描述好的路径保存到上下文(即:添加路径到上下文)
    • 6.把上下文的内容渲染到View

38、DrawRect方法作用?什么时候调用?

  • DrawRect作用:专用在这个方法当中绘图的.只有在这个方法当中才能取得跟View相关联的上下文.
  • DrawRect是系统自己调用的, 它是当View显示的时候自动调用.

39、setNeedsDisplay方法的作用

  • 当每次调用setNeedsDisplay这个方法,系统就会自动调用drawRect
  • 当我们手动调用drawRect:方法时, 它并不会给我们创建跟VIEW相关联的上下文.
  • 只有系统自动调用drawRect方法的时候才会创建跟View相关联的上下文.
  • setNeedsDisplay底层会调用DrawRect方法重绘.
  • 但是它不是立马就进行重绘.它仅仅是设置了一个重绘标志,等到下一次屏幕刷新的时候才会调用DrawRect方法.

40、如何使用CADisplayLink添加定时器

  • Target:哪个对象要监听方法.
  • selector:监听的方法名称.
  • CADisplayLink *link = [CADisplayLink displayLinkWithTarget:self selector:@selector(setNeedsDisplay)];
  • 想要让CADisplayLink工作,必须得要把它添加到主运行循环.
  • 只要添加到主运行循环, 跟模式没有关系
    • [link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];

41、什么是隐式动画?

  • 根层:UIView内部自动关联着的那个layer我们称它是根层.
  • 非根层:自己手动创建的层,称为非根层.
  • 隐式动画就是当对非根层的部分属性进行修改时, 它会自动的产生一些动画的效果.
  • 我们称这个默认产生的动画为隐式动画.

42、position和anchorPoint如何使用?

这两个属性是配合使用的.

  • position:它是用来设置当前的layer在父控件当中的位置的.
  • 所以它的坐标原点.以父控件的左上角为(0.0)点.
  • anchorPoint:它是决点CALayer身上哪一个点会在position属性所指的位置
  • anchorPoint它是以当前的layer左上角为原点(0.0)
  • 它的取值范围是0~1,它的默认在中间也就是(0.5,0.5)的位置.
  • anchorPoint又称锚点.就是把锚点定到position所指的位置.

43、New 作用是什么?

  1. 向计算机(堆区)申请内存空间;
  2. 给实例变量初始化;
  3. 返回所申请空间的首地址;

44、OC实例变量的修饰符? 及作用范围?

@puplic

1.可以在其他类中访问被@public修饰的成员变量 2.也可以在本类中访问被@public修饰的成员变量 3.可以在子类中访问父类中被@public修饰的成员变量

@private

1.不可可以在其他类中访问被@private修饰的成员变量 2.也可以在本类中访问被@private修饰的成员变量 3.不可以在子类中访问父类中被@private修饰的成员变量

@protected (默认情况下所有的实例变量都是protected)

1.不可可以在其他类中访问被@protected修饰的成员变量 2.也可以在本类中访问被@protected修饰的成员变量 3.可以在子类中访问父类中被@protected修饰的成员变量

@package

介于public和private之间的,如果是在其他包中访问就是private,在当前代码中访问就是public.

45、@proprety的作用

@property = ivar + getter + setter;

  1. 在.h文件中帮我们自动生成getset方法声明
  2. 在.m文件中帮我们生成私有的实例变量(前提是没有在.h文件中没有手动生成)
  3. 在.m文件中帮我们是实现get和set方法的实现
  • 注意:
    在使用@property情况下,可以重写getter和setter方法.需要注意的是, 当把setter和getter方法都实现了之后,实例变量也需要手动添加.

46、NSObject和id的区别?

  • NSObject和id都可以指向任何对象
  • NSObject对象会在编译时进行检查,需要强制类型转换
  • id类型不需要编译时检查,不需要强制类型转换

47、id类型, nil , Nil ,NULL和NSNULL的区别?

  • id类型: 是一个独特的数据类型,可以转换为任何数据类型,id类型的变量可以存放任何数据类型的对象,在内部处理上,这种类型被定义为指向对象的指针,实际上是一个指向这种对象的实例变量的指针; id 声明的对象具有运行时特性,既可以指向任意类型的对象
  • nil 是一个实例对象值;如果我们要把一个对象设置为空的时候,就用nil
  • Nil 是一个类对象的值,如果我们要把一个class的对象设置为空的时候,就用Nil
  • NULL 指向基本数据类型的空指针(C语言的变量的指针为空)
  • NSNull 是一个对象,它用在不能使用nil的场合

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

  • 在 ARC 中,在有可能出现循环引用的时候,往往要通过让其中一端使用 weak 来解决, 比如:delegate 代理属性, 自身已经对它进行一次强引用,没有必要再强引用一次,此时也会使用 weak,自定义 IBOutlet 控件属性一般也使用 weak;当然,也可以使用 strong,但是建议使用 weak

weak 和 assign 的不同点

  • weak 策略在属性所指的对象遭到摧毁时,系统会将 weak 修饰的属性对象的指针指 向 nil,在 OCnil 发消息是不会有什么问题的; 如果使用 assign 策略在属性所指 的对象遭到摧毁时,属性对象指针还指向原来的对象,由于对象已经被销毁,这时候就产生了野指针,如果这时候在给此对象发送消息,很容造成程序奔溃 assigin 可以用于修饰非 OC 对象,而 weak 必须用于 OC 对象

49、NSOperation 相比于 GCD 有哪些优势?

GCD是基于c的底层api,NSOperation属于object-c类。ios 首先引入的是NSOperation,IOS4之后引入了GCD和NSOperationQueue并且其内部是用gcd实现的。 相对于GCD:

  • 1、NSOperation拥有更多的函数可用,具体查看api。
  • 2、在NSOperationQueue中,可以建立各个NSOperation之间的依赖关系。
  • 3、有kvo可以监测operation是否正在执行(isExecuted)、是否结束(isFinished),是否取消(isCanceld)。
  • 4、NSOperationQueue可以方便的管理并发、NSOperation之间的优先级。 GCD主要与block结合使用。代码简洁高效。 GCD也可以实现复杂的多线程应用,主要是建立个个线程时间的依赖关系这类的情况,但是需要自己实现相比NSOperation要复杂。 具体使用哪个,依需求而定。 从个人使用的感觉来看,比较合适的用法是:除了依赖关系尽量使用GCD,因为苹果专门为GCD做了性能上面的优化。

50、直接调用_objc_msgForward函数将会发生什么?

_objc_msgForward是 IMP 类型,用于消息转发的:当向一个对象发送一条消息,但它并没有实现的时候,_objc_msgForward会尝试做消息转发。 直接调用_objc_msgForward是非常危险的事,如果用不好会直接导致程序Crash,但是如果用得好,能做很多非常酷的事。 一旦调用_objc_msgForward,将跳过查找 IMP 的过程,直接触发“消息转发”,如果调用了_objc_msgForward,即使这个对象确实已经实现了这个方法,你也会告诉objc_msgSend:“我没有在这个对象里找到这个方法的实现”

51、block底层实现

block本质是指向一个结构体的一个指针 运行时机制 比较高级的特性 纯C语言 平时写的OC代码 转换成C语言运行时的代码 指令:clang -rewrite-objc main.m(可以打印验证) 默认情况下,任何block都是在栈里面的,随时可能被回收 只要对其做一次copy操作 block的内存就会放在堆里面 不会释放 只有copy才能产生一个新的内存地址 所有地址会发生改变

52、oc中向一个nil对象发送消息会出现问题吗?

不会出现问题,因为objc是动态语言,每个方法在运行时会被动态转为消息发送。即:objc_msgSend(receiver,selector)。objc在向一个对象发送消息时,runtime库会根据对象的isa指针找到该对象实际所属的类,然后在该类中的方法列表以及其父类方法列表中寻找方法运行,然后在发送消息的时候,objc_msgSend方法不会返回值,所谓的返回内容都是具体调用时执行的。 那么,回到本题,如果向一个nil对象发送消息,首先在寻找对象的isa指针时就是0地址返回了,所以不会出现任何错误。

53、自动释放池用过吗?它是什么时候释放?什么情况下对象会被加入到自动释放池,它会加入到哪个自动释放池?

主线程默认开启runloop,同时runloop会自动创建一个autoreleasepool,autorelease对象会自动被加入autoreleasepool中,一次runloop后清空自动释放池。用__autoreleasing修饰符修饰,或类方法创建会自动加入autoreleasepool。它会加入到最近的autoreleasepool中。

54、category的方法能被子类继承吗?它覆盖原有类的方法后,原有类的方法还能调用吗?如果能,你说明理由。

category的方法可以被子类继承。category并不是绝对的覆盖了类的同名方法,而是category的方法排在了类的同名方法之前,方法的检索方式是顺序检索,所以在调用方法时,调用到的同名方法是category,从而产生了覆盖。 利用运行时遍历方法列表,可以调用被category覆盖的方法。

55、Static与const的区别?

const表示只读的意思,只在声明中使用。

static一般有2个作用,规定作用域和存储方法。对于局部变量,static规定其为静态存储区,每次调用的初始值为上一次调用的值,调用结束后存储空间不释放。

对于全局变量,如果以文件划分作用域的话,此变量只在当前文件可见,对于static函数也是在当前模块内函数可见。

56、简述GET请求与POST请求的区别

(1)POST 需要明确制定方法 GET不需要 ,并且默认就是GET方法,并且GET有缓存,POST没有缓存

(2)GET的参数放在URL的后面,并且第一个参数用?拼接,后面的从第二个参数开始,直到最后一个,如果有多个,用&分割;POST 的参数放在请求体里面,并且第一个参数,不用,后面从第二开始,直到最后,如果有多个,用&分割;

(3)GET 一般用于获取数据,POST向服务器提交数据用到

(4)GET的参数是暴漏在地址栏的,不安全;POST的参数隐藏在请求体里面,相对安全一点;

(5)GET请求没有请求体,POST请求有请求体。

(6)GET请求提交数据受浏览器限制,1k,POST请求理论上无限制。

57、@synthesize与@dynamic的区别?

@synthesize:如果你没有手动实现setter方法和getter方法,编译器会自动为帮你生成setter方法和getter方法。

@dynamic:告诉编译器属性的setter和getter方法由用户自己实现,不自动生成。如果一个属性声明为@dynamic var,又没有提供setter和getter方法,编译的时候不会有问题,如果程序中运行到person.name = newName;或newName=person.name时候就会导致程序崩溃。因为”unrecognized selector sent to instance …”这就是动态绑定。

58、@property(copy)NSMutableArray *array;这句代码有什么问题?如果有请简述原因

  • (1)添加、删除、修改数组内的元素的时候,程序会因为找不到对应的方法而崩溃,因为copy就是复制一个不可变的NSArray对象。
  • (2)没有使用nonatomic属性修饰符,默认是 atomic修饰,这样会严重影响性能。

59、对于语句NSString*obj = [[NSData alloc] init]; obj在编译时和运行时分别是什么类型的对象?

编译时是NSString类型对象,运行时时NSData类型对象

首先,声明NSString*testObject是告诉编译器,obj是一个指向某个Objective-C对象的指针,因为不管指向的是什么类型的对象,一个指针所占的内存空间都是固定的,所以这里声明称任何类型的对象,最终生成的可执行代码都是没有区别的。这里限定了NSString只不过是告诉编译器,请把obj当做一个NSString来检查,如果后面调用了非NSString的方法,会产生警告,接着,你创建了一个NSData对象,然后把这个对象所在的内存地址保存在obj里。那么运行时,obj指向的内存空间就是一个NSData对象。你可以把obj当做一个NSData对象来用。

60、Objective-C中id与void*有什么区别?id与instancetype有什么区别?nil、null、NULL三者有什么区别?

Objective-C中id与void*区别:

id是指向OC类对象的指针,它可以声明为任何类对象的指针,当在OC中使用id时,编译器会假定你知道,id指向哪个类的对象。与void不同,void编译器不知道也不假定指向任何类型的指针。

id与instancetype区别:

id返回的是id类型,instancetype返回的是所在类的类型。

相同点是同样都是作为方法的返回类型。

区别:

(1) instancetype可以返回和方法所在类相同类型的对象,id只能返回未知类型的对象。

(2) instancetype只能作为返回值,id可以作为参数。

nil、Nil、NULL三者区别:

nil是一个指向不存在的对象指针(对象空指针)。Nil是指向不存在的类指针(类空指针)。NULL指向其他类型的空指针。NSNull在集合对象中,表示空值的对象。

61、+load和+initialize 的区别是什么?

+initialize:第一次初始化这个类之前被调用,我们用它来初始化静态变量。

+load方法会在加载类的时候就被调用,也就是iOS应用启动的时候,就会加载所有的类。

+initialize方法类似一个懒加载,如果没有使用这个类,系统默认不会去调用这个方法,且默认只加载一次。

如果是在类别中,+load方法会全都执行,但是类别中的load方法会后于类中的方法,+initialize方法会覆盖类中的方法,只执行一个。

+initialize的调用发生在+init方法之前。子类会去调用父类的+initialize方法

62、new和alloc/init的区别

概括来说,new和alloc/init在功能上几乎是一致的,分配内存并完成初始化。
差别在于,采用new的方式只能采用默认的init方法完成初始化。
而采用alloc的方式可以用其他定制的初始化方法。

63、简述内存分区情况

栈区:存放函数的参数值,局部变量的值等。由编译器自动分配释放

堆区:由程序员分配释放。程序员如果不释放,则程序结束时可能由系统回收

全局区:全局变量和静态变量是存储在一块的。初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在另一块区域。程序结束后由系统释放。全局区可分为未初始化全局区:.bbs段和初始化全局区:data段。

常量区:存放常量字符串,程序结束后由系统释放

代码区:存放函数体的二进制代码。

64、从输出url到页面展现到底产生了什么

  • 1、输出地址
  • 2、浏览器查找域名的 IP 地址  
  • 3、浏览器向 web 服务器发送一个 HTTP 申请
  • 4、服务器的永恒重定向响应
  • 5、浏览器跟踪重定向地址
  • 6、服务器解决申请
  • 7、服务器返回一个 HTTP 响应 
  • 8、浏览器显示 HTML
  • 9、浏览器发送申请获取嵌入在 HTML 中的资源(如图片、音频、视频、CSS、JS等等)

65、你在开发过程中罕用到哪些定时器,定时器工夫会有误差吗,如果有,为什么会有误差?

iOS中常NSTimer、CADisplayLink、GCD定时器,其中NSTimer、CADisplayLink基于NSRunLoop实现,故存在误差,GCD定时器只依赖零碎内核,绝对一前两者是比拟准时的

误差起因是:与NSRunLoop机制无关, 因为RunLoop每跑完一次圈再去查看以后累计工夫是否曾经达到定时设置的间隔时间,如果未达到,RunLoop将进入下一轮工作,待工作完结之后再去查看以后累计工夫,而此时的累计工夫可能曾经超过了定时器的间隔时间,故会存在误差。

66、简述ARC的实现原理。它在什么时机插入retain/release?

ARC:自动引用计数。它会在对象创建或者消亡的时候自动插入retain/release。达到自动管理内存的目的。

67、Framework与Library的区别?动态库与静态库的区别?

library与Framework的区别:

在iOS中,Library 仅能包含编译后的代码,即 .a 文件。
但一般来说,一个完整的模块不仅有代码,还可能包含.h 头文修的、.nib 视图文件、图片资源文件、说明文档。(像 UMeng 提供的那些库,集成时,要把一堆的文件拖到Xcode中,配置起来真不是省心的事。
Framework 作为 Cocoa/Cocoa Touch 中使用的一种资源打包方式,可以上述文件等集中打包在一起,方便开发者使用(就像Bundle)。

静态库与动态库的区别:

简单的说,静态链接库是指模块被编译合并到应用中,应用程序本身比较大,但不再需要依赖第三方库。运行多个含有该库的应用时,就会有多个该库的Copy在内存中,冗余。
动态库可以分开发布,在运行时查找并载入到内存,如果有通用的库,可以共用,节省空间和内存。同时库也可以直接单独升级,或作为插件发布。

68、iOS项目中引用多个第三方库引发冲突的解决方法

答:表现为编译报dumplicate symbols错误。
解决方式
一、使用命令将 .a 库中相同的包
二、在编译链接项中添加-dead_strip项

一、使用命令将 .a 库中相同的包

1、创建临时文件夹,用于存放armv7平台解压后的.o文件:mkdir armv7

2、取出armv7平台的包:lipo libx.a -thin armv7 -output armv7/libx-armv7.a

3、查看库中所包含的文件列表:ar -t armv7/libx-armv7.a

4、解压出object file(即.o后缀文件):cd armv7 && ar xv libx-armv7.a

5、找到冲突的包(AFHTTPSessionManager),删除掉rm AFHTTPSessionManager.o

6、重新打包object file:cd .. && ar rcs libx-armv7.a armv7/*.o,可以再次使用[2]中命令确认是否已成功将文件去除

7、将其他几个平台(armv7s, i386, arm64, x86_64)包逐一做上述[1-6]操作

8、重新合并为fat file的.a文件:
lipo -create libx-armv7.a libx-armv7s.a libx-i386.a -output libSDK-new.a

9、拷贝到项目中覆盖源文件:
cp libSDK-new.a /Users/tony/Desktop/XXXProject/Lib/libSDK.a
解决二
二、在编译链接项中添加-dead_strip项
在Build Settings->Other link flags中添加-dead_strip,如果Other link flags中有-all_load与-force_load则删掉,只填-dead_strip

69、GCD实现多读单写

- (void)viewDidLoad {
    [super viewDidLoad];
    
    _syncQueue = dispatch_queue_create("ioQueue", DISPATCH_QUEUE_CONCURRENT);
        for (int i = 0; i < 100; i ++) {
            [self setSomeString:[NSString stringWithFormat:@"%d",i]];
            NSLog(@"someString:%@",[self someString]);
        }
}

-(NSString *)someString {
    
    __block NSString *localSomeString;
    dispatch_sync(_syncQueue, ^{
        sleep(1);
        localSomeString = self.string;
    });
    
    return localSomeString;
}

- (void)setSomeString:(NSString *)someString {
    
    dispatch_barrier_async(_syncQueue, ^{
        sleep(1);
        self.string = someString;
    });
}

70、iOS中内省的几个方法?

答:四个方法,判断类,判断方法

-(BOOL) isKindOfClass:            判断是否是这个类或者这个类的子类的实例
-(BOOL) isMemberOfClass:          判断是否是这个类的实例

-(BOOL) respondsToSelector:           判读实例是否有这样方法
+(BOOL) instancesRespondToSelector:   判断类是否有这个方法

70、能不能简述一下Dealloc的实现机制

答:

  • 当一个对象要释放时,会自动调用dealloc,接下的调用轨迹是
  1. dealloc
  2. _objc_rootDealloc
  3. rootDealloc
  4. object_dispose
  5. objc_destructInstance、free

71、HTTPS和HTTP的区别

  • HTTP:超文本传输协议,明文传输
  • HTTPS:在HTTP基础上增加SSL/TLS加密层,密文传输
  • HTTP端口号为8080,HTTPS端口号为443
  • HTTPS需要证书认证,一般需要申请证书的费用
  • HTTP 页面响应速度比 HTTPS 快,主要是因为 HTTP 使用 TCP 三次握手建立连接,客户端和服务器需要交换 3 个包,而 HTTPS除了 TCP 的三个包,还要加上 ssl 握手需要的 9 个包,所以一共是 12 个包。

72、对称加密和非对称加密的区别?分别有哪些算法的实现?

答:

  1. 对称加密:使用同一个秘钥,非对称加密使用2把密钥加密和解密,即公钥、私钥
  2. 常见的加密方式:
    1. 不可逆
      • 单向散列函数:MD5、SHA
    2. 可逆
      • 对称加密:DES、3DES、AES
      • 非对称加密:RSA
    3. 其他
      • 混合密码系统
      • 数字签名
      • 证书

73、什么是中间人攻击?如何避免?

  • 指攻击者与通讯的两端分别创建独立的联系,并交换其所收到的数据,使通讯的两端认为他们正在通过一个私密的连接与对方直接对话,但事实上整个会话都被攻击者完全控制。
  • 使用HTTPS

74、了解编译的过程么?分为哪几个步骤?

  • 预处理:处理以#开头的命令,删除注释,解开宏定义等
  • 编译:词法分析、语法分析、语义分析、中间代码生成与优化,最终生成汇编代码
  • 汇编:将汇编代码翻译成机器码,生成.o目标文件
  • 链接:将多个.o目标文件和其他函数库链接成可执行文件

75、静态链接了解么?静态库和动态库的区别?

  • 静态链接:将各个模块之间互相引用的部分都处理好,使得各个模块之间能够正确的衔接
  • 区别:静态库在程序链接成可执行文件时就已经链接完成,动态库是在程序启动、运行时才进行链接

76、iOS开发中的加密方式

  • base64加密
  • Token值加密:服务端生成token,客户端保存后每次请求发送token到服务端,用来判断登陆状态。
  • MD5加密--(信息-摘要算法) 哈希算法之一、
  • 时间戳密码以及指纹识、人脸识别
  • keychain保存

77、weak实现原理

  • weak的原理在于底层维护了一张weak_table_t结构的hash表,key是所指对象的地址,value是weak指针的地址数组。
  • weak 关键字的作用是弱引用,所引用对象的计数器不会加1,并在引用对象被释放的时候自动被设置为 nil。
  • 对象释放时,调用clearDeallocating函数根据对象地址获取所有weak指针地址的数组,然后遍历这个数组把其中的数据设为nil,最后把这个entry从weak表中删除,最后清理对象的记录。
  • SideTable、weak_table_t、weak_entry_t这样三个结构,它们之间的关系如下图所示。

738839-3c5a233315895b7b.webp

78、事件传递和响应机制

1. 事件的产生

  • 发生触摸事件后,系统会将该事件加入到一个由UIApplication管理的事件队列中,为什么是队列而不是栈?因为队列的特点是FIFO,即先进先出,先产生的事件先处理才符合常理,所以把事件添加到队列。
  • UIApplication会从事件队列中取出最前面的事件,并将事件分发下去以便处理,通常,先发送事件给应用程序的主窗口(keyWindow)。
  • 主窗口会在视图层次结构中找到一个最合适的视图来处理触摸事件,这也是整个事件处理过程的第一步。
  • 找到合适的视图控件后,就会调用视图控件的touches方法来作具体的事件处理。

2. 事件的传递

  • 触摸事件的传递是从父控件传递到子控件
  • 也就是UIApplication->window->寻找处理事件最合适的view
  • 注 意: 如果父控件不能接受触摸事件,那么子控件就不可能接收到触摸事件