之前看到别人整理的面试题,大概总共有180多题。然后我整理了下,结合自己碰到的情况做了些删减,并对每道题目阐述了一些自己的理解。因为内容过多,所以会分几波发。
-
swift和oc的区别
swift注重安全性,oc注重灵活性。swift有函数式编程,面向对象编程和面向协议编程,而oc几乎只有面向对象编程。swift更注重值类型的数据结构,而oc遵循c语言的老一套,注重指针和索引,swift是==静态类型语言==,而oc==是动态类型语言==。
编译链接
-
synthesize & @dynamic
- synthesize,编译器自动生成setter和getter的方法,在你没有手动去实现这两个方法时。
- dynamic,告诉编译器你会动态生成setter和getter方法,不会要编译器帮你生成。
-
在项目开发中常用的开发工具有哪些?
- xcode
- instruments
- terminal
……
-
UITableView & UICollection
- 都是继承于scrollview
- UICollectionView默认没有表头, UITableView: 有表头和表尾;
- UICollectionView的区里面是项Item, UITableView:区里面是单元格Cell
-
NSProxy & NSObject
- 都实现了<NSObject>协议
- NSProxy代理类,主要做消息转发,模拟多继承,NSProxy这个基类没有定义默认的init方法.
-
传值通知 & 推送通知(本地&远程)
- nsnotifcaiton
- push、apns
第三方库 & 第三方平台
-
NSCache & NSDictionary
- nscache可以设置最大值,主动删除
- nscache线程安全,nsdictionary非线程安全
- NSCache并不会“拷贝”键,而是会“保留”它(NSCache 中的key不必实现copy,NSDictionary中的key必须实现copy)
NSCache中存储的对象也不必实现NSCoding协议,因为毕竟是临时存储,类似于内存缓存,程序退出后就被释放了。
-
UIView的setNeedsDisplay和setNeedsLayout方法
- 首先两个方法都是异步执行的。而setNeedsDisplay会调用自动调用drawRect方法,这样可以拿到 UIGraphicsGetCurrentContext,就可以画画了。而setNeedsLayout会默认调用layoutSubViews,
就可以 处理子视图中的一些数据。
综上所诉,setNeedsDisplay方便绘图,而layoutSubViews方便出来数据。
- 首先两个方法都是异步执行的。而setNeedsDisplay会调用自动调用drawRect方法,这样可以拿到 UIGraphicsGetCurrentContext,就可以画画了。而setNeedsLayout会默认调用layoutSubViews,
-
layoutSubViews & drawRects
1、 layoutSubViews- init初始化不会触发layoutSubviews。
- addSubview会触发layoutSubviews。
- 设置view的Frame会触发layoutSubviews,当然前提是frame的值设置前后发生了变化。
- 滚动一个UIScrollView会触发layoutSubviews。
- 旋转Screen会触发父UIView上的layoutSubviews事件。
- 改变一个UIView大小的时候也会触发父UIView上的layoutSubviews事件。
- 直接调用setLayoutSubviews。
2、 drawRects
-如果在UIView初始化时没有设置rect大小,将直接导致drawRect不被自动调用。drawRect调用是在Controller->loadView, Controller->viewDidLoad 两方法之后掉用的.所以不用担心在控制器中,这些View的drawRect就开始画了.这样可以在控制器中设置一些值给View(如果这些View draw的时候需要用到某些变量值).
- 该方法在调用sizeToFit后被调用,所以可以先调用sizeToFit计算出size。然后系统自动调用drawRect:方法。
- 通过设置contentMode属性值为UIViewContentModeRedraw。那么将在每次设置或更改frame的时候自动调用drawRect:。
- 直接调用setNeedsDisplay,或者setNeedsDisplayInRect:触发drawRect:,但是有个前提条件是rect不能为0。
-
UILayer & UIView
- 每个 UIView 内部都有一个 CALayer 在背后提供内容的绘制和显示,并且 UIView 的尺寸样式都由内部的 Layer 所提供。两者都有树状层级结构,layer 内部有 SubLayers,View 内部有 SubViews.但是 Layer 比 View 多了个AnchorPoint
- 在 View显示的时候,UIView 做为 Layer 的 CALayerDelegate,View 的显示内容由内部的 CALayer 的 display
- CALayer 是默认修改属性支持隐式动画的,在给 UIView 的 Layer 做动画的时候,View 作为 Layer 的代理,Layer 通过 actionForLayer:forKey:向 View请求相应的 action(动画行为)
- layer 内部维护着三分 layer tree,分别是 presentLayer Tree(动画树),modeLayer Tree(模型树), Render Tree (渲染树),在做 iOS动画的时候,我们修改动画的属性,在动画的其实是 Layer 的 presentLayer的属性值,而最终展示在界面上的其实是提供 View的modelLayer
- 两者最明显的区别是 View可以接受并处理事件,而 Layer 不可以
-
UDID & UUID
- UDID是Unique Device Identifier的缩写,中文意思是设备唯一标识.移动设备标示?在很多需要限制一台设备一个账号的应用中经常会用到,在Symbian时代,我们是使用IMEI作为设备的唯一标识的,可惜的是Apple官方不允许开发者获得设备的IMEI。
- UUID是Universally Unique Identifier的缩写,中文意思是通用唯一识别码. 由网上资料显示,UUID是一个软件建构的标准,也是被开源软件基金会(Open Software Foundation,OSF)的组织在分布式计算环境(Distributed Computing Environment,DCE)领域的一部份.UUID的目的,是让分布式系统中的所有元素,都能有唯一的辨识资讯,而不需要透过中央控制端来做辨识资讯的指定.
- UDID :是用来标示设备的唯一性。
- UUID :是用来标示同一个设备上不同应用之间的唯一性。
-
CPU & GPU
- GPU 图形处理器
- CPU 中央处理器
- CPU操作的主要问题是会延迟动画的开始时间,这些操作包括:布局计算(Layout Calculations)、视图懒加载(Lazy View Loading)、Core Graphics绘制(Core Graphics Drawing)、解压图片(Image Decompression)。
- CALayer的属性都是GPU绘制(Draw),包括图层背景、边框颜色、裁剪尺寸等,这些不需要软件层面的绘制。文中提到一些会降低GPU图层绘制的事情包括:太多的几何结构、重绘、离屏绘制、过大的图片。
-
点(pt)& 像素(px)
- px: pixel,像素,屏幕上显示的最小单位。
- pt: point ,点,是一个标准的长度单位,1pt=1/72英寸。
- PPI(DPI):pixel per inch ,像素密度PPI,指每英尺的像素数,表示了清晰度。
-
属性与成员变量
- 属性,自动生成set,get方法,可以用self.调用。有atomic、和noatomic
- 成员变量,只作用于子类中,
-
int和NSInteger的区别
- 在苹果的api实现中,NSInteger是一个封装,它会识别当前操作系统的位数,自动返回最大的类型。
- 用NSInteger,32位系统NSInteger是一个int,即32位,但当时64位系统时,NSInteger便是64位的。
-
类和对象
1、 分类(category)类扩展(extension)协议(Protocol)中哪些可以声明属性?- iOS中协议中和分类中是可以用@property形式声明属性的,只不过在协议、分类中声明的属性,只有对应的setter/getter方法,并没有生成对应的成员变量。因为协议中只可以声明方法,分类中只能声明方法和对应的实现。
- 类扩展可以声明属性
2、 继承和类别的区别
- 继承修改的方法不会对父类原方法产生影响;类别修改的方法相当于替换了原有方法。
- 以viewController举例,继承一个viewController相当于建立一个新的页面;而给一个viewController添加类别用于增加或修改原viewcontroller上的方法。
- 类别支持开发人员针对自己构建的类,把相关的方法分组到多个单独的文件中,对于大型而复杂的类,这有助于提高可维护性,并简化单个源文件的管理。
- 针对系统提供的一些类,例如:NSString,NSArray,NSNumber等类,系统本身不提倡使用继承取拓展方法,因为这些类内部实现对继承有所限制,所以最后使用类别的方法进行拓展。
- 理论上类别不能增加新属性。
3、分类的作用
- 分类是为了扩展系统类的方法而产生的一种方式。
- 分类的作用就是在不修改原有类的基础上,为一个类扩展方法,最主要的是可以给系统类扩展我们自己定义的方法。
- 分类中可以访问原来类的成员变量,但只能访问@protect和@public形式的变量。
- 如果要给分类添加成员变量,则需要写变量的get、set方法,否则添加的成员变量无法被调用。
如果给一个类定义了两个分类,这两个分类中分别实现了同样的一个方法,调用方法时候,这两个方法都会被执行,执行顺序按照编译先后顺序。
4、分类的局限性
- 无法向类中添加新的实例变量,类别没有位置容纳实例变量。
- 名称冲突,即当类别中的方法与原始类方法名称冲突时,类别具有更高的优先级。类别方法将完全取代初始方法从而无法再使用初始方法。
5、 分类category 和 类扩展extension 区别
- extension在编译期决议,它是类的一部分;但是category则完全不一样,它是在运行期决议的
- extension可以添加实例变量,而category是无法添加实例变量的(因为在运行期,对象的内存布局已经确定)。
- extension,所以你无法为系统的类比如NSString添加extension,除非创建子类添加extension。而category不需要有类的源码,我们可以给系统提供的类添加category。
-
NSValue & NSNumber 区别
- NSNumber主要是用来封装ANSI C内置的数据,比如char,float,int等等。
- NSValue主要用来封装自定义的数据结构,可以是系统框架提供的CGRect/CGPoint/CGSize等数据结构,也可以是自己定义的struct。
- NSNumber实际上是NSValue的一个特殊情况,所以在类关系中,NSNumber是NSValue的子类。
-
CFSocket使用有哪几个步骤
- CFSocket是在系统的CFNetwork.framework中,
- 苹果对对底层 BSD Socket 进行轻量级的封装(纯 C)
- 主要使用的 API:CFSocekt 用于建立连接,CFStream 用于读写数据。
-
Core Foundation中提供了哪几种操作Socket的方法?
- CFNetwork(CFStream输入输出流socket通信)
- CFSocket(c语言)
- BSD Socket(C语言底层socket)
-
解析XML文件有哪几种方式?
在iOS开发中,数据解析通常有两种方式,一种是JSON解析,一种是XML解析。XML优点:格式统一;缺点:文件庞大,格式复杂- SAX解析,SAX解析的特点是逐行进行解释
- DOM解析,DOM解析的特点是通过节点解析
- XMLReader解析,XMLReader通过向前读取文档并识别读取到的元素
-
什么是沙盒模型?
iOS中的沙盒机制是一种安全体系。为了保证系统安全,iOS每个应用程序在安装时,会创建属于自己的沙盒文件(存储空间)。应用程序只能访问自身的沙盒文件,不能访问其他应用程序的沙盒文件。
-
在一个对象的方法里面:self.name= “object”;和 name =”object” 有什么不同吗?
- self.name会调用set方法
-
请简要说明viewDidLoad和viewDidUnload何时调用
-
viewDidUnload
ios6之后废弃 -
viewWillAppear
:Called when the view is about to made visible. Default does nothing视图即将可见时调用。默认情况下不执行任何操作 -
viewDidAppear
:Called when the view has been fully transitioned onto the screen. Default does nothing视图已完全过渡到屏幕上时调用 -
viewWillDisappear
:Called when the view is dismissed, covered or otherwise hidden. Default does nothing视图被驳回时调用,覆盖或以其他方式隐藏。默认情况下不执行任何操作 -
viewDidLoad
:Called after the view has been loaded. For view controllers created in code, this is after -loadView. For view controllers unarchived from a nib, this is after the view is set.在视图加载后被调用,如果是在代码中创建的视图加载器,他将会在loadView方法后被调用,如果是从nib视图页面输出,他将会在视图设置好后后被调用。
-
-
创建控制器、视图的方式
-
alloc
创建对象,分配空间 -
init
(initWithNibName
) 初始化对象,初始化数据
-
-
简述内存分区情况
1、 bss段- bss段通常是指用来存放程序中未初始化的全局变量和静态变量的一块内存区域
- 通常来说如果不初始化全局变量和静态变量,编译器也会对它们进行一个隐式初始化(直接赋值就是显示初始化),赋给它们一个缺省值,是我们这里所说的未初始化。
- BSS段在程序执行之前会清0,所以未初始化的全局变量(静态变量)已经是0了。所以这种情况还是存放在BSS段,一旦初始化就会从BSS段中回收掉,转存到data段(数据段)中。
- bss区-Block Started by Symbol(未初始化数据段):并不给该段的数据分配空间,仅仅是记录了数据所需空间的大小。
2、数据段
- 数据段分为只读数据段(常量区) 和 读写数据段
- 通常是指用来存放程序中已经初始化的全局变量和静态变量的一块内存区域。数据段属于静态内存分配,可以分为只读数据段和读写数据段。字符串常量等,是放在只读数据段中,结束程序时才会被收回。
3、代码段
- 通常是指用来存放程序执行代码的一块内存区域。这部分区域的大小在程序运行前就已经确定,并且内存区域通常属于只读, 某些架构也允许代码段为可写,即允许修改程序。在代码段中,也有可能包含一些只读的常数变量,例如字符串常量等,这些常量放在只读数据段(data segment)中,也有叫做常量区的说法。
4、堆
- 堆是用于存放进程运行中被动态分配的内存段,它的大小并不固定,可动态扩张或 缩减。
- 堆向高地址扩展的数据结构,是不连续的内存区域。程序员负责在何时释放内存(如用free或delete),在iOS的ARC程序中,系统自动管理计数器,计数器为0的时候,在当次的runloop结束后,释放掉内存。堆中的所有东西都是匿名的,这样不能按名字访问,而只能通过指针访问。
- 对于堆来讲,频繁的new/delete势必会造成内存空间的不连续性,从而造成大量的碎片 ,使程序效率降低。
5、栈
- 栈又称堆栈, 是用户存放程序临时创建的局部变量,也就是说我们函数括弧“{}” 中定义的变量(但不包括static声明的变量,static意味着在数据段中存放变量)。除此以外, 在函数被调用时,其参数也会被压入发起调用的进程栈中,并且待到调用结束后,函数的返回值 也会被存放回栈中。由于栈的后进先出特点,所以 栈特别方便用来保存/恢复调用现场。从这个意义上讲,我们可以把堆栈看成一个寄存、交换临时数据的内存区。
- 指针都存在栈区,用于指向分配在堆区的内存的地址
-
队列和栈有什么区别
- 队列:先进先出
- 栈:先进后出
- 堆:堆是在程序运行时,而不是在程序编译时,申请某个大小的内存空间。即动态分配内存,对其访问和对一般内存的访问没有区别。{堆是指程序运行是申请的动态内存,而栈只是指一种使用堆的方法(即先进后出)。
-
iOS的系统架构
1、Cocoa Touch(触摸层)为应用程序开发提供了各种常用的框架并且大部分框架与界面有关,本质上来说它负责用户在iOS设备上的触摸交互操作。
2、Media(媒体层)
提供应用中视听方面的技术,如图形图像相关的CoreGraphics、CoreImage、GLKit、OpenGL ES、CoreText、ImageIO等等。声音技术相关的CoreAudio、OpenAL、AVFoundation,视频相关的CoreMedia、Media Player框架,音视频传输的AirPlay框架等等。
3、Core Services(核心服务层)
提供给应用所需要的基础的系统服务。如Accounts账户框架,广告框架,数据存储框架,网络连接框架,地理位置框架,运动框架等等。这些服务中的最核心的是CoreFoundation和Foundation框架,定义了所有应用使用的数据类型。
4、Core OS(核心操作系统层)
包含大多数低级别接近硬件的功能,它所包含的框架常常被其它框架所使用。Accelerate框架包含数字信号,线性代数,图像处理的接口。针对所有的iOS设备硬件之间的差异做优化,保证写一次代码在所有iOS设备上高效运行。CoreBluetooth框架利用蓝牙和外设交互,包括扫描连接蓝牙设备,保存连接状态,断开连接,获取外设的数据或者给外设传输数据等等。Security框架提供管理证书,公钥和私钥信任策略,keychain,hash认证数字签名等等与安全相关的解决方案。
-
控件主要响应3种事件
- 触摸事件
- 加速事件
- 远程控制事件
-
简述视图控件器的生命周期
-
alloc
创建对象,分配空间 -
init
(initWithNibName
)初始化对象、初始化数据 -
loadView
从nib载入视图 ,通常这一步不需要去干涉。除非你没有使用xib文件创建视图 -
viewDidLoad
载入完成,可以进行自定义数据以及动态创建其他控件 -
viewWillAppear
视图将出现在屏幕之前,马上这个视图就会被展现在屏幕上了 -
viewDidAppear
视图已在屏幕上渲染完成 -
viewWillDisappear
视图将被从屏幕上移除之前执行 -
viewDidDisappear
视图已经被从屏幕上移除,用户看不到这个视图了 -
dealloc
视图被销毁,此处需要对你在init和viewDidLoad中创建的对象进行释放
-
-
app 项目的生命周期
1、应用的生命周期appdelegate里面的方法
2、简要说明一下APP的启动过程,main文件说起,main函数中有什么函数?作用是什么?
main()函数中调用了UIApplicationMain()方法,确定执行;
UIApplicationMain主要负责三件事:
1、从给定的类名初始化应用程序对象,也就是初始化UIApplication或者子类对象的一个实例,如果你在这里给定的是nil,那么 系统会默认UIApplication类,也就主要是这个类来控制以及协调应用程序的运行。在后续的工作中,你可以用静态方法sharedApplication 来获取应用程序的句柄。
2、从给定的应用程序委托类,初始化一个应用程序委托。并把该委托设置为应用程序的委托,这里就有如果传入参数为nil,会调用函数访问 Info.plist文件来寻找主nib文件,获取应用程序委托。
3、启动主事件循环,并开始接收事件。