1 线程与进程,以及三种多线程技术简介。
(1)线程是进程的执行单元,进程的所有任务都在线程中执行!
(2)线程是 CPU 调用的最小单位
(3)进程是 CPU 分配资源和调度的单位
(4)一个程序可以对应过个进程,一个进程中可有多个线程,但至少要有一条线程
(5)同一个进程内的线程共享进程资源
同步、异步、并行、并发
同步:同步添加任务到指定的队列中,在添加的任务执行结束之前,会一直等待,直到队列里面的任务完成之后再继续执行。
只能在当前线程中执行任务,不具备开启新线程的能力。
异步:异步添加任务到指定的队列中,它不会做任何等待,可以继续执行任务。
可以在新的线程中执行任务,具备开启新线程的能力。
并行:每次只有一个任务被执行。让任务一个接着一个地执行。(只开启一个线程,一个任务执行完毕后,再执行下一个任务
并发:可以让多个任务并发(同时)执行。(可以开启多个线程,并且同时执行任务)
1(一)NSThread
优点:NSThread 比其他两个轻量级
缺点:需要自己管理线程的生命周期,线程同步。线程同步对数据的加锁会有一定的系统开销
2(二)NSOperation
优点:不需要关心线程管理, 数据同步的事情,可以把精力放在自己需要执行的操作上。
Cocoa operation相关的类是NSOperation, NSOperationQueue.
NSOperation是个抽象类,使用它必须用它的子类,可以实现它或者使用它定义好的两个子类: NSInvocationOperation和NSBlockOperation.
创建NSOperation子类的对象,把对象添加到NSOperationQueue队列里执行。
3(三)GCD(全称:Grand Central Dispatch)
没找到缺点
一次函数
- (void)once{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSLog(@"once");
});
}
栅栏函数
dispatch_barrier_async(queue, ^{
NSLog(@"+++++++++++++++");
});
延时函数
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
});
定时器
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(0, 0));
dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 2.0 * NSEC_PER_SEC, 0 * NSEC_PER_SEC);
// 3.设置定时器执行任务
dispatch_source_set_event_handler(timer, ^{
NSLog(@"GCD --- %@",[NSThread currentThread]);
});
// 4.启动执行
dispatch_resume(timer);
2 运行时机制的原理和运用场景。
runtime简称运行时。OC是运行时机制,也就是在运行时才做一些处理。例如:C语言在编译的时候就知道要调用哪个方法函数,而OC在编译的时候并不知道要调用哪个方法函数,只有在运行的时候才知道调用的方法函数名称,来找到对应的方法函数进行调用。Runtime基本是用C和汇编写的,方便我们在运行时的时候将消息重定向给新的对象、交换方法、动态添加方法、为系统类添加属性等等。
(1)、发送消息objc_msgSend(p, @selector(eat));
(2)、可以通过runtime的一系列方法获取类的一些信息(包括属性列表,方法列表,成员变量列表,和遵循的协议列表
objc_property_t *propertyList = class_copyPropertyList([selfclass], &count);
Method *methodList = class_copyMethodList([selfclass], &count);
Ivar *ivarList = class_copyIvarList([selfclass], &count);
class_copyProtocolList([selfclass], &count);
(3)、交换方法
开发使用场景:系统自带的方法功能不够,给系统自带的方法扩展一些功能,并且保持原有的功能。
方式一:继承系统的类,重写方法.
方式二:使用runtime,交换方法.method_exchangeImplementations(imageWithName, imageName);
(4)、动态添加方法
class_addMethod(self, sel, (IMP)runAddMethod,"v@:*");
(5)、给分类添加属性
objc_setAssociatedObject(self, key, name, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
3 SDWebImage的原理。实现机制。
4 如何解决TableView卡的问题。
a、cell复用
b、异步加载图片
c、cell中减少使用动画
d、文字图片可以直接drawInRect绘制
e、动态行高,提前计算好高度缓存
5 block和代理的,通知的区别。block的用法需要注意些什么。
1.NotificationCenter 通知中心:“一对多”,在APP中,很多控制器都需要知道一个事件,应该用通知;
2.delegate 代理委托:
1,代理是一种软件设计模式,传递方式是“一对一”的,对同一个协议,一个对象只能设置一个代理delegate,所以单例对象就不能用代理;
2,代理更注重过程信息的传输:比如发起一个网络请求,可能想要知道此时请求是否已经开始、是否收到了数据、数据是否已经接受完成、数据接收失败
3,在协议中可以定义方法和属性
代理中规定的协议方法,都必须实现吗?
答:不一定。在协议当中,方法的声明,被@required修饰,那么就准守这个协议的类,必须实现这个方法
被@optional修饰,那么准守这个协议的类,可以实现这个方法,也可以不实现这个方法
3.block(闭包)
block和delegate一样,一般都是“一对一”之间通信交互,相比代理block有以下特点
1:写法更简练,不需要写protocol、函数等等
2,block注重结果的传输:比如对于一个事件,只想知道成功或者失败,并不需要知道进行了多少或者额外的一些信息
3,block需要注意防止循环引用
6 strong,weak,retain,assign,copy nomatic 等的区别。
strong:强引用,引用计数加1,一个对象只要有strong指针指向它就不能被释放
weak:弱引用,引用计数不会加1,并在引用对象被释放时候自动被置为nil
copy:浅Copy:可以理解为指针的复制,只是多了一个指向这块内存的指针,共用一块内存。
深Copy:理解为内存的复制,两块内存是完全不同的,也就是两个对象指针分别指向不同的内存,互不干涉。如果使用strong在浅拷贝的时候是和copy一样没有问题,在需要深拷贝的时候用strong是做不到的,会造成意外的数据操作。
retain:使用了引用计数,retain引起引用计数加1, release引起引用计数减1,当引用计数为0时,dealloc函数被调用,内存被回收;
assign:修饰基本数据类型,内存由系统开辟和释放,修饰对象,如果用assign修饰对象,当对象被释放后,指针的地址还是存在的,也就是说指针并没有被置为nil,从而造成了野指针。因为对象是分配在堆上的,堆上的内存由程序员分配释放。而因为指针没有被置为nil,如果后续的内存分配中,刚好分配到了这块内存,就会造成崩溃。
atomic:表示是线程安全的。
nonatomic:表示是非线程安全的,使用此属性性能会提高一些。
系统默认是atomic
7 设计模式,mvc,单利,工厂,代理等的应用场景。
(一)代理模式
应用场景:当一个类的某些功能需要由别的类来实现,但是又不确定具体会是哪个类实现。
优势:解耦合敏捷原则:开放-封闭原则实例:tableview的 数据源delegate,通过和protocol的配合,完成委托诉求。列表row个数delegate自定义的delegate
二)观察者模式
应用场景:一般为model层对,controller和view进行的通知方式,不关心谁去接收,只负责发布信息。
优势:解耦合敏捷原则:接口隔离原则,开放-封闭原则实例:Notification通知中心,注册通知中心,任何位置可以发送消息,注册观察者的对象可以接收。kvo,键值对改变通知的观察者,平时基本没用过。
(三)MVC模式
应用场景:是一中非常古老的设计模式,通过数据模型,控制器逻辑,视图展示将应用程序进行逻辑划分。
优势:使系统,层次清晰,职责分明,易于维护敏捷原则:对扩展开放-对修改封闭实例:model-即数据模型,view-视图展示,controller进行UI展现和数据交互的逻辑控制。
四)单例模式
应用场景:确保程序运行期某个类,只有一份实例,用于进行资源共享控制。
优势:使用简单,延时求值,易于跨模块敏捷原则:单一职责原则实例:[UIApplication sharedApplication]。注意事项:确保使用者只能通过 getInstance方法才能获得,单例类的唯一实例。java,C++中使其没有公有构造函数,私有化并覆盖其构造函数。object c中,重写allocWithZone方法,保证即使用户用 alloc方法直接创建单例类的实例,返回的也只是此单例类的唯一静态变量。
(五)策略模式
应用场景:定义算法族,封装起来,使他们之间可以相互替换。优势:使算法的变化独立于使用算法的用户敏捷原则:接口隔离原则;多用组合,少用继承;针对接口编程,而非实现。
实例:排序算法,NSArray的sortedArrayUsingSelector;经典的鸭子会叫,会飞案例。
注意事项:
1,剥离类中易于变化的行为,通过组合的方式嵌入抽象基类
2,变化的行为抽象基类为,所有可变变化的父类
3,用户类的最终实例,通过注入行为实例的方式,设定易变行为防止了继承行为方式,导致无关行为污染子类。完成了策略封装和可替换性。
(六)工厂模式
应用场景:工厂方式创建类的实例,多与proxy模式配合,创建可替换代理类。
优势:易于替换,面向抽象编程,application只与抽象工厂和易变类的共性抽象类发生调用关系。
七)MVVM模式
MVVM模式是Model-View-ViewMode模式的简称。由视图(View)、视图模型(ViewModel)、模型(Model)三部分组成,结构如下图。通过这三部分实现UI逻辑、呈现逻辑和状态控制、数据与业务逻辑的分离。
使用MVVM模式有几大好处:
1. 低耦合。View可以独立于Model变化和修改,一个ViewModel可以绑定到不同的View上,当View变化的时候Model可以不变,当Model变化的时候View也可以不变。
2. 可重用性。可以把一些视图的逻辑放在ViewModel里面,让很多View重用这段视图逻辑。
3. 独立开发。开发人员可以专注与业务逻辑和数据的开发(ViewModel)。设计人员可以专注于界面(View)的设计。
4. 可测试性。可以针对ViewModel来对界面(View)进行测试
8 传递者链 和响应者链 。
响应者链应该是:First Responser—-> UIView -- > The Window -- >The Application -- > App Delegate
传递者链 UIWindow -> UIView -> Next UIView -> NextView (直到用户触碰的那个View)
9重新@property (nonatomic, copy) NSString *name; 的setter方法原型;
(void)setName:(NSString *)name {
if(_name) {
[ _name release];
_name = [name copy];
}
}
10 远程推送原理是什么??
由App向iOS设备发送一个注册通知
iOS向APNs远程推送服务器发送App的Bundle Id和设备的UDID
APNs根据设备的UDID和App的Bundle Id生成deviceToken再发回给App
App再将deviceToken发送给远程推送服务器(商家自己的服务器), 由服务器保存在数据库中
当商家想发送推送时, 在远程推送服务器中输入要发送的消息并选择发给哪些用户的deviceToken,由远程推送服务器发送给APNs
APNs根据deviceToken发送给对应的用户
11 在arc中需要我们手动管理内存的几种情况
1、while (true) {} 无线循环时
2、webview在dealloc中把WebView的delegate释放。
3、Core Foundation对象还是需要我们手动进行释放的,CFRelease()
4、循环引用
12 KVC和KVO
KVC也就是key-value-coding,即键值编码,通常是用来给某一个对象的属性进行赋值
kvc的两种常用场景
1,对私有变量进行赋值
2,字典转模型
但是也有一些需要注意的地方
1,字典转模型的时候,字典中的某一个key一定要在模型中有对应的属性
2,如果一个模型中包含了另外的模型对象,是不能直接转化成功的。
3,通过kvc转化模型中的模型,也是不能直接转化成功的。
二,KVO
KVO,即key-value-observing,利用一个key来找到某个属性并监听其值得改变。其实这也是一种典型的观察者模式。
简单的说,kvo的用法非常简单。
1,添加观察者
2,在观察者中实现监听方法,observeValueForKeyPath: ofObject: change: context:(通过查阅文档可以知道,绝大多数对象都有这个方法,因为这个方法属于NSObject)
3,移除观察者
KVO的底层实现
当一个类的属性被观察的时候,系统会通过runtime动态的创建一个该类的派生类,并且会在这个类中重写基类被观察的属性的setter方法,而且系统将这个类的isa指针指向了派生类,从而实现了给监听的属性赋值时调用的是派生类的setter方法。重写的setter方法会在调用原setter方法前后,通知观察对象值得改变
13 类别,类扩展,继承
类别是一种为现有的类添加新方法的方式。
利用Objective-C的动态运行时分配机制,可以为现有的类添加新方法,为现有的类添加新方法的方式称为类别catagory
分类的特点:(也是分类与扩展的区别)
1运行时决议的
2可为系统添加分类(例如常用的为uiview添加获取坐标的分类)
分类都可以添加哪些内容?
1实例方法
2类方法
3协议
4属性(添加属性,并不是意味着添加成员变量。分类想要添加成员变量需要借助关联对象这一方法为分类添加成员变量)
1、声明类别
声明类别与声明类的形式很相似
@interface NSString(TestCateory)
-(int)lengthString;
@end
两个特点:(1)现有的类位于@interface关键字之后,其后是位于圆括号中的类别名称。同名类别有唯一性,可以添加任意多的不同名类别。
(2)可以向其添加类别的类以及类别的名称,列出添加的方法, 不可以添加新的实例变量。
2、实现类别
@implementation NSString(TestCateory)
-(int)lengthString{
}
@end //在实现部分也包括类名、类别名和新方法的实现代码
3、类别的局限性
有两方面局限性:
(1)无法向类中添加新的实例变量.
(2)名称冲突,即当类别中的方法与原始类方法名称冲突时,类别具有更高的优先级。类别方法将完全取代初始方法从而无法再使用初始方法。
4、类别的作用
类别主要有3个作用:
(1)将类的实现分散到多个不同文件或多个不同框架中。
(2)创建对私有方法的前向引用。
(3)向对象添加非正式协议。
扩展
类扩展Class extensions
1,类扩展声明格式@interface MyClass(), 可以在类扩展中声明属性和实例变量。
2,类的Extension 可以当作是匿名的 category
3,定义在里面的方法不能被其它的 category 覆盖掉,因为找不到 reference. 用这个来实现某种意义上的 private method.
继承
object-c不支持多重继承,只能单继承,一个类只能有一个父类。
1,方法重写:若子类中的方法与父类的某一方法具有相同的方法名、返回类型和参数表,则新方法覆盖原有方法。
2,方法重载:类中可以创建多个方法,他们具有相同的方法名,但具有不同的参数和不同的定义,调用方法时通过传递给他们不同个数和类型的参数来觉定使用哪个方法。 方法名一定相同;方法的参数表必须不同,包括参数的个数和类型,以此区分不同的方法体; 方法的返回类型和修饰符可以相同也可以不同。
3,self:一个类中的方法调用同一个类的另一个方法是使用self,代表本身,相当于this。
4,super:表示父类,可以使用super访问父类中被子类隐藏或重写的方法。