面试题集锦2(更新)

1.xcode5和xcode7区别

  • 1.xcode7没有Frameworks文件夹,xcode7内部会自动帮你导入一些常见的框架.
  • 2.xcode7多了LaunchScreen.xib,LaunchScreen.xib设置启动界面,而且可以确定模拟器或者真机的真实尺寸,如果没有设置,默认4s的尺寸(320,480)
  • 3.xcode7没有pch文件
  • 4.xcode5当中也有info.plist,只不过它的名字很长.是工程的名称.

2.pch文件原理

  • 会把pch里面的所有内容导入到每个文件中去

3.UIApplication常见功能

  • 1.设置应用提醒数字
  • 2.设置连网状态
  • 3.设置状态栏
  • 4.跳转网页

4.程序完整启动流程

  • 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文件,如果没有,那么应用程序加载完毕.

5.UIWindow是什么?

  • UIWindow是一种特殊的UIView,通常在一个app中至少有一个UIWindow
  • iOS程序启动完毕后,创建的第一个视图控件就是UIWindow,接着创建控制器的view,
  • 最后将控制器的view添加到UIWindow上,于是控制器的view就显示在屏幕上了
  • 一个iOS程序之所以能显示到屏幕上,完全是因为它有UIWindow

6.手动创建窗口的步骤

  • 1.创建窗口,要有窗口显示,必须要有强引用.窗口也是控件,要想展示出来.必须得要有尺寸.
  • 2.创建控制器
  • 3.设置控制器为窗口的根控制器
  • 4.显示窗口

7.makeKeyAndVisable做了哪些事情?

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

8.如何从storyboard中加载控制器?

  • 1.加载指定的storyBoard
  • 2.加载箭头所指向的控制器.
  • 3.加载指定标识的控制器.

9.initWithNibName的加载过程?

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

10.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方法

11.UIPickerView是什么控件?基本用法是怎样的?

  • UIPickerView是选择控件,用来供用户选择一些城市等,他的基本用法与tableView基本相似,需要设置数据源和代理,让其展示数据

12.KVC底层实现?

  • 拿字符串与当前类的属性进行匹配,如果匹配到,就给该属性赋值
  • [item setValue:forKeyPath:key]
  • 1.会找有没有跟key值相同名称的set方法,就会调用set方法,把obj传入
  • 2.如果说没有set方法,那么它会去找有没有相同名称,并且带有下划线的成员属性,如果有就会给该属性赋值
  • 3.如果也没有带下划线的成员属性,就看有没有跟它相同名称的成员属性,如果有就会给该属性赋值
  • 4.如果还没有跟它相同名称的成员属性,就会调用setVale:forUndefineKey:
  • 5.如果没有实现setValue:forUndefinedKey:就会直接报错

13.导航控制器的view的结构是怎样的?

  • 导航条,导航条的高度为44,y为20
  • 专门存放栈顶控制器view的view

14.导航控制器push做了哪些事情?

  • 当调用push方法的时候,会把要push的控制器从栈里面移除
  • 把之前导航控制器中栈顶控制器的view给移除,把当前栈顶控制器的view添加上去

15.导航控制器pop做了哪些事情?

  • 当调用pop方法时, 会把要pop的控制器从栈里移除
  • 把之前导航控制器中栈顶控制器View给移除,把当前栈顶控制器添加上去.
  • popViewController:把当前控制器从栈中移除
  • popToRootViewControllerAnimated:把除了根控制器以外的控制器,全部从栈中移除
  • popToViewController:要返回的控制器必须要在导航控制器的子控制器当中

16.如何设置导航条的内容?

  • 导航条的内容由导航控制器的栈顶控制器的navigationItem决定
  • 设置标题:.title
  • 设置标题视图:.titleView
  • 设置左侧样式:.leftBarButtonItem
  • 自定义view:initWithCustomView
  • 设置图片:initWithImage:

17.导航控制器pop操作有哪些?

  • 返回到上一级
  • 返回到根控制器
  • 返回到指定的控制器

18.文本框如何拦截用户输入?

  • 给指定的文本框,设置代理,遵守协议,实现代理方法,包括是否允许开始编辑,是否允许结束编辑,是否允许改变字符等。

19.如何自定义键盘?

  • 继承自系统的UITextField,自定义一个键盘,设置文本框的inputView属性,把键盘定义成自己想要的view

20.导航控制器的作用?

  • 导航控制器可以通过push/pop操作,实现控制器之间的跳转

21.如何通过storyboard进行控制器之间的跳转?

  • 在storyBoard当中,选中一个视图, 按住Ctrol,拖一根线到指定的控制器,就可以跳转到指定的控制器

22.控制器view的生命周期

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

23.segue自动跳转和手动跳转有什么区别?

  • 自动跳转是通过控件拖到下一个控制器.只要一点击该控件,就会跳转,
    • 一般跳转之不需要做任何事时, 用此跳转方法
  • 手动跳转是通过控制器拖线的方式,跳转到下一个控制器.要给segue绑定标识
    • 需要手动执行方法才能跳转.

24.UIAlertController使用步骤

  • 第一步:创建控制器:UIAlertController
  • 第二步:创建按钮:UIAlertAction
  • 第三步:添加按钮:[alertVC addAction:action];
  • 第四步:显示弹框.(相当于show操作)presentViewController:alertVC

25.数据顺传的步骤

  • 1.要在数据接收控制器当中定义属性
  • 2.获取数据接收控制器
  • 3.给对应的属性进行赋值.

26.代理传递的过程

  • 当一个对象发生某一件事时,想要把自己的东西传给别人.或是通知别人做某事使用代理.
  • 使用场景 上下级之间,通常是它的上一级成为它的代理.
    1.定义协议,在协议方法中,把要传的数据,写成参数
    2.定义代理属性
    3.调用代理方法
    4.设置代理
    5.遵守协议
    6.实现协议方法.

27.如何取消tableView多余的线

  • tableView的footView为一个空白的View.

28.在跳转之前会执行什么方法?

  • prepareForSegue方法
    在执行segue跳转之前会调用,(不论是自动型跳转, 还是手动跳转都会来到这个方法)

29.performSegueWithIdentifier:做了哪些事情?

  • 1.会根据标识到Storyboard当中查找有没有这个标识的segue
  • 2.如果有的话,就会创建一个UIStoryboardSegue对象,
  • 3.把当前的控制器赋值给UIStoryboardSegue对象sourceViewController segue.sourceViewController = self
  • 4.创建UIStoryboardSegue箭头指向的控制器.创建完毕后.把创建的控制器给UIStoryboardSegue对象destinationViewController赋值
  • 5.调用当前控制器的prepareForSegue方法,告诉你线的准备工作已经完成.问你有没有要传递数据给目标控制器.
  • 6.等prepareForSegue执行完毕后,才去做真正的跳转 UIStoryboardSegue对象perform
    [segue perform];
    [segue.sourceViewController.navigationController pushViewController:segue.destinationViewController animated:YES];

30.延迟执行代码方法?

  • GCD的dispatch_after方法

31.ios当中的存储方式有哪些?

  • plist存储

  • preference偏好设置

  • NSKeyedArchive归档

  • SQLLite存储

  • CoreData存储

32.简述ios应用沙盒的概念?

  • 每个ios应用都有自己的应用沙盒(应用沙盒就是文件系统目录),与其他文件系统隔离

  • 应用必须待在自己的沙盒里,其他应用不能访问该沙盒

33.沙盒目录结构

  • Documents:保存应用运行时生成的需要持久化的数据,iTunes同步设备的时候会备份该目录

  • tmp:保存应用运行时所需要的临时数据,使用完毕后再将相应的文件从该目录删除。应用没有运行时,系统也可能会清除该目录下的文件。

  • Library

    • Caches:保存应用运行时生成的需要持久化的数据,iTunes同步设备时不会备份该目录

    • Preference:保存应用的所有偏好设置,ios的setting设置应用会在该目录中查找应用的设置信息

34.如何获取沙盒目录?

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

35.NSUserDefaults的实现是什么存储?一般用来存什么?

  • NSUserDefaults不需要考虑文件名称跟文件的路径
  • NSUserDefaults本质就是plist存储(NSDictionary)
  • 在NSUserDefaults中,key值不能为nil
  • 在NSUserDefaults也不能存放自定义的对象
  • 一般用来存用户的一些偏好,如版本号,密码,账号等

36.归档一般用来保存什么?使用时有哪些注意点?

  • 归档一般用来保存自定义的对象,使用归档的时候,要告诉保存的对象
  • encodeWithCoder:保存该对象的哪些属性
  • initWithCoder:询问你要读取该对象的哪些属性

37.initWithCoder,什么时候调用?与awakeFromNib的区别?

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

38.使用导航控制器有哪些注意点?

  • 凡是在导航控制器下的scrollView都会自动设置一个内边距64
  • 可以使用automaticallyAdjustsScrollViewInsets属性取消内边距
  • 导航条以及导航条里面的控件设置透明度是没有效果的
  • 如果不设置背景图片,会默认设置一张透明的图片
  • 只要是想要设置背景图片,必须得要使用UIBarMetricsDefault样式
  • 同一个导航控制器下,导航条只有一个

39.UITabBarController的基本使用

  • 初始化UITabBarController控制器
  • 设置为窗口的根控制器为UITabBarController
  • 创建对应的子控制器
  • 调用UITabBarController的addChildViewController添加子控制器
  • 默认选中的是第一个添加的子控制器
  • 可以通过tabBar.selectedIndex的属性更改选中的控制器
  • 内部有多少个子控制器,底部tabBar条上就有多少个按钮
  • 每一个子控制器的view都是懒加载

40.如何设置TabBar的内容?

  • UITabBarButton里面显示什么内容,由对应子控制器的tabBarItem属性决定
  • 设置标题
  • vc1.tabBarItem.title = @"标题1";
  • 设置提醒数字
  • vc1.tabBarItem.badgeValue = @"10";
  • 添加子控制器.
  • [tabBar addChildViewController:vc1];

41.事件的传递过程?(掌握)

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

42.一个控件什么情况下不接收事件?

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

43.如何寻找最适合的view?

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

44.事件的响应过程

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

45.如何寻找上一个响应者

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

46.transform带Make与不带Make的区别?

  • 带Make:是相对于最原始的形变,使用情况为只做一次形变操作
  • 不带Make:是相对于上一次的形变,使用情况为多次形变操作

47.如何添加手势

  • 创建手势
  • 添加手势
  • 实现手势方法

48.如何同时支持多个手势

  • 想要同时支持多个手势,要通过代理的方法
  • 设置代理,在实现是否支持允许多个手势的代理方法中,返回YES

49.hitTest:方法的作用以及什么时候调用

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

50.pointInSide方法的作用以及有什么注意点?

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

51.什么是图形上下文?

  • 图形上下文是用来保存用户绘制的内容状态,并决定绘制到哪个地方的.
  • 用户把绘制好的内容先保存到图形上下文,
  • 然后根据选择的图形上下文的不同,绘制的内容显示到地方也不相同,即输出目标也不相同.

52.如何自定义UIView,步骤是什么?

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

53.DrawRect方法作用?什么时候调用?

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

54.setNeedsDisplay方法的作用

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

55.如何画文字?

  • 先创建好要画的文字
  • 使用UIKit提供的方法进行绘制.
  • 方法说明:
    • drawAtPoint:要画到哪个位置
    • withAttributes:文本的样式.
    • [str drawAtPoint:CGPointZero withAttributes:nil];

56.如果画图片?

  • 绘制图片同样开始要先把图片素材导入.
  • AtPoint:参数说明图片要绘制到哪个位置.
  • 通过调用UIKit的方法drawAtPoint:CGPointZero方法进行绘制;
    • drawAtPoint:绘制出来的图图片跟图片的实际尺寸一样大
    • drawInRect:使用这个方法绘制出来的图片尺寸会和传入的rect区域一样大.
  • 平铺图片
    • [image drawAsPatternInRect:rect];

57.如何使用CADisplayLink添加定时器

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

58.什么是上下文状态栈?

  • 上下文状态栈为内存中的一块区域,用来保存上下文当前的状态
  • 我们获取的图层上下文当中其实有两块区域:一个是存放添加的路径,一个是用来保存用户设置的状态
  • 这些状态包括线条的颜色、线宽等
  • 当我们把上下文的内容渲染到view上面的时候
  • 它会自动将设置的所有上下文状态运行到保存的路径上面显示到view上面

59.如何保存和恢复上下文状态

  • 保存
    • CGContextSaveGState(context)
  • 恢复
    • CGContextRestoreGState(context)

60.上下文矩阵操作有哪些?

  • 上下文的矩阵操作,就是上下文当中的路径可以进行一些形变操作

  • 平移CGContextTranslateCTM()

  • 旋转CGContextScaleCTM()

  • 缩放CGContextRotate()

  • 注意相比操作要在添加路径之前进行

61.如何生成一张图片?

  • 开启一个图片上下文.
  • 上下文的大小和原始图片保持一样.以免图片被拉伸缩放.
  • 在上下文的上面添加一个圆形裁剪区域.圆形裁剪区域的半径大小和图片的宽度一样大.
  • 把要裁剪的图片绘制到图片上下文当中.
  • 从上下文当中取出图片.
  • 关闭上下文.

62.如何把图片转成二进制流?

  • 把生成的图片写到桌面上.
  • 桌面都是以流的形式传递数据,所以我们要把图片转成二进流.
    • image:要转的图片
    • compressionQuality:压缩质量,1代表质量最高
    • NSData *data = UIImageJPEGRepresentation(newImage, 1);
    • 原始质量的png图片.
    • NSData *data = UIImagePNGRepresentation(newImage);
    • 把二进流写到桌面.
    • [data writeToFile:@"/Users/gaoxinqiang/Desktop/newImage.png" atomically:YES];

63.如何把一个路径设置为裁剪区域?

  • 利用UIBezierPath设置一个矩形的裁剪区域.
  • 然后把这个路径设置为裁剪区域.
  • 把路径设为裁剪区域的方法为:
    • [path addClip];

64.如何擦除上下文当中的某一个区域?

获取当前的上下文.
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    把UIImageV上的图片渲染到上下文当中. 
    [self.imageV.layer renderInContext: ctx];
    设置擦除区域 
    CGContextClearRect(ctx, rect);

65.如何判断点在不在某个区域当中

判断手指当前点在不在按钮上.
        if (CGRectContainsPoint(btn.frame, point)) { 
            在按钮上.返回当前按钮 
            return btn;
        } 

66.如何把图片保存到系统相册?

  • 调用方法:
  • 参数说明:
    • 第一个参数:要写入到相册的图片.
    • 第二个参数:哪个对象坚听写入完成时的状态.
    • 第三个参数:图片保存完成时调用的方法
UIImageWriteToSavedPhotosAlbum(newImage,self,@selector(image:didFinishSavingWithError: contextInfo:),nil);
注意:图片保存完成时调用的方法必须得是image:didFinishSavingWithError: contextInfo:

67.如何从系统相册当中选择一张照片?

弹出系统相册
    UIImagePickerController *vc = [[UIImagePickerController alloc] init];
    设置照片的来源 
    vc.sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum;
    vc.delegate = self;
    Modal出来系统相册
    [self presentViewController:vc animated:YES completion:nil];
调用代理方法:-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info

68.如何办到一个图片长按的时候闪一下?

  • 先通过一个动画,把图片的alpha值改为0.
  • 在动画完成时, 立马再通过一个动画设置为1.

69.抽取方法的思路?

  • 抽取一个方法时,要做到方法的功能单一性, 不要一个方法里面写过多的业务逻辑, 要方便适合更多场合
  • 相同的代码,写到一个方法当中 ,不同的地方当做参数传入.

70.什么情况下自定义类?

  • 当发现系统的类没有办法瞒足自己要求时, 可以继续系统的类, 在子类当中添加属性自己的类属性.

71.什么是CALayer?

  • CALayer我们又称它叫做层.
  • 在每个UIView内部都有一个layer这样一个属性.
  • UIView之所以能够显示,就是因为它里面有这个一个层,才具有显示的功能.
  • 我们通过操作CALayer对象,可以很方便地调整UIView的一些外观属性.
  • 可以给UIView设置阴影,圆角,边框等等…

72.如何自定义Layer?

  • 自定义CALayer的方式创建UIView的方式非常相似.
CALayer *layer = [CALayer layer];
layer.frame = CGRectMake(50, 50, 100, 100);
layer.backgroundColor = [UIColor redColor].CGColor;
[self.view.layer addSublayer:layer];

73.UIView和CALayer都能够显示东西,该怎么选择?

  • 对比CALayer,UIView多了一个事件处理的功能。也就是说,CALayer不能处理用户的触摸事件,而UIView可以
  • 如果显示出来的东西需要跟用户进行交互的话,用UIView;
  • 如果不需要跟用户进行交互,用UIView或者CALayer都可以
  • CALayer的性能会高一些,因为它少了事件处理的功能,更加轻量级

74.layer的CATransform3D属性是干什么用的?

旋转
x,y,z 分别代表x,y,z轴.
CATransform3DMakeRotation(M_PI, 1, 0, 0);
平移
CATransform3DMakeTranslation(x,y,z)
缩放
CATransform3DMakeScale(x,y,z);
可以通过KVC的方式进行设置属性.
但是CATransform3DMakeRotation它的值,是一个结构体, 所以要把结构转成对象.
NSValue *value = [NSValue valueWithCATransform3D:CATransform3DMakeRotation(M_PI, 1, 0, 0)];
[_imageView.layer setValue:value forKeyPath:@"transform.scale"];

75.position和anchorPoint是CALayer的两个属性,作用?

  • 我们以前修改一个控件的位置都是能过Frame的方式进行修改.
  • 现在利用CALayer的position和anchorPoint属性也能够修改控件的位置.
  • 这两个属性是配合使用的.
    • position:它是用来设置当前的layer在父控件当中的位置的.所以它的坐标原点.以父控件的左上角为(0.0)点.
  • 两者结合使用.想要修改某个控件的位置,我们可以设置它的position点.
  • 设置完毕后.layer身上的anchorPoint会自动定到position所在的位置.

76.什么是隐式动画?

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

77.如何获取当前时间?

  • 创建日历类
    • NSCalendar *calendar = [NSCalendar currentCalendar];
  • 把日历类转换成一个日期组件
  • 日期组件(年,月,日,时,分,秒)
    • component:日期组件有哪些东西组成,他是一个枚举,里面有年月日时分秒
    • fromDate:当前的日期
    • NSDateComponents *cmp = [calendar components:NSCalendarUnitSecond fromDate:[NSDate date]];
  • 我们的秒就是保存在日期组件里面,它里面提供了很多get方法.
    • NSInteger second = cmp.second;

78.ios中所有的旋转和缩放都是绕着哪个点进行的?

  • ios中所有的旋转与缩放都是绕着锚点进行的
  • 只要修改锚点,就会让旋转,与缩放的点发生变化.

79.CoreAnimation的使用步骤

  • 1.初始化一个CAAnimation对象,并设置一些动画相关属性
  • 2.通过调用CALayer的addAnimation:forKey:方法增加CAAnimation对象到CALayer中,这样就能开始执行动画了
  • 3.通过调用CALayer的removeAnimationForKey:方法可以停止CALayer中的动画

80.UIView和核心动画对比?

  • 1.UIView和核心动画区别?
    • 核心动画只能添加到CALayer
    • 核心动画一切都是假象,并不会改变真实的值。
  • 2.什么时候使用UIView的动画?
    • 如果需要与用户交互就使用UIView的动画.
    • 不需要与用户交互可以使用核心动画
  • 3.什么场景使用核心动画最多?
    • 在转场动画中,核心动画的类型比较多
    • 根据一个路径做动画,只能用核心动画(帧动画)
    • 动画组:同时做多个动画

81.如何让按钮成为选中状态?取消按钮的高亮状态?

  • 1.在添加按钮时,给每一个按钮添加选中状态
    • 添加按钮事件的时候要注意,如果按钮添加到UIImageView上的,UIImageView默认是不接收事件的,所以需要手动把UIImageView设置为可接收事件
  • 2.让按钮成为选中状态
    • 在事件处理方法当中,我们要先定义一个成员属性记录上一个按钮的选中状态
    • 先把上一个按钮的选中状态取消选中
    • 把当前点击的按钮设置为选中状态
    • 把当前的按钮赋值给上一个按钮
  • 3.取消按钮的高亮状态
    • 自定义按钮
    • 重写按钮的setHighlighted:方法

82.如何从一张大图当中截取某一部分为图片?

  • 首先要确定裁剪的区域,即每一张图片的宽高
    • 每一张图片的高度,为原始图片的高度
    • 每一张图片的宽度,为整个图片的宽度除以总共需要裁剪的图片的数量。
  • 方法:CGImageCreateWithImageInRect(image,rect)
    • image:为要裁剪的图片(原始图片),它的类型为CGImageRef类型,所以要转成CGImage
    • rect:为裁剪的范围,这时需要确定每一个x的位置
      • 每一个x为当前的角标*要裁剪的宽度
    • 这个方法它会返回一个图片,图片类型为CGImageRef image,所以要在设置背景图片的时候,要把这张图片给转成UIImage
    • 转化的方法:UIImage *image = [UIImage imageWithCGImage:image]

83.如何让一张图片只显示上半部分或者下半部分?

  • 利用CALayer的一个属性 contentsRect = CGRectMake(0,0,1,0.5)

    • contentsRect就是要显示的范围,它的取值范围是0~1
  • 想让上部图片只显示上半部分contentsRect设置CGRectMake(0,0,1,0.5)

  • 下半部分图片只显示下半部分contentsRect设置为CGRectMake(0,0.5,1,0.5)

84.如何设置渐变效果?

  • 我们可以通过CAGradientLayer这个层来创建渐变,这个层我们就称它是一个渐变层。

  • 渐变层也是需要添加到一个层上面才能够显示

  • 渐变层里面有一个colors属性,这个属性就是设置要渐变的颜色,他是一个数组,数组当中要求我们传入CGColorRef类型,所以我们要把颜色转成CGColor,但是转成CGColor后,数组就认识它是一个对象了,就要通过在前面加上一个(id)来告诉编译器是一个对象

  • 设置渐变的方向

    • startPoint
    • endPoint
    • 取值范围0~1
  • 默认方向为上下渐变

    • startPoint = CGPointMake(0,0)
    • endPoint = CGPointMake(0,1)
  • 设置左右渐变

    • startPoint = CGPointMake(0,0)
    • endPoint = CGPointMake(1,0)

85.在手指拖动的过程当中,松开手指时,有一个动画反弹回去的效果是如何做到的?

  • [UIView animateWithDuration:0.8 delay:0 usingSpringWithDamping:0.1 initialSpringVelocity:0
    options:UIViewAnimationOptionCurveLinear
    animations:^{
    动画执行代码
    } completion:^(BOOL finished) {
    动画完成时调用.
    }];

    • Duration:动画的执行时长
    • delay:动画延时时长.
    • Damping:动画的弹性系数,越小,弹簧效果越明显
    • initialSpringVelocity:弹簧初始化速度

86.如何使用复制层?

  • 添加复制层,首先先要让这个层显示出来
  • 复制层必须加到一个层里面才能够复制它的子层
  • 不需要设置它的尺寸,需要设置它的颜色,子层超过父层也能够显示,所以不用设置尺寸
  • CAReplicatorLayer *replicator = [CAReplicatorLayer layer];
  • 将复制层添加到_contententView.layer
    • [_contentsView.layer addSublayer:replicator];

    • instanceCount:表示原来层中的所有子层复制的份数

    • replicator.instanceCount = 2;

    • 在复制层中添加子层
      [replicator addSublayer:layer];

87.如何使用形状图层?

  • 形式为
- (CAShapeLayer *)shape{
   if(_shape == nil){
   //创建形状图层
   CAShapeLayer *shape = [CAShapeLayer layer];
   //设置形状图层的填充颜色
   shape.fillColor = [UIColor redColor].CGColor;
   self.shape = shape;
   //把形状图层添加到当前按钮的父层当中
   [self.superview.layer insertSublayer:shape atIndex:0];
   _shape = shape;
   }
   return _shape;  
}

88.拖动的时候如何让它有一个立体的效果?

  • 立体的效果就是有一种近大远小的感觉.
  • 想要设置立体效果.要修改它的TransForm当中的一个M34值,设置方式为弄一个空的TransFrom3D
  • CATransform3D transform = CATransform3DIdentity;
    • transform.m34 = - 1 / 200.0;
    • 200.0可以理解为,人的眼睛离手机屏幕的垂直距离,近大远小效果越明显
  • transform = CATransform3DRotate(transform, angle, 1, 0, 0);
  • 相对上一次改了m34的形变,再去旋转

89.如何通过layer改变UIView的外观?

  • 默认图层是有阴影的, 只不过,是透明的

    • _RedView.layer.shadowOpacity = 1;
  • 设置阴影的圆角

    • _RedView.layer.shadowRadius =10;
  • 设置阴影的颜色,把UIKit转换成CoreGraphics框架,用.CG开头

    • _RedView.layer.shadowColor = [UIColor blueColor].CGColor;
  • 设置边框

  • 设置图层边框,在图层中使用CoreGraphics的CGColorRef

    • _RedView.layer.borderColor = [UIColor whiteColor].CGColor;
    • _RedView.layer.borderWidth = 2;
  • 设置圆角

  • 图层的圆角半径,圆角半径为宽度的一半, 就是一个圆

    • _RedView.layer.cornerRadius = 50;
  • 操作layer改变UIImageView的外观.

  • 设置图形边框

    • _imageView.layer.borderWidth = 2;
    • _imageView.layer.borderColor = [UIColor whiteColor].CGColor;

90.position和anchorPoint如何使用?

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

91.为什么要自定义类?

  • 当发现系统的类无法满足我们的需求的时候,想要在系统的功能上添加一些自己的功能,这个时候就可以自定义类
    • 新建一个类,继承自系统的类,添加一些属于自己的功能
    • 比如在做画板的时候,自定义了UIBeizierPath
  • 想要让代码的结构更加清晰,便于阅读(做到谁的事情谁管理)

92.自定义tabBar的实现思路

  • 把系统的tabBar移除
  • tabBar中的按钮个数,和按钮显示什么样的图片由外界决定
  • 外界传入一个数组,数组中存放的都是UITabBarItem模型,有多少个模型就创建多少个按钮,并设置内容

93.Block作用?

  • 保存一段代码

94.Block的定义方式?

返回值类型(^Block名称)(参数) = ^(参数){
   保存的代码
}

95.Block如何当做参数传递?

  • 当发现某一块的功能变化的时候,其他地方没有变化,此时,可以把变化的地方利用block的方式,当做参数传入。

96.如何进行解耦?

  • 第一种方式:代理
  • 第二种方式:block

97.如何自定义遮盖?

  • 自定义的遮盖是显示到最外面的,显示到最外面的东西,我们要添加到主窗口上
  • 通过UIApplication的keyWindow拿到应用程序的窗口,把遮盖添加到窗口显示出来

98.如何显示与隐藏pop菜单?

  • 显示pop的方式,提供显示到某一个点的方法,同样是添加到窗口上面,提供隐藏到某一个点的方法
  • 通过动画的方式进行隐藏,隐藏完毕的时候,通过block方式传入,由外界决定做什么事情。

99.如何全局修改导航条的属性?

  • 通过Appearance的方式拿到整个应用程序的导航条
  • 获取指定类下的导航条
    • UINavigationBar * bar = [UINavigationBar appearanceWhenContainedInstancesOfClasses:@[self class]];

100.分类中如何添加属性,应该注意哪些?

  • 分类当中如果要添加属性的话,就必须要实现该属性的set与get方法,如果不写的话,要自动生成get、set方法
  • 在分类中,使用@property不会生成带有下划线的成员属性,只会声明它的set和get方法

101.initialize

  • initialize 当前类或者子类第一次使用的时候调用
  • 如果子类也写了initialize方法,那么会先调用父类的initialize方法,再调用子类的initialize;如果子类没有写initialize,那么会调用两次父类的initialize,可以根据[self class]判断是谁先调用的
    • [self class]和[super class] 是同一个对象
    • super是优先找它父类的方法
  • initialize不只调用一次

102.字符串是用strong还是用copy

  • 理论上应该用copy,但是在实际开发中由于字符串大多是不可变的,所有常用strong修饰

  • 为什么用copy?

    • 外界修改时,不会影响里面的值
  • 为什么声明为copy时不会影响到里面的值?

    • 使用copy时会生成新的内存地址,使用strong的时候,用的是同一个内存地址
  • copy的set方法是怎么写的?

    - (void) setName:(NSString *)name{
    _name = [name copy]
    }   
  • 当使用的是不可变字符串的时候,是不会生成新的内存地址的
  • 如果是不可变的字符串当使用copy的时候,它会多做一次判断,判断是否为可变
  • 在开发当中使用的字符串大多数是不可变的,比如从网络加载的字符串大多是不可变的,plist中的字符串也是不可变的
  • 所以不可变的字符串使用strong性能会好一些。

103.如何通过代码拉伸图片?

//取出背景图片
UIImage *image = self.loginBtn.currentBackgroundImage;
//拉伸图片的中间区域
UIImage * stretchImage = [image stretchImageWithLeftCapWidth:image.size.width *0.5 topCapHeight:image.size.height *0.5]
[self.loginBtn setBackgroundImage:stretchImage forState:UIControlStateNormal]

104.static关键字的作用?

  • 函数(方法)体内,static变量的作用范围为该函数体,该变量的内存只被分配一次,因此其值在下次调用的时候仍维持在上次的值
  • 在模块内的static全局变量可以被模块内所有函数访问,但不能被模块外其他函数访问
  • 在模块内的static函数只可被这一模块内的其他函数调用,这个函数的使用范围被限制在声明它的模块内;
  • 在类中static 成员变量属于属于整个类拥有,对类的所有对象只有一份拷贝
  • 在类中的static成员函数属于整个类所拥有,这个函数不接受指针,因而只能访问类的static成员变量

105.如何全局修改返回按钮?

- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated {
if (self.childViewControllers.count != 0) {
         NSLog(@"非根控制器");
        //设置返回按钮
        viewController.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithImage:[UIImage imageWithOriImageName:@"NavBack"] style:0 target:self action:@selector(back)];
        
        //重写了系统返回,那么系统的侧滑返回功能就会失效
        self.interactivePopGestureRecognizer.delegate = nil;
        
        //当push时隐藏系统底部Tabbar
        viewController.hidesBottomBarWhenPushed = YES;
    }
[super pushViewController:viewController animated:animated];
}

106.如何恢复侧滑返回功能?

  • 侧滑返回是一个手势,重写返回按钮的时候,侧滑返回手势会通过它的代理,不去做任务事情
  • 把系统的侧滑返回手势的代理清空
  • 清空手势代理带来的问题
  • 当是根控制器的时候,还要把侧滑返回的手势代理给设置回去

107.如何添加全屏幕滑动返回?

  • 给导航控制器的view添加拖动手势
  • 让拖动手势的事件调用系统的侧滑返回方法

108.通过scrollView实现无限轮播思路?

1.确定图片的宽度等于scrollViewW
2.设置scollView 的contentSize (3 * W,H)
3.把scollView的offset.x设置为一个W
4.创建两个imageV, centerImageV * reuseImageV
5.设置centerImageV .x = W
6. reuseImageV.x =  maxX(centerImageV .frame)
7.当scorllView滚动时,判断offset.x是否大于2 * W
   立马把offset.x设置为W
交换两个ImageView的位置
8.交换两个指针

109.UICollectionViewController使用的注意点?

  • 创建CollectionViewController必须得要初始化一个布局参数
  • UICollectionViewCell必须得要自己手动去注册
  • UICollectionViewCell默认内部并没有子控件,需要我们手动的去添加,自定义cell

110.流水布局属性有哪些?

 //流水布局
    UICollectionViewFlowLayout *flowL = [[UICollectionViewFlowLayout alloc] init];
    //设置每一个格子的大小
    flowL.itemSize = CGSizeMake([UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height);
    //设置最小行间距
    flowL.minimumLineSpacing = 0;
    //设置每个格子之间的间距
    flowL.minimumInteritemSpacing = 0;
    
    //设置滚动的方向
    flowL.scrollDirection = UICollectionViewScrollDirectionHorizontal;

111.initialize方法的作用?

  • 该方法是当前类或者它的子类第一次使用的时候会调用

112.新特性业务逻辑是怎样的?

  • 获取当前软件的版本号
  • 判断当前版本是否与之前的版本相同
  • 相同,跳到程序的主框架
  • 不同,跳到新特性,保存当前的版本号

113.如何切换根控制器?

  • 点击立即体验按钮的时候,跳转到程序的主框架
  • 新特性界面已经不需要出现了,新特性界面现有窗口的根控制器强引用
  • 所以把窗口的根控制器指向程序的主框架,新特性界面就会被释放掉

114.为什么要抽取业务类?

  • 让代码具有更强的扩展性
  • 让代码的结构更加的清晰
  • 减少第三方框架对程序的污染

115.KVO内部实现原理?

  • KVO是基于runtime机制实现的
  • 当某个类的属性对象第一次被观察时,系统就会在运行期动态地创建该类的一个派生类,在这个派生类中重写基类中任何被观察属性的setter 方法。派生类在被重写的setter方法内实现真正的通知机制
  • 如果原类为Person,那么生成的派生类名为NSKVONotifying_Person
  • 每个类对象中都有一个isa指针指向当前类,当一个类对象的第一次被观察,那么系统会偷偷将isa指针指向动态生成的派生类,从而在给被监控属性赋值时执行的是派生类的setter方法
  • 键值观察通知依赖于NSObject 的两个方法: willChangeValueForKey: 和 didChangevlueForKey:;在一个被观察属性发生改变之前, willChangeValueForKey: 一定会被调用,这就 会记录旧的值。而当改变发生后,didChangeValueForKey: 会被调用,继而 observeValueForKey:ofObject:change:context: 也会被调用。

116.如何把一个字符串转成类名?

NSClassFromString(<#NSString * _Nonnull aClassName#>) 通过类型,就可以去创建一个对象.

117.block使用的注意点有哪些?

  • 在使用block前需要对block指针做判断处理
  • 在MRC的编译环境下,block如果作为成员参数要copy一下将栈上的block拷贝到堆上
  • 在block使用之后要对block指针做赋空值处理,如果是MRC的编译环境下,要先release掉block对象,block作为类对象的成员变量,使用block的人有可能用类对象参与block中的运算而产生循环引用
  • 使用方将self或者成员变量加入block之前要先将self变为_weak
  • 在多线程环境下(block中的weakSelf有可能被析构的情况下)需要先将self转为strong指针,避免在运行到某个关键步骤的时候self对象被析构。

118.UITableView优化技巧?

  • 1.正确的使用cell标识,缓存池.(必须讲)
  • 2.提前计算好行高.因为heightForRowAtIndexPath:是调用最频繁的方法,不要在该方法当中使用indexPath获取行返回行高
  • 3.如果cell内容非常多的时候可以在异步线程当中进行绘制.
  • 4.cell的内容来自网络时,一定要异步加载.把请求的结果缓存起来.
  • 5.减小subView的数量.
  • 6.尽量少用或者不用透明图片图层.,渲染系统就认为这个view是完全不透明的,这使得渲染系统优化一些渲染过程和提高性能。
  • 7.尽量少用addSubView给cell添加子控件,可以初始化的时候就添加好.然后通过hidden来控件显示.
  • 8.在Cell中来自网络图片时,UIImageView的图片最好跟来自网络图片一样大.因为压缩图片是非常耗费资源的,其实做的是变形transform操作,每一次的压缩图片都要乘以一个变换矩阵,
  • 9.设置阴影时尽量不要使用offset,使用shadowPath这种方法,这个会比使用offset性能要高, offset会让系统先描述好形状,然后再添加阴影.
  • 10.在View设置Frame时,尽量避免使用小数点.使用取整,或四舍5入

119.如何解决通过drawRect方法进行绘制内存增大问题?

  • 使用CALayer的方式进行绘制

  • CAShapeLayer是一个通过矢量图形而不是bitmap来绘制的图层子类。用CGPath来定义想要绘制的图形,CAShapeLayer会自动渲染。它可以完美替代我们的直接使用Core Graphics绘制layer,对比之下使用CAShapeLayer有以下优点:

  • 渲染快速。CAShapeLayer 使用了硬件加速,绘制同一图形会比用 Core Graphics 快很多。

  • 高效使用内存。一个 CAShapeLayer 不需要像普通 CALayer 一样创建一个寄宿图形,所以无论有多大,都不会占用太多的内存。

  • 不会被图层边界剪裁掉。

  • 不会出现像素化。

120.如何高性能的给UIImageView加一个圆角?

  • 不好的解决方案是使用layer,使用layer的方式会强制Core Animation提前渲染屏幕的离屏绘制, 而离屏绘制就会给性能带来负面影响,会有卡顿的现象出现
  • 正确的解决方案:使用绘图技术
  • 还有一种方案:使用了贝塞尔曲线"切割"个这个图片, 给UIImageView 添加了的圆角,其实也是通过绘图技术来实现的

121.block和weak修饰符的区别?

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

122.如何封装一个view?

  • 可以通过纯代码或者xib的方式来封装子控件
  • 建立一个跟view相关的模型,然后将模型数据传给view,通过模型上的数据给view的子控件赋值

你可能感兴趣的:(面试题集锦2(更新))