一、isMemberOfClass 和 isKindOfClass 联系与区别
-
联系:两者都能检测一个对象是否是某个类的成员
-
区别:
isKindOfClass
不仅用来确定一个对象是否是一个类的成员,也可以用来确定一个对象是否派生自该类的类的成员 ,而isMemberOfClass
只能做到第一点。 -
举例:如
ClassA
派 生 自NSObject
类 ,
ClassA *a = [ClassA alloc] init]
;,
[a isKindOfClass:[NSObject class]]
可以检查出 a 是否是 NSObject派生类 的成员,但 isMemberOfClass 做不到。
二、iOS 开发中数据持久性有哪几种?
数据存储的核心都是写文件。
-
属性列表:只有NSString、NSArray、NSDictionary、NSData可writeToFile;存储依旧是plist文件。plist文件可以存储的7中数据类型:array、dictionary、string、bool、data、date、number。
-
对象序列化(对象归档):对象序列化通过序列化的形式,键值关系存储到本地,转化成二进制流。通过runtime实现自动化归档/解档,请参考这个文章。实现NSCoding协议必须实现的两个方法:1.编码(对象序列化):把不能直接存储到plist文件中得到数据,转化为二进制数据,NSData,可以存储到本地;2.解码(对象反序列化):把二进制数据转化为本来的类型。
-
SQLite 数据库:大量有规律的数据使用数据库。
-
CoreData :通过管理对象进行增、删、查、改操作的。它不是一个数据库,不仅可以使用SQLite数据库来保持数据,也可以使用其他的方式来存储数据。如:XML。
CoreData的介绍:
-
CoreData是面向对象的API,CoreData是iOS中非常重要的一项技术,几乎在所有编写的程序中,CoreData都作为数据存储的基础。
-
CoreData是苹果官方提供的一套框架,用来解决与对象声明周期管理、对象关系管理和持久化等方面相关的问题。
-
大多数情况下,我们引用CoreData作为持久化数据的解决方案,并利用它作为持久化数据映射为内存对象。提供的是对象-关系映射功能,也就是说,CoreData可以将Objective-C对象转换成数据,保存到SQL中,然后将保存后的数据还原成OC对象。
CoreData的特征:
-
通过CoreData管理应用程序的数据模型,可以极大程度减少需要编写的代码数量。
-
将对象数据存储在SQLite数据库已获得性能优化。
-
提供NSFetchResultsController类用于管理表视图的数据,即将Core Data的持久化存储在表视图中,并对这些数据进行管理:增删查改。
-
管理undo/redo操纵;
-
检查托管对象的属性值是否正确。
Core Data的6成员对象
-
1.NSManageObject:被管理的数据记录Managed Object Model是描述应用程序的数据模型,这个模型包含实体(Entity)、特性(Property)、读取请求(Fetch Request)等。
-
2.NSManageObjectContext:管理对象上下文,持久性存储模型对象,参与数据对象进行各种操作的全过程,并监测数据对象的变化,以提供对undo/redo的支持及更新绑定到数据的UI。
-
3.NSPersistentStoreCoordinator:连接数据库的Persistent Store Coordinator相当于数据文件管理器,处理底层的对数据文件的读取和写入,一般我们与这个没有交集。
-
4.NSManagedObjectModel:被管理的数据模型、数据结构。
-
5.NSFetchRequest:数据请求;
-
6.NSEntityDescription:表格实体结构,还需知道.xcdatamodel文件编译后为.momd或者.mom文件。
Core Data的功能
-
对于KVC和KVO完整且自动化的支持,除了为属性整合KVO和KVC访问方法外,还整合了适当的集合访问方法来处理多值关系;
-
自动验证属性(property)值;
-
支持跟踪修改和撤销操作;
-
关系维护,Core Data管理数据的关系传播,包括维护对象间的一致性;
-
在内存上和界面上分组、过滤、组织数据;
-
自动支持对象存储在外部数据仓库的功能;
-
创建复杂请求:无需动手写SQL语句,在获取请求(fetch request)中关联NSPredicate。NSPreadicate支持基本功能、相关子查询和其他高级的SQL特性。它支持正确的Unicode编码、区域感知查询、排序和正则表达式;
-
延迟操作:Core Data使用懒加载(lazy loading)方式减少内存负载,还支持部分实体化延迟加载和复制对象的数据共享机制;
-
合并策略:Core Data内置版本跟踪和乐观锁(optimistic locking)来支持多用户写入冲突的解决,其中,乐观锁就是对数据冲突进行检测,若冲突就返回冲突的信息;
-
数据迁移:Core Data的Schema Migration工具可以简化应对数据库结构变化的任务,在某些情况允许你执行高效率的数据库原地迁移工作;
-
可选择针对程序Controller层的集成,来支持UI的显示同步Core Data在IPhone OS之上,提供NSFetchedResultsController对象来做相关工作,在Mac OS X上我们用Cocoa提供的绑定(Binding)机制来完成的。
iOS技术交流群:923910776,群内提供数据结构与算法、底层进阶、swift、逆向、底层面试题整合文档等免费资料!
三、怎样使用performSelector传入3个以上参数,其中一个为结构体
- 因为系统提供的
performSelector
的API中,并没有提供三个参数。因此,我们只能传数组或者字典,但是数组或者字典只有存入对象类型,而结构体并不是对象类型,我们只能通过对象放入结构作为属性来传过去了.
- (id)performSelector:(SEL)aSelector;
- (id)performSelector:(SEL)aSelector withObject:(id)object;
- (id)performSelector:(SEL)aSelector withObject: (id)object1 withObject:(id)object2;
- 具体实现如下:
typedef struct HYBStruct {
int a;
int b;
} *my_struct;
@interface HYBObject : NSObject
@property (nonatomic, assign) my_struct arg3;
@property (nonatomic, copy) NSString *arg1;
@property (nonatomic, copy) NSString *arg2;
@end
@implementation HYBObject
// 在堆上分配的内存,我们要手动释放掉
- (void)dealloc {
free(self.arg3);
}
@end
- 测试:
my_struct str = (my_struct)(malloc(sizeof(my_struct)));
str->a = 1;
str->b = 2;
HYBObject *obj = [[HYBObject alloc] init];
obj.arg1 = @"arg1";
obj.arg2 = @"arg2";
obj.arg3 = str;
[self performSelector:@selector(call:) withObject:obj];
// 在回调时得到正确的数据的
- (void)call:(HYBObject *)obj {
NSLog(@"%d %d", obj.arg3->a, obj.arg3->b);
}
四、UITableViewCell上有个UILabel,显示NSTimer实现的秒表时间,手指滚动cell过程中,label是否刷新,为什么?
这是否刷新取决于timer加入到Run Loop中的Mode是什么。Mode主要是用来指定事件在运行循环中的优先级的,分为:
-
NSDefaultRunLoopMode(kCFRunLoopDefaultMode)
:默认,空闲状态 -
UITrackingRunLoopMode
:ScrollView滑动时会切换到该Mode -
UIInitializationRunLoopMode
:run loop启动时,会切换到该mode -
NSRunLoopCommonModes(kCFRunLoopCommonModes)
:Mode集合
苹果公开提供的Mode有两个: -
NSDefaultRunLoopMode(kCFRunLoopDefaultMode
-
NSRunLoopCommonModes(kCFRunLoopCommonModes)
-
在编程中:如果我们把一个
NSTimer
对象以NSDefaultRunLoopMode(kCFRunLoopDefaultMode)
添加到主运行循环中的时候, ScrollView滚动过程中会因为mode的切换,而导致NSTimer
将不再被调度。当我们滚动的时候,也希望不调度,那就应该使用默认模式。但是,如果希望在滚动时,定时器也要回调,那就应该使用common mode。
五、对于单元格重用的理解
- 当屏幕上滑出屏幕时,系统会把这个单元格添加到重用队列中,等待被重用,当有新单元从屏幕外滑入屏幕内时,从重用队列中找看有没有可以重用的单元格,若有,就直接用,没有就重新创建一个。
解决cell重用的问题
-
UITableView通过重用单元格来达到节省内存的目的,通过为每个单元格指定一个重用标示(reuseidentifier),即指定了单元格的种类,以及当单元格滚出屏幕时,允许恢复单元格以便复用。对于不同种类的单元格使用不同的ID,对于简单的表格,一个标示符就够了。
-
如一个TableView中有10个单元格,但屏幕最多显示4个,实际上iPhone只为其分配4个单元格的内存,没有分配10个,当滚动单元格时,屏幕内显示的单元格重复使用这4个内存。实际上分配的cell的个数为屏幕最大显示数,当有新的cell进入屏幕时,会随机调用已经滚出屏幕的Cell所占的内存,这就是Cell的重用。
-
对于多变的自定义Cell,这种重用机制会导致内容出错,为解决这种出错的方法,把原来的
UITableViewCell *cell = [tableview dequeueReusableCellWithIdentifier:defineString]
修改为:UITableViewCell *cell = [tableview cellForRowAtIndexPath:indexPath];
这样就解决掉cell重用机制导致的问题。
六、有a、b、c、d 4个异步请求,如何判断a、b、c、d都完成执行?如果需要a、b、c、d顺序执行,该如何实现?
- 对于这四个异步请求,要判断都执行完成最简单的方式就是通过GCD的group来实现:
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, queue, ^{ /*任务a */ });
dispatch_group_async(group, queue, ^{ /*任务b */ });
dispatch_group_async(group, queue, ^{ /*任务c */ });
dispatch_group_async(group, queue, ^{ /*任务d */ });
dispatch_group_notify(group,dispatch_get_main_queue(), ^{
// 在a、b、c、d异步执行完成后,会回调这里
});
- 当然,我们还可以使用非常老套的方法来处理,通过四个变量来标识a、b、c、d四个任务是否完成,然后在runloop中让其等待,当完成时才退出runloop。但是这样做会让后面的代码得不到执行,直到Run loop执行完毕。
- 解释:要求顺序执行,那么可以将任务放到串行队列中,自然就是按顺序来异步执行了。
七、使用block有什么好处?使用NSTimer写出一个使用block显示(在UILabel上)秒表的代码
-
代码紧凑,传值、回调都很方便,省去了写代理的很多代码。
-
NSTimer封装成的block,具体实现
-
实现方法:
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.0
repeats:YES
callback:^() {
weakSelf.secondsLabel.text = ...
}
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
八、一个view已经初始化完毕,view上面添加了n个button,除用view的tag之外,还可以采用什么办法来找到自己想要的button来修改button的值
有2种方法解决:
-
第一种:如果是点击某个按钮后,才会刷新它的值,其它不用修改,那么不用引用任何按钮,直接在回调时,就已经将接收响应的按钮给传过来了,直接通过它修改即可。
-
第二种:点击某个按钮后,所有与之同类型的按钮都要修改值,那么可以通过在创建按钮时将按钮存入到数组中,在需要的时候遍历查找。
九、线程与进程的区别和联系?
-
一个程序至少要有进城,一个进程至少要有一个线程.
-
进程:资源分配的最小独立单元,进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位.
-
线程:进程下的一个分支,是进程的实体,是CPU调度和分派的基本单元,它是比进程更小的能独立运行的基本单位,线程自己基本不拥有系统资源,只拥有一点在运行中必不可少的资源(程序计数器、一组寄存器、栈),但是它可与同属一个进程的其他线程共享进程所拥有的全部资源。
-
进程和线程都是由操作系统所体会的程序运行的基本单元,系统利用该基本单元实现系统对应用的并发性。
-
进程和线程的主要差别在于它们是不同的操作系统资源管理方式。进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差一些。
-
但对于一些要求同时进行并且又要共享某些变量的并发操作,只能用线程,不能用进程。
多线程编程
-
NSThread
:当需要进行一些耗时操作时会把耗时的操作放到线程中。线程同步:多个线程同时访问一个数据会出问题,NSlock、线程同步块、@synchronized(self){}。 -
NSOperationQueue
操作队列(不需考虑线程同步问题)。编程的重点都放在main里面,NSInvocationOperation
、BSBlockOperation
、自定义Operation。创建一个操作绑定相应的方法,当把操作添加到操作队列中时,操作绑定的方法就会自动执行了,当把操作添加到操作队列中时,默认会调用main方法。 -
GCD(
Grand Central Dispatch
)宏大的中央调度,串行队列、并发队列、主线程队列; -
同步和异步:同步指第一个任务不执行完,不会开始第二个,异步是不管第一个有没有执行完,都开始第二个。
-
串行和并行:串行是多个任务按一定顺序执行,并行是多个任务同时执行;
-
代码是在分线程执行,在主线程嘟列中刷新UI。
多线程编程是防止主线程堵塞、增加运行效率的最佳方法。
-
Apple提供了NSOperation这个类,提供了一个优秀的多线程编程方法;
-
一个NSOperationQueue操作队列,相当于一个线程管理器,而非一个线程,因为你可以设置这个线程管理器内可以并行运行的线程数量等。
-
多线程是一个比较轻量级的方法来实现单个应用程序内多个代码执行路径。
-
iPhoneOS下的主线程的堆栈大小是1M。第二个线程开始就是512KB,并且该值不能通过编译器开关或线程API函数来更改,只有主线程有直接修改UI的能力。
定时器与线程的区别;
- 定时器;可以执行多次,默认在主线程中。
- 线程:只能执行一次。
队列和多线程的使用原理
在iOS中队列分为以下几种:
- 串行队列:队列中的任务只会顺序执行;
dispatch_queue_t q = dispatch_queue_create("...", DISPATCH_QUEUE_SERIAL);
- 并行队列: 队列中的任务通常会并发执行;
dispatch_queue_t q = dispatch_queue_create("......",DISPATCH_QUEUE_CONCURRENT);
- 全局队列:是系统的,直接拿过来(GET)用就可以;与并行队列类似;
dispatch_queue_t q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
- 主队列:每一个应用程序对应唯一主队列,直接GET即可;在多线程开发中,使用主队列更新UI;
dispatch_queue_t q = dispatch_get_main_queue();
-
更多细节见下图:
十、TCP和UDP的区别于联系
-
TCP为传输控制层协议,为面向连接、可靠的、点到点的通信;
-
UDP为用户数据报协议,非连接的不可靠的点到多点的通信;
-
TCP侧重可靠传输,UDP侧重快速传输。
TCP连接的三次握手
-
第一次握手:客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认;
-
第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包,即SYN+ACK包,此时服务器进入SYN+RECV状态;
-
第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次状态。
十一、Scoket连接和HTTP连接的区别:
-
HTTP协议是基于TCP连接的,是应用层协议,主要解决如何包装数据。Socket是对TCP/IP协议的封装,Socket本身并不是协议,而是一个调用接口(API),通过Socket,我们才能使用TCP/IP协议。
-
HTTP连接:短连接,客户端向服务器发送一次请求,服务器响应后连接断开,节省资源。服务器不能主动给客户端响应(除非采用HTTP长连接技术),iPhone主要使用类NSURLConnection。
-
Socket连接:长连接,客户端跟服务器端直接使用Socket进行连接,没有规定连接后断开,因此客户端和服务器段保持连接通道,双方可以主动发送数据,一般多用于游戏.Socket默认连接超时时间是30秒,默认大小是8K(理解为一个数据包大小)。
HTTP协议的特点,关于HTTP请求GET和POST的区别
GET和POST的区别:
-
HTTP超文本传输协议,是短连接,是客户端主动发送请求,服务器做出响应,服务器响应之后,链接断开。HTTP是一个属于应用层面向对象的协议,HTTP有两类报文:请求报文和响应报文。
-
HTTP请求报文:一个HTTP请求报文由请求行、请求头部、空行和请求数据4部分组成。
-
HTTP响应报文:由三部分组成:状态行、消息报头、响应正文。
-
GET请求:参数在地址后拼接,没有请求数据,不安全(因为所有参数都拼接在地址后面),不适合传输大量数据(长度有限制,为1024个字节)。
GET提交、请求的数据会附在URL之后,即把数据放置在HTTP协议头<requestline>中。
以"?"分割URL和传输数据,多个参数用&连接。如果数据是英文字母或数字,原样发送,
如果是空格,转换为+,如果是中文/其他字符,则直接把字符串用BASE64加密。
-
POST请求:参数在请求数据区放着,相对GET请求更安全,并且数据大小没有限制。把提交的数据放置在HTTP包的包体
<request-body>
中. -
GET提交的数据会在地址栏显示出来,而POST提交,地址栏不会改变。
传输数据的大小:
- GET提交时,传输数据就会受到URL长度限制,POST由于不是通过URL传值,理论上书不受限。
安全性:
-
POST的安全性要比GET的安全性高;
-
通过GET提交数据,用户名和密码将明文出现在URL上,比如登陆界面有可能被浏览器缓存。
-
HTTPS:安全超文本传输协议(
Secure Hypertext Transfer Protocol
),它是一个安全通信通道,基于HTTP开发,用于客户计算机和服务器之间交换信息,使用安全套结字层(SSI
)进行信息交换,即HTTP的安全版。
十二、ASIHttpRequest、AFNetWorking之间的区别
-
ASIHttpRequest功能强大,主要是在MRC下实现的,是对系统CFNetwork API进行了封装,支持HTTP协议的CFHTTP,配置比较复杂,并且ASIHttpRequest框架默认不会帮你监听网络改变,如果需要让ASIHttpRequest帮你监听网络状态改变,并且手动开始这个功能。
-
AFNetWorking构建于NSURLConnection、NSOperation以及其他熟悉的Foundation技术之上。拥有良好的架构,丰富的API及模块构建方式,使用起来非常轻松。它基于NSOperation封装的,AFURLConnectionOperation子类。
-
ASIHttpRequest是直接操作对象ASIHttpRequest是一个实现了NSCoding协议的NSOperation子类;AFNetWorking直接操作对象的AFHttpClient,是一个实现NSCoding和NSCopying协议的NSObject子类。
-
同步请求:ASIHttpRequest直接通过调用一个
startSynchronous
方法;AFNetWorking默认没有封装同步请求,如果开发者需要使用同步请求,则需要重写getPath:paraments:success:failures
方法,对于AFHttpRequestOperation进行同步处理。 -
性能对比:AFNetworking请求优于ASIHttpRequest;
十三、XML数据解析方式各有什么不同,JSON解析有哪些框架?
-
XML数据解析的两种解析方式:DOM解析和SAX解析;
-
DOM解析必须完成DOM树的构造,在处理规模较大的XML文档时就很耗内存,占用资源较多,读入整个XML文档并构建一个驻留内存的树结构(节点树),通过遍历树结构可以检索任意XML节点,读取它的属性和值,通常情况下,可以借助XPath查询XML节点;
-
SAX与DOM不同,它是事件驱动模型,解析XML文档时每遇到一个开始或者结束标签、属性或者一条指令时,程序就产生一个事件进行相应的处理,一边读取XML文档一边处理,不必等整个文档加载完才采取措施,当在读取解析过程中遇到需要处理的对象,会发出通知进行处理。因此,SAX相对于DOM来说更适合操作大的XML文档。
-JSON解析:性能比较好的主要是第三方的JSONKIT和iOS自带的JSON解析类,其中自带的JSON解析性能最高,但只能用于iOS5之后。
十四、SVN的使用
-
SVN=版本控制+备份服务器,可以把SVN当成备份服务器,并且可以帮助你记住每次上服务器的档案内容,并自动赋予每次变更的版本;
-
SVN的版本控制:所有上传版本都会帮您记录下来,也有版本分支及合并等功能。SVN可以让不同的开发者存取同样的档案,并且利用SVN Server作为档案同步的机制,即您有档案更新时,无需将档案寄送给您的开发成员。SVN的存放档案方式是采用差异备份的方式,即会备份到不同的地方,节省硬盘空间,也可以对非文字文件进行差异备份。
-
SVN的重要性:备份工作档案的重要性、版本控管的重要性、伙伴间的数据同步的重要性、备份不同版本是很耗费硬盘空间的;
-
防止冲突:
1.防止代码冲突:不要多人同时修改同一文件,例如:A、B都修改同一个文件,先让A修改,然后提交到服务器,然后B更新下来,再进行修改;
2.服务器上的项目文件Xcodeproj,仅让一个人管理提交,其他人只更新,防止文件发生冲突。
十五、如何进行网络消息推送
-
一种是Apple自己提供的通知服务(APNS服务器)、一种是用第三方推送机制。
-
首先应用发送通知,系统弹出提示框询问用户是否允许,当用户允许后向苹果服务器(APNS)请求deviceToken,并由苹果服务器发送给自己的应用,自己的应用将DeviceToken发送自己的服务器,自己服务器想要发送网络推送时将deviceToken以及想要推送的信息发送给苹果服务器,苹果服务器将信息发送给应用。
-
推送信息内容,总容量不超过256个字节;
-
iOS SDK本身提供的APNS服务器推送,它可以直接推送给目标用户并根据您的方式弹出提示。
优点:不论应用是否开启,都会发送到手机端;
缺点:消息推送机制是苹果服务端控制,个别时候可能会有延迟,因为苹果服务器也有队列来处理所有的消息请求; -
第三方推送机制,普遍使用Socket机制来实现,几乎可以达到即时的发送到目标用户手机端,适用于即时通讯类应用。
优点:实时的,取决于心跳包的节奏;
缺点:iOS系统的限制,应用不能长时间的后台运行,所以应用关闭的情况下这种推送机制不可用。
923910776最后,给大家推荐一个iOS技术交流群,不管你在地球哪个方位,不管你参加工作几年都欢迎你的入驻!(群内会免费提供一些群主收藏的免费学习书籍资料以及整理好的几百道面试题和答案文档!)
网友评论