您的位置:首页 > 移动开发 > IOS开发

IOS-基础知识

2016-08-01 16:14 225 查看

单例

基本概念

通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问

在IOS中使用单例模式的情况

如果说创建一个对象会耗费很多系统资源,那么此时采用单例模式,因为只需要一个实例,会节省alloc的时间

在IOS开发中,如果很多模块都要使用同一个变量,此时如果把该变量放入单例类,则所有访问该变量的调用变得很容易,否则,只能通过一个模块传递给另外一个模块,这样增加了风险和复杂度

UIApplication类,NSBundle类,NSFileManager类,NSNotificationCenter类,NSUserDefaults类

创建单例模式的基本步骤

声明一个单例对象的静态实例,并初始化为nil

声明一个类的工厂方法,生成一个该类的实例,并且只会生成一个

覆盖allcoWithZone方法,确保用户在alloc 时,不会产生一个多余的对象

实现NSCopying协议,覆盖release,autorelease,retain,retainCount方法,以确保只有一个实例化对象

在多线程的环境中,注意使用@synchronized关键字

创建单例

GCD方式创建单例

static id _instance;
+ (instancetype)allocWithZone:(struct _NSZone *)zone
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [super allocWithZone:zone];
});
return _instance;
}
+ (instancetype)sharedInstance
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [[self alloc] init];
});
return _instance;
}
- (id)copyWithZone:(NSZone *)zone
{
return _instance;
}
- (id)mutableCopyWithZone:(NSZone *)zone {
return _instance;
}


互斥锁方式

static id _instance;
+ (instancetype)allocWithZone:(struct _NSZone *)zone
{
@synchronized(self) {
if (_instance == nil) {
_instance = [super allocWithZone:zone];
}
}
return _instance;
}
+ (instancetype)sharedInstance
{
@synchronized(self) {
if (_instance == nil) {
_instance = [[self alloc] init];
}
}
return _instance;
}
- (id)copyWithZone:(NSZone *)zone
{
return _instance;
}


kvo是同步的

Runtime

运行时系统

对于C语言,函数的调用在编译的时候会决定调用哪个函数。对于OC的函数,属于动态调用过程,在编译的时候并不能决定真正调用哪个函数,只有在真正运行的时候才会根据函数的名称找到对应的函数来调用。

动态特性

使得它在语言层面上支持程序的可扩展性。只有在程序运行时,才会去确定对象的类型,并调用类与对象相应的方法。利用runtime机制让我们可以在程序运行时动态修改类的具体实现、包括类中的所有私有属性、方法。

常用方法

获取类的所有变量

获取类的所有方法

改变类的私有变量

为类的category类增加新属性

为类添加方法

交换类的方法功能

事件传递,响应者链条

事件分发,触摸事件处理

1 点击一下iOS设备的屏幕,UIKit就会生成一个事件对象UIEvent

2 UIKit把这个Event分发给当前活动的app。

3 当前活动的app有事件之后,UIApplication 单例就会从事件队列中去取最新的事件,然后分发给能够处理该事件的对象。

3 UIApplication 获取到Event之后,Application就纠结于到底要把这个事件传递给谁,这时候就要依靠HitTest来决定了。

4 iOS中,hit-Testing的作用就是找出这个触摸点下面的View是什么,HitTest会检测这个点击的点是不是发生在这个View上,如果是的话,就会去遍历这个View的subviews,直到找到最小的能够处理事件的view,如果整了一圈没找到能够处理的view,则返回自身,最终,这个触摸事件交给主窗口的hitTest:withEvent:方法返回的视图对象去处理。拿到这个UIView后,就调用该UIView的touches系列方法。消息处理过程,在找到的那个视图里处理,处理完后根据需要,利用响应链nextResponder可将消息往下一个响应者传递,UIAppliactionDelegate <- UIWindow <- UIViewController <- UIView <- UIView(响应者链条)

响应者链条传递过程

如果view是控制器的view,就传递给控制器;如不是,则将其传递给它的父视图 在视图层次结构的最顶级视图,如果也不能处理收到的事件或消息,则其将事件或消息传递给window对象进行处理 如果window对象也不处理,则其将事件或消息传递给UIApplication对象 如果UIApplication也不能处理该事件或消息,则将其丢弃,如果处理,UIApplication再分发给AppDelegate,于是我们在ViewController和appDelegate的touchBegan方法中都捕获到了这次事件。

编程思想

面向过程:处理事情以过程为核心,一步一步的实现。

面向对象:万物皆对象

链式编程思想:

是将多个操作(多行代码)通过点号(.)链接在一起成为一句代码,使代码可读性好。a(1).b(2).c(3)

链式编程特点:方法的返回值是block,block必须有返回值(本身对象),block参数(需要操作的值)

代表:Masonry框架。

响应式编程思想:不需要考虑调用顺序,只需要知道考虑结果,类似于蝴蝶效应,产生一个事件,会影响很多东西,这些事件像流一样的传播出去,然后影响结果,借用面向对象的一句话,万物皆是流。代表:KVO运用。

函数式编程思想:

是把操作尽量写成一系列嵌套的函数或者方法调用。

函数式编程特点:每个方法必须有返回值(本身对象),把函数或者Block当做参数,block参数(需要操作的值)block返回值(操作结果)

代表:ReactiveCocoa。

ReactiveCocoa编程思想 函数响应式编程(FRP)框架

函数式编程(Functional Programming)

响应式编程(Reactive Programming)

Block

1.闭包就是能够读取其它函数内部变量的函数

2.__block是一种特殊类型,

使用该关键字声明的局部变量,可以被block所改变,并且其在原函数中的值会被改变。

3.使用block和使用delegate完成委托模式有什么优点?

使用block实现委托模式,其优点是回调的block代码块定义在委托对象函数内部,使代码更为紧凑;

适配对象不再需要实现具体某个protocol,代码更为简洁。

IOS 优化

tableView优化

使用局部更新

少给cell动态添加view

重用

UIImageView背景色设置成不透明,Cell上背景色不要使用clearColor,最好和tableView背景色一致

cell上layer尽量避免使用圆角

图片加载方式imageNamed(小图,经常使用,根据key查找缓存区的内存地址)imageWithContentOfFile(大图,一次使用,使用完会立即丢弃资源)

runloop延迟加载,滑动的时候NSRunLoopTrackingMode

模式切换到NSDefaultRunLoopMode模式,停止滚动再加载图片

8.图片加载优化,先模糊在清晰(kCGImagePropertyJFIFXDensity)

AFNetWork

AFNetwork是封装NSURLConnetion与NSURLSession框架,NSURLConnetion和NSURLSession是基于CFNetwork,3.0以后

已不再维护NSURLConnetion

NSURLSession()没有实现同步,提供了block和delegate方式,block重视结果,delegate重视过程。

IBOutlet连出来的视图属性为什么可以被设置成weak?

使用storyboard(xib不行)创建的vc,会有一个叫_topLevelObjectsToKeepAliveFromStoryboard的私有数组强引用所有top level的对象,所以这时即便outlet声明成weak也没关系


bjc使用什么机制管理对象内存?

通过retainCount的机制来决定对象是否需要释放。每次runloop的时候,都会检查对象的retainCount,如果retainCount为0,说明该对象没有地方需要继续使用了,可以释放掉了。


ARC通过什么方式帮助开发者管理内存?

编码时根据代码上下文,插入保留/释放


不手动指定autoreleasepool的前提下,一个autorealese对象在什么时刻释放?(比如在一个vc的viewDidLoad中创建)

1.手动干预释放时机 - 指定autoreleasepool就是所谓的:当前作用域大括号结束时释放。
2.系统自动去释放 - 不手动指定autoreleasepool
Autorelease对象会在当前的runloop迭代结束时释放。
如果在一个vc的viewDidLoad中创建一个Autorelease对象,那么该对象会在viewDidAppear方法执行前就被销毁了。

释放时机是基于runloop而不是作用域,每个线程创建的时候就会创建一个autorelease pool,并且在线程退出的时候,清空autorelease pool,(子线程中循环是无法释放的,可以用@autorelease{})通过autorelease pool手动干预释放;循环多次时当心要对autorelease进行优化。下面我们开始第二个问题的讨论
当我们使用@autoreleasepool{}时,编译器实际上将其转化为以下代码:
void *context = objc_autoreleasePoolPush();
// {}中的代码
objc_autoreleasePoolPop(context);//当前runloop迭代结束时进行pop操作
for、forin、enumerateObjectsUsingBlcokblock版本的遍历方式已经内嵌了@autoreleasepool{}操作,而前面两个没有,这样就意味着使用block版本的遍历方式会使app更加健壮,内存使用效率更加出色,而且,逼格更高


ARC模式下iOS对象无法按预期释放原因是循环引用,需要注意的问题

1.NSTimer经常会被作为某个类的成员变量,而NSTimer初始化时要指定self为target,容易造成循环引用,不要在delloc中释放timer,要显性释放(timer不析构,不调用delloc)
2.block循环引用
3.代理声明delegate时请用assign(MRC)或者weak(ARC)
4.子线程中循环,释放时机是基于runloop而不是作用域,每个线程创建的时候就会创建一个autorelease pool,并且在线程退出的时候,清空autorelease pool,(子线程中循环是无法释放的,可以用@autorelease{})


IOS 数据结构总结

其它

属性readwrite,readonly,assign,retain,copy,nonatomic 各是什么作用,在那种情况下用?

readwrite 是可读可写特性;需要生成getter方法和setter方法时

readonly 是只读特性 只会生成getter方法 不会生成setter方法 ;不希望属性在类外改变

assign 是赋值特性,setter方法将传入参数赋值给实例变量;仅设置变量时;

retain 表示持有特性,setter方法将传入参数先保留,再赋值,传入参数的retaincount会+1;

copy 表示拷贝特性,setter方法将传入对象复制一份;需要完全一份新的变量时。

nonatomic 非原子操作,决定编译器生成的setter getter是否是原子操作,atomic表示多线程安全,一般使用nonatomic

iOS SDK中如何实现MVC的开发模式

MVC是模型、视图、控制器开发模式,对于iOS SDK,所有的View都是视图层的,它应该独立于模型层,由视图器来控制。所有的用户数据都是模型层,它应该独立于视图。所有的ViewController都是视图器,由它负责控制视图,访问模型数据。

iOS多线程常见面试题

在项目什么时候选择使用GCD,什么时候选择NSOperation?

项目中使用NSOperation的优点是NSOperation是对线程的高度抽象,在项目中使用它,会使项目的程序结构更好,子类化NSOperation的设计思路,是具有面向对象的优点(复用、封装),使得实现是多线程支持,而接口简单,建议在复杂项目中使用。

项目中使用GCD的优点是GCD本身非常简单、易用,对于不复杂的多线程操作,会节省代码量,而Block参数的使用,会是代码更为易读,建议在简单项目中使用。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: