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的子控件赋值
网友评论