1.@synthesize && @dynamic
@synthesize,编译器自动生成setter和getter的方法,在你没有手动去实现这两个方法时。
@dynamic,告诉编译器你会动态生成setter和getter方法,不会要编译器帮你生成。
2.NSProxy && NSObject
3.NSCache && NSDictionary
构建缓存时使用--NSCache而非NSDictionary的理由:
- 当系统资源将要耗尽的时候,NSCache可以自动删减缓存,而且线性删减"最久未使用的"对象,NSCache是不是很强大。但是NSDictionary就需要在系统发出"低内存"通知时手工删减缓存,还需要自己编写相应优先删减内存等一系列逻辑。
- NSCache是线程安全的,可以在供多个线程同时访问NSCache但是NSDictionary就不具备此优势
- NSCache对象不拷贝键,因为很多时候键都是由不支持拷贝操作的对象来充当的,因此NSCache不会自动拷贝
4.UILayer && UIView
所有的 view 都是由一个底层的 layer 来驱动的,layer侧重于图形的显示,而view相当于layer的管理者
- 响应事件:从UIView和CALayer的定义可以看出UIView是继承于UIResponder,而CALayer是继承于NSObject。在iOS中,UIKit使用UIResponder作为响应对象,来响应系统传递过来的事件并进行处理。所以UIView可以响应事件,而CALyer则不能响应事件。
- 初始化Frame:一个 Layer 的 frame 是由它的 anchorPoint,position,bounds,和 transform 共同决定的,而一个 View 的frame 只是简单的返回 Layer的 frame,同样 View 的 center和 bounds 也是返回 Layer 的一些属性
- 内容管理和绘制:UIView主要是对显示内容的管理,而CALayer主要是对显示的绘制
- 隐式动画:每个view都有一个layer,但是也有一些不依附view单独存在的layer,如CAShapelayer。它们不需要附加到 view 上就可以在屏幕上显示内容。
UIView
默认情况下禁止了layer
动画,但是在animation block
中又重新启用了它们。当layer
在背后支持一个view
的时候,view
就是它的delegate
。
每个 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 不可以
5.layoutSubViews && drawRect
layoutSubViews 这个方法是用来对
subviews重新布局
,默认没有做任何事情,需要子类进行重写。当我们在某个类的内部调整子视图位置时,需要调用。
- - (void)layoutSubviews; //对subview重新布局
- - (void)setNeedsLayout; //将视图标记为需要重新布局,
这个方法会在系统runloop的下一个周期自动调用layoutSubviews。
- - (void)layoutIfNeeded; //如果有需要刷新的
标记
,立即调用layoutSubviews进行布局(如果没有标记,不会调layoutSubviews)layoutSubViews 调用时机
- init初始化不会触发layoutSubviews。
- addSubview会触发layoutSubviews。(当然这里frame为0,是不会调用的,同上面的drawrect:一样)
- 设置view的Frame会触发layoutSubviews,(当然前提是frame的值设置前后发生了变化。)
- 滚动一个UIScrollView会触发layoutSubviews。
- 旋转屏幕会触发父UIView上的layoutSubviews事件。(这个我们开发中会经常遇到,比如屏幕旋转时,为了界面美观我们需要修改子view的frame,那就会在layoutSubview中做相应的操作)
- 改变一个UIView大小的时候也会触发父UIView上的layoutSubviews事件。
- 直接调用setLayoutSubviews。(Apple是不建议这么做的)
绘图操作是在UIView的drawRect中完成的,我们想要在UIView中完成绘图(或者自定义控件),需要在UIView的拓展类(或者子类)中重写drawRect函数,在这里进行绘图的操作,系统会自动调用该函数进行绘图。
- - (void)drawRect:(CGRect)rect; //重写此方法,执行重绘任务
- - (void)setNeedsDisplay; //将视图标记为需要重绘,异步调用drawRect
- - (void)setNeedsDisplayInRect:(CGRect)rect; //将视图标记为需要局部重绘
drawRect调用时机
- 调用时机:loadView ->ViewDidload ->drawRect:
- 如果在UIView初始化时没有设置rect大小,将直接导致drawRect:不被自动调用。
- 通过设置contentMode属性值为UIViewContentModeRedraw。那么将在
每次设置或更改frame
的时候自动调用drawRect:
。- 直接调用setNeedsDisplay,或者setNeedsDisplayInRect:触发drawRect:,但是有个前提条件是:
view当前的rect不能为nil
- 该方法在调用sizeThatFits后被调用,所以可以先调用sizeToFit计算出size。然后系统自动调用drawRect:方法。
这里简单说一下sizeToFit和sizeThatFit:
sizeToFit:会计算出最优的 size 而且会改变自己的size。
sizeThatFits:会计算出最优的 size 但是不会改变 自己的 size
6.UDID && UUID
- Unique Device Identifier :设备唯一标识符,用来唯一识别某台设备。在很多需要限制一台设备一个账号的应用中经常会用到,在Symbian时代,我们是使用IMEI作为设备的唯一标识的,可惜的是Apple官方不允许开发者获得设备的IMEI.
- Universally Unique Identifier :通用唯一标识符,它能让你在不同地点,不借助中央服务器的情况下为任何项目创建唯一的标识符。例如:如果你要在App里加入一个永不会和其它ID冲突的用户ID,你可以自己建一个服务器,并用脚本为每个客户端分配一个ID。但这种集中管理的方式受网络影响,速度慢,而且服务器处理时间也影响速度。事实上你可以用UUID,它在每个客户端上生成ID,生成的ID不会跟任何ID重复(UUID生成条件: 1.当前日期和时间 2.时钟序列 3.全局唯一的IEEE机器识别号,如果有网卡从网卡MAC地址获得,没有网卡以其他方式获得)。
7.点(pt) && 像素(px)
iOS 开发中用到的单位 pt 是独立像素的意思,它是绝对长度,不随屏幕像素密度变化而变化(和我们日常用到的毫米、厘米是一个意思,只是它要小得多),在非视网膜的 iPhone 上(iPhone 3G),苹果规定 1px=1pt,也就是说 pt 和像素点是一一对应的。但随着 iPhone 4 的到来,高分屏出现了(视网膜屏),这个时候 1pt 对应 2px
8.int && NSInteger
#if LP64 || TARGET_OS_EMBEDDED || TARGET_OS_IPHONE || TARGET_OS_WIN32 || NS_BUILD_32_LIKE_64 typedef long NSInteger; typedef unsigned long NSUInteger; #else typedef int NSInteger; typedef unsigned int NSUInteger; #endif
NSInteger与int的区别是NSInteger会根据系统的位数(32or64)自动选择int的最大数值(int or long)。
9.iOS多重继承 协议 && 分类 && 消息转发
10.Object-C 优点 && 缺点
优点:1.分类 在不创建继承类的情况下,给已经存在的类添加方法
2.运行时 运行时主要包括动态识别,动态添加属性,动态添加方法,动态交换方法实现
3.可以和C、C++混编
缺点:1.没有多重继承
2.没有命名空间
3.不支持运算符重载
11.Object-C 动态特性 && 动态特征
动态特征:1.封装 封装是隐藏对象的属性和方法实现,仅对外公开接口
2.继承 使子类具有父类的各种属性和方法
3.多态 允许将子类类型的指针赋值给父类类型的指针,即父类的指针指向子类的实例
动态特性:1.动态类型 (id类型)在编译器编译的时候不能被识别出,在运行时(run time),程序运行的时候才会根据 语境来识别。
2.动态绑定 (关键词@selector)跳过编译,在运行时动态添加函数调用,运行时才决定调用什么方法,传递 什么参数。
3.动态加载 根据需求动态地加载资源。
12.讲一下MVC && MVVM && MVP
MVC特点:
MVC模式的特点是数据模型与业务和展示逻辑解耦。在客户端web开发中,就是将模型(M-数据、操作数据)、视图(V-显示数据的HTML元素)之间实现代码分离,松散耦合,使之成为一个更容易开发、维护和测试的客户端应用程序。
View 传送指令到 Controller ;
Controller 完成业务逻辑后,要求 Model 改变状态 ;
Model 将新的数据发送到 View,用户得到反馈。
MVP(Model-View-Presenter)是MVC的改良模式,由IBM的子公司Taligent提出。和MVC的相同之处在于:Controller/Presenter负责业务逻辑,Model管理数据,View负责显示只不过是将 Controller 改名为 Presenter,同时改变了通信方向。
MVP特点:M、V、P之间双向通信。
View 与 Model 不通信,都通过 Presenter 传递。Presenter完全把Model和View进行了分离,主要的程序逻辑在 Presenter里实现。
View 非常薄,不部署任何业务逻辑,称为”被动视图”(Passive View),即没有任何主动性,而 Presenter非常厚,所有逻辑都部署在那里。
Presenter与具体的View是没有直接关联的,而是通过定义好的接口进行交互,从而使得在变更View时候可以保持Presenter的不变,这样就可以重用。不仅如此,还可以编写测试用的View,模拟用户的各种操作,从而实现对Presenter的测试–从而不需要使用自动化的测试工具。
MVVM
MVVM是Model-View-ViewModel的简写。MVVM模式其实是MV模式与WPF结合的应用方式时发展演变过来的一种新型架构模式。它立足于原有MVP框架并且把WPF的新特性糅合进去,以应对客户日益复杂的需求变化。
13.load && initialize
调用方式:load是根据函数地址直接调用,initialize是通过objc_msgSend调用
调用时刻:load是runtime加载类、分类的时候调用(只会调用1次),initialize是类第一次接收到消息的时候调用,每一个类只会initialize一次(父类的initialize方法可能会被调用多次)调用顺序:先调用类的load方法,先编译那个类,就先调用load。在调用load之前会先调用父类的load方法。分类中load方法不会覆盖本类的load方法,先编译的分类优先调用load方法。initialize先初始化父类,之后再初始化子类。如果子类没有实现+initialize,会调用父类的+initialize(所以父类的+initialize可能会被调用多次),如果分类实现了+initialize,就覆盖类本身的+initialize调用。