高级面试题

多线程的底层实现
1> 首先搞清楚什么是线程、什么是多线程、多线程的使用场合
2> Mach是第一个以多线程方式处理任务的系统,因此多线程的底层实现机制是基于Mach的线程
3> GCD 和 NSOperationQueue 区别。
•NSThread:
–优点:NSThread 比其他两个轻量级,使用简单
–缺点:需要自己管理线程的生命周期、线程同步、加锁、睡眠以及唤醒等。线程同步对数据的加锁会有一定的系统开销

•NSOperation:
–不需要关心线程管理,数据同步的事情,可以把精力放在自己需要执行的操作上
–NSOperation是面向对象的

•GCD:
–Grand Central Dispatch是由苹果开发的一个多核编程的解决方案。iOS4.0+才能使用,是替代NSThread, NSOperation的高效和强大的技术
–GCD是基于C语言的
4> 分发源 和 分发队列 . dispatch source监听事件(线程间
通信)。当这些事件发生时,它自动将一个block放入一个dispatch queue的执行例程中。
5> 开发中实现多线程的方案
C语言的POSIX接口:#include <pthread.h>
OC的NSThread
C语言的GCD接口(性能最好,代码更精简)
OC的NSOperation和NSOperationQueue(基于GCD)
6> 为什么UI必须在主线程 [主线程又叫UI线程]
项目经理是主线程,程序员是子线程,那么程序员完成任务后需要通知经理【否则经理不知道,那么经理就无法整合代码了】
有时候可以在子线程刷新UI,【注意:只是有时候可以】为了避免这种情况,我们必须在主线程刷新UI,子线程会和主线程交流的,但什么时候交流是不确定的,我们无法知晓具体时间
7>线程间怎么通信
1. GCD dispatch_async(dispatch_get_main_queue)回到主线程
2. performSelector:onThread:withObject:waitUntilDone:
   performSelectorOnMainThread:withObject:waitUntilDone:
1. NSMachPort(可选)

网络图片处理问题中怎么解决一个相同的网络地址重复请求的问题
利用字典(图片地址为key,下载操作为value)
这里其实问的是SDWebImage,关于图片处理,SDWebImage已经帮我们处理过了,下载之前他会先到缓存中查找,如果有就会直接拿来用,没有就去下载



列举cocoa中常见对几种多线程的实现,并谈谈多线程安全的几种解决办法及多线程安全怎么控制?
1> 只在主线程刷新访问UI
2> 如果要防止资源抢夺,得用@synchronized进行加锁保护
3> 如果异步操作要保证线程安全等问题, 尽量使用GCD(有些函数默认就是安全的)
4> 注意
1. dispatch_sync(dispatch_get_mian_queue)
     ^{  
1. nslog(@“-----”)

      }   
在主线程中执行就会造成死锁。
1. 2 的前提是1 已经执行完毕,但是1执行完毕的前提是2 执行完毕 ,由此就造成了死锁。
备注:sync是同步的,而且他代表的是当前线程【可能是主线程也可能是子线程】如果是代表主线程那么sync 会等到 后面block 执行完成才返回, sync 又再 dispatch_get_main_queue() 队列中,它是串行队列,sync 是后加入的,前一个是主线程,所以 sync 想执行 block 必须等待主线程执行完成,主线程等待 sync 返回,去执行后续内容。照成死锁,sync 等待mainThread 执行完成,mianThread 等待sync 函数返回。


GCD内部怎么实现的
1> iOS和OS X的核心是XNU内核,GCD是基于XNU内核实现的
2> GCD的API全部在libdispatch库中
3> GCD的底层实现主要有Dispatch Queue和Dispatch Source
Dispatch Queue :管理block(操作)
Dispatch Source :处理事件(比如线程间的通信,新线程)

你为什么要使用NSOperationQueue,实现了什么?请描述它和GCD的区别和类似的地方
1> GCD是纯C语言的API 封装在libdispatch库
     NSOperationQueue是基于GCD的OC版本封装
2> GCD只支持FIFO的队列
     NSOperationQueue可以很方便地调整执行顺序、设置最大并发数量
3> NSOperationQueue可以在轻松在Operation间设置依赖关系
     GCD需要写很多的代码才能实现
4> NSOperationQueue支持KVO,可以监测operation是否正在执行(isExecuted)、是否结束(isFinished),是否取消(isCanceld)
建一个Person类:
@interface Person : NSObject
@property (copy, nonatomic) NSString *name;
@property(assign, nonatomic) int;
在控制器中: age;
Person *p = [[Person alloc]init];
p.name = @"jack";
p.age = 18;
// 注册KVO
[p addObserver:self forKeyPath:@“name" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
p.name = @"rose";
self.person = p;
p的name属性发生变化就会调用这个方法
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    NSLog(@"%@",change);
}
补充
// 注册KVO
(void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context;
//解除KVO
• (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath;
值得注意的是:不要忘记解除注册,否则会导致资源泄露。

5> GCD的执行速度比NSOperationQueue快

任务之间不太互相依赖:GCD
任务之间有依赖\或者要监听任务的执行情况:NSOperationQueue

在使用GCD以及block时要注意些什么?它们两是一回事儿么?block在ARC中和传统的MRC中的行为和用法有没有什么区别,需要注意些什么?
block 底层: 结构体指针
block 原理 :没有__block修饰的变量是值传递(闭包)
                   有__block修饰的变量地址传递  【有__block 修饰的变量我们才能在block内部修改它   作用 : 1  逆传值    从控制器A 跳转到 控制器B,而A需要B里边的东西,这个时候就用到逆传值了
1. 保存代码
2. 回调
Block的使用注意:
block的内存管理
防止循环retian
      为什么会循环retain(在block块里使用self,会对self有个强指针)
      一般用copy修饰block来将block从栈中移到堆中,如果用copy,则self会对block有一个强指针,而在block中又使用了self,那么block会对self有一个强指针。
MRC:__block
ARC:__weak\__unsafe_unretained
1. 对Block不管是retain、copy、release都不会改变引用计数retainCount,retainCount始终是1
在异步线程中下载很多图片,如果失败了,该如何处理?请结合RunLoop来谈谈解决方案.(提示:在异步线程中启动一个RunLoop重新发送网络请求,下载图片)
1>   重新下载图片(多次下载)
2>下载完毕,利用RunLoop的输入源回到主线程刷新UIImageView(performSelectorOnMainThread)
关于RunLoop
RunLoop从字面上看是运行循环的意思,准确的说是线程中的循环。
有些线程执行的任务是一条直线,起点到终点——-如简单HelloWorld,运行打印完,它的生命周期便结束了

而另一些线程要干的活则是一个圆,不断循环,直到通过某种方式将它终止。—操作系统,一直运行直到你关机,圆型的线程就是通过run loop不停的循环实现的。

首先循环体的开始需要检测是否有需要处理的事件,如果有则去处理,如果没有则进入睡眠以节省CPU时间。 所以重点便是这个需要处理的事件,在RunLoop中,需要处理的事件分两类,一种是输入源,一种是定时器,
定时器
好理解就是那些需要定时执行的操作
输 入源分三类:
performSelector源
基于端口(Mach port)的源
自定义的源。
RunLoop有一个观察者Observer的概念,可以往RunLoop中加入自己的 观察者以便监控着RunLoop的运行过程
 另外RunLoop中还有一个运行模式的概念,每一个运行循环必然运行在某个模式下,而模式的存在是为了过滤事件源和观察者的,只有那些和当前 RunLoop运行模式一致的事件源和观察者才会被激活。


在一个线程中我们需要做的事情并不单一,如需要处理定时钟事件,需要处理用户的触控事件,需要接受网络远端发过来的数据,将这些需要做的事情统统注 册到事件源中,每一次循环的开始便去检查这些事件源是否有需要处理的数据,有的话则去处理。 
拿具体的应用举个例子,NSURLConnection网络数据请求,默认是异步的方式,其实现原理就是创建之后将其作为事件源加入到当前的 RunLoop,而等待网络响应以及网络数据接受的过程则在一个新创建的独立的线程中完成,当这个线程处理到某个阶段的时候比如得到对方的响应或者接受完 了网络数据之后便通知之前的线程去执行其相关的delegate方法。

每一个线程都有其对应的RunLoop,但是默认非主线程的RunLoop是没有运行的,需要为RunLoop添加至少一个事件源,然后去run它。一般情况下我们是没有必要去启用线程的RunLoop的,除非你在一个单独的线程中需要长久的检测某个事件。
Run loop同时也负责autorelease pool的创建和释放
在使用手动的内存管理方式的项目中,会经常用到很多自动释放的对象,如果这些对象不能够被即时释放掉,会造成内存占用量急剧增大。Run loop就为我们做了这样的工作,每当一个运行循环结束的时候,它都会释放一次autorelease pool,同时pool中的所有自动释放类型变量都会被释放掉。


Run loop的优点
一个run loop就是一个事件处理循环,用来不停的监听和处理输入事件并将其分配到对应的目标上进行处理。如果仅仅是想实现这个功能,你可能会想一个简单的while循环不就可以实现了吗,用得着费老大劲来做个那么复杂的机制?显然,苹果的架构设计师不是吃干饭的,你想到的他们早就想过了。
首先,NSRunLoop是一种更加高明的消息处理模式,他就高明在对消息处理过程进行了更好的抽象和封装,这样才能使得你不用处理一些很琐碎很低层次的具体消息的处理,在NSRunLoop中每一个消息就被打包在input source或者是timer source(见后文)中了。
其次,也是很重要的一点,使用run loop可以使你的线程在有工作的时候工作,没有工作的时候休眠,这可以大大节省系统资源。

Run loop相关知识点

Run loop接收输入事件来自两种不同的来源:输入源(input source)和定时源(timer source)。两种源都使用程序的某一特定的处理例程来处理到达的事件。图-1显示了run loop的概念结构以及各种源。






 Socket的实现原理及Socket之间是如何通信的
Socket用于网络中进程通讯
 一般基于TCP/IP,UDP,常链接,时时保持通讯(取决于协议)
TCP/IP 【端对端: 一个对一个】比较安全,不会出现丢包现象,只要发了就一定会收到
UDP     【广播式协议: 一对多】容易出现丢包现象,只管发,不管你收没收到
长连接与短连接  
长连接 指在一个TCP连接上可以连续发送多个数据包,在TCP连接保持期间,如果没有数据包发送,需要双方发检测包以维持此连接,一般需要自己做在线维持。 
长连接操作过程: 
  连接→数据传输→保持连接(心跳)→数据传输→保持连接(心跳)→……→关闭连接; 
短连接 是指通信双方有数据交互时,就建立一个TCP连接,数据发送完成后,则断开此TCP连接,一般银行都使用短连接。
短连接操作步骤是: 
  连接→数据传输→关闭连接;  
什么时候用长连接,短连接?
长连接多用于操作频繁,点对点的通讯,而且连接数不能太多情况
每个TCP连接都需要三步握手,这需要时间,如果每个操作都是先连接,再操作的话那么处理速度会降低很多,
所以每个操作完后都不断开,下次次处理时直接发送数据包就OK了,不用建立TCP连接。

一般银行都使用短连接。

例如:数据库的连接用长连接, 
如果用短连接频繁的通信会造成socket错误,而且频繁的socket 创建也是对资源的浪费。
 http协议的实现 
HTTP的概念: 全称是Hypertext Transfer Protocol,超文本传输协议
(1)规定客户端和服务器之间的数据传输格式
(2)让客户端和服务器能有效地进行数据沟通

为什么选择使用HTTP:
(1)简单快速  因为HTTP协议简单,所以HTTP服务器的程序规模小,因而通信速度很快
(2)灵活  HTTP允许传输任意类型的数据
(3)HTTP 0.9和1.0使用非持续连接  限制每次连接只处理一个请求,服务器对客户端的请求做出响应后,马上断开连接,这种方式可以节省传输时间
HTTP的通信过程
(1)请求:客户端向服务器索要数据


请求行:包含了请求方法、请求资源路径、HTTP协议版本
GET /MJServer/resources/images/1.jpg HTTP/1.1


请求头:包含了对客户端的环境描述、客户端请求的主机地址等信息
1.  192.168.1.105:8080 // 客户端想访问的服务器主机地址
2. er-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9) Firefox/30.0// 客户端的类型,客户端的软件环境
Accept: text/html, */*// 客户端所能接收的数据类型
Accept-Language: zh-cn // 客户端的语言环境
Accept-Encoding: gzip // 客户端支持的数据压缩格式
请求体:客户端发给服务器的具体数据,比如文件数据

(2)响应:服务器返回客户端相应的数据
状态行:包含了HTTP协议版本、状态码、状态英文名称
1. TP/1.1 200 OK
响应头:包含了对服务器的描述、对返回数据的描述
1. rver: Apache-Coyote/1.1 // 服务器的类型
Content-Type: image/jpeg // 返回数据的类型
1. t-Length: 56811 // 返回数据的长度
2. e: Mon, 23 Jun 2014 12:54:52 GMT // 响应的时间
实体内容:服务器返回给客户端的具体数据,比如文件数据       

 iOS中发送HTTP请求的方案
在iOS中,常见的发送HTTP请求(GET和POST)的解决方案有
(1)苹果原生(自带)
NSURLConnection:用法简单,最古老最经典最直接的一种方案
NSURLSession:iOS 7新出的技术,功能比NSURLConnection更加强大
CFNetwork:NSURL*的底层,纯C语言
(2)第三方框架
ASIHttpRequest:外号“HTTP终结者”,功能极其强大,可惜早已停止更新
AFNetworking:简单易用,提供了基本够用的常用功能
ASI和AFN架构对比

说明:AFN基于NSURL,ASI基于CFHTTP,ASI的性能更好一些。



怎么保证多人开发进行内存泄露的检查
使用Analyze进行代码的静态分析(检测有无潜在的内存泄露)
通过profile –> leak检查在程序运行过程中有无内存泄露     
使用ARC

2.非自动内存管理情况下怎么做单例模式.
创建单例设计模式的基本步骤 ·
>声明一个单例对象的静态实例,并初始化为nil。 
• satic Person * Person= nil;
>创建一个类的类工厂方法里面加锁实现【可以用NSLock/ NSCondiction/@synchronized 这里我们直接用dispatch_once因为里面自动加锁而且只调用一次】
类方法: +(instance)sharePerson;
>重写allocWithZone:方法和copyWithZone:方法,确保用户在直接分配和初始化对象时,不会产 生另一个对象。 
>重写release、autorelease、retain、retainCount方法, 以此确保单例的状态。 
具体如下:
#import <foundation foundation.h="">
@interface Singleton : NSObject
+(instancetype) shareInstance ;
@end

#import "Singleton.h"
@implementation Singleton
• atic Singleton* _instance = nil;
+(instancetype) shareInstance
{
    static dispatch_once_t onceToken ;
    dispatch_once(&onceToken, ^{
        _instance = [[super allocWithZone:NULL] init] ;
    }) ;
    return _instance ;
}
+(id) allocWithZone:(struct _NSZone *)zone
{
    return [Singleton shareInstance] ;
}
-(id) copyWithZone:(struct _NSZone *)zone
{
    return [Singleton shareInstance] ;
}
@end

#import <foundation foundation.h="">
#import "Singleton.h"

• t main(int argc, const char * argv[]) {
    @autoreleasepool {

• ngleton* obj1 = [Singleton shareInstance] ;
• Log(@"obj1 = %@.", obj1) ;
• ngleton* obj2 = [Singleton shareInstance] ;
• Log(@"obj2 = %@.", obj2) ;

• ngleton* obj3 = [[Singleton alloc] init] ;
• Log(@"obj3 = %@.", obj3) ;

• ngleton* obj4 = [[Singleton alloc] init] ;
• Log(@"obj4 = %@.", [obj4 copy]) ;
    }
    return 0;
}</foundation>
输出结果是一样的,即获取的对象是一样的


3.对于类方法(静态方法)默认是autorelease的。所有类方法都会这样吗?
1> 系统自带的绝大数类方法返回的对象,都是经过autorelease的

4.block在ARC中和MRC中的用法有什么区别,需要注意什么
1>不管是ARC和MRC,block都应该用copy操作来持有
2>应注意避免循环引用
ARC: __weak、__unscafe_unretained
MRC:__block

5.什么情况下会发生内存泄漏和内存溢出?
1> 内存泄露:该释放的没有释放内存泄露会最终会导致内存溢出!
2>内存溢出:当程序在申请内存时,没有足够的内存空间供其使用,出现out of memory;比如申请了一个int,但给它存了long才能存下的数,那就是内存溢出。

6.[NSArray arrayWithobject:<id>] 这个方法添加对象后,需要对这个数组做释放操作吗?
    不需要 这个对象被放到自动释放池中 

7.Json数据的解析,和解析数据的时候有内存泄露吗?有的话 如何解决        
JSON解析的方案
苹果原生  NSJSONSerialization (无需导入包,IOS5支持,低版本IOS不支持)
1. NSError *error;
2. //加载一个NSURL对象
3. NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://m.weather.com.cn/data/101180601.html"]];
4. //将请求的url数据放到NSData对象中
5. NSData *response = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
6. //IOS5自带解析类NSJSONSerialization从response中解析出数据放到字典中
7. NSDictionary *weatherDic = [NSJSONSerialization JSONObjectWithData:response options:NSJSONReadingMutableLeaves error:&error];


第三方【TouchJson、 SBJson 、JSONKit】
TouchJson (需导入包:#import “TouchJson/JSON/CJSONDeserializer.h")

1. //获取API接口
2. NSURL *url = [NSURL URLWithString:@"http://m.weather.com.cn/data/101010100.html"];
3. //定义一个NSError对象,用于捕获错误信息
4. NSError *error;          NSString *jsonString = [NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:&error];
5. //将解析得到的内容存放字典中,编码格式为UTF8,防止取值的时候发生乱码
6. NSDictionary *rootDic = [[CJSONDeserializer deserializer] deserialize:[jsonString dataUsingEncoding:NSUTF8StringEncoding] error:&error];
7. //因为返回的Json文件有两层,去第二层内容放到字典中去
8. NSDictionary *weatherInfo = [rootDic objectForKey:@"weatherinfo"];
9. NSLog(@"weatherInfo--->%@",weatherInfo);
10. //取值打印
11. txtView.text = [NSString stringWithFormat:@"今天是 %@  %@  %@  的天气状况是:%@  %@ ",[weatherInfo objectForKey:@"date_y"],[weatherInfo objectForKey:@"week"],[weatherInfo objectForKey:@"city"], [weatherInfo objectForKey:@"weather1"], [weatherInfo objectForKey:@"temp1"]];
    14          
SBJson  (需导入包:#import "SBJson/SBJson.h")
1. NSURL *url = [NSURL URLWithString:@"http://m.weather.com.cn/data/101180701.html"];
2. NSError *error = nil;
3. NSString *jsonString = [NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:&error];
4. SBJsonParser *parser = [[SBJsonParser alloc] init];
    5          
1. NSDictionary *rootDic = [parser objectWithString:jsonString error:&error];
2. NSDictionary *weatherInfo = [rootDic objectForKey:@"weatherinfo"];
3. txtView.text = [NSString stringWithFormat:@"今天是 %@  %@  %@  的天气状况是:%@  %@ ",[weatherInfo objectForKey:@"date_y"],[weatherInfo objectForKey:@"week"],[weatherInfo objectForKey:@"city"], [weatherInfo objectForKey:@"weather1"], [weatherInfo objectForKey:@"temp1"]];
4. }
JSONKit 不支持ARC(需导入包:#import “JSONKit/JSONKit.h")
1. //如果json是“单层”的,即value都是字符串、数字,可以使用objectFromJSONString
2. NSString *json1 = @"{\"a\":123, \"b\":\"abc\"}";
1. Dictionary *data1 = [json1 objectFromJSONString];

    //如果json有嵌套,即value里有array、object,如果再使用objectFromJSONString,程序可能会报错(测试结果表明:使用由网络或得到的php/json_encode生成的json时会报错,但使用NSString定义的json字符串时,解析成功),最好使用objectFromJSONStringWithParseOptions:  
1. String *json2 = @"{\"a\":123, \"b\":\"abc\", \"c\":[456, \"hello\"], \"d\":{\"name\":\"张三\", \"age\":\"32\"}}";

1. Dictionary *data2 = [json2 objectFromJSONStringWithParseOptions:JKParseOptionLooseUnicode];
    // 记住释放用来保存解析后数据的数组
1. son2 release];

1. 自动释放池底层怎么实现
自动释放池以栈的形式实现:当你创建一个新的自动释放池时,它将被添加到栈顶。当一个对象收到发送autorelease消息时,它被添加到当前线程的处于栈顶的自动释放池中,当自动释放池被回收时,它们从栈中被删除, 并且会给池子里面所有的对象都会做一次release操作.
自动释放池什么时候会进行回收:在那个大括号执行完毕就会释放回收


KVO内部实现原理
KVO是基于runtime机制实现的
当某个类的对象第一次被观察时, 系统就会在运行期动态地创建该类的一个派生类【就是子类】,在这个派生类中重写基类中任何被观察属性的 setter 方法。 
 NSKVONotifying_Person)◊派生类在被重写的 setter 方法实现真正的通知机制(Person


上图中的NSKVONotifitying_Person就是动态创建的派生类


是否可以把比较耗时的操作放在NSNotificationCenter中
如果在异步线程发的通知,那么可以执行比较耗时的操作;
如果在主线程发的通知,那么就不可以执行比较耗时的操作

3.Foundation对象与Core Foundation对象有什么区别
1> Foundation对象是OC的,Core Foundation对象是C对象
2> Foundation对象和Core Foundation对象是可以互相转换的,数据类型之间的转换
ARC:__bridge_retained、__bridge_transfer
非ARC: __bridge

4.不用中间变量,用两种方法交换A和B的值
A = A + B
• = A - B
• = A - B
或者
A = A^B;
B = A^B;
A = A^B;

6.什么是动态,举例说明
1> 在程序运行过程才执行的操作
2>动态绑定    
3>runtime

7.runtime实现的机制是什么,怎么用,一般用于干嘛. 你还能记得你所使用的相关的头文件或者某些方法的名称吗? 
作用
获取类里面的所有成员变量【归档】
为类动态添加成员变量,
动态改变类的方法实现,
为类动态添加新的方法等 
需要导入<objc/message.h><objc/runtime.h>
runtime,运行时机制,它是一套C语言库
• OC代码,最终都是转成了runtime库的东西,比如类转成了结构体等数据类型,方法转成函数,平时调方法都是转成了objc_msgSend函数(所以说OC有个消息发送机制)[p setName:]; --- > objc_msgSend(p, selector(setName:),);
• 拿到所有成员变量,进行归档。Class_copyIvarList([Person class], &count)
• swizzel;  imageWithName,里面判断如果是iOS7,在name图片名后拼接“_os7”,然后image = [UIImage  ImageName:name];不是iOS7,直接image = [UIImage  ImageName:name];返回image即可;但是如果没有用分类方法处理图片,要么一个一个换成ImageWithName,要么swizzle将ImageName方法的实现换成IamgeWithName;表面上调用ImageNamed, 实际上用的ImageWithName。
2.为了避免数组不能存nil.给可变数组(Foundation)弄个分类
也可以如果是字符串再添加,避免数组越界;换objectAtIndex;
总结:


CoreText 【就是富文本—用NSAttributedString这个类来做富文本】
随意修改文本的样式
图文混排(纯C语言)
国外:Niumb
Core Image(滤镜处理)
• 能调节图片的各种属性(饱和度, 色温, 色差等) 美图秀秀用到这个

9.NSNotification和KVO的区别和用法是什么?
什么时候应该使用通知,什么时候应该使用KVO,它们的实现上有什么区别吗?如果用protocol和delegate(或者delegate的Array)来实现类似的功能可能吗?如果可能,会有什么潜在的问题?如果不能,为什么?(虽然protocol和delegate这种东西面试已经面烂了…)
通知比较灵活(1个通知能被多个对象接收, 1个对象能接收多个通知), 

代理比较规范,但是代码多(默认是1对1)但是也能有多个代理,就是让代理都遵守同一份协议

KVO性能不好(底层会动态产生新的类),只能监听某个对象属性的改变, 不推荐使用(1个对象的属性能被多个对象监听,  1个对象能监听多个对象的其他属性)

更详细参考:
http://blog.csdn.net/dqjyong/article/details/7685933

谈谈你对KVC 与 KVO 理解
KVC,即是指 NSKeyValueCoding,一个非正式的 Protocol,提供一种机制来间接访问对象的属性。KVO 就是基于 KVC 实现的关键技术之一。

KVC 运用的技术
• C运用了一个isa- swizzling技术。isa-swizzling就是类型混合指针机制。KVC主要通过isa- swizzling,来实现其内部查找定位的。
isa指针,如其名称所指,(就是is a kind of的意思),指向维护分发表的对象的类。该分发表实际上包含了指向实现类中的方法的指针,和其它数据。
KVC实例:
一个对象拥有某些属性。比如说,一个 Person 对象有一个 name 和一个 address 属性。以 KVC 说法,Person 对象分别有一个 value 对应他的 name 和 address 的 key。 key 只是一个字符串,它对应的值可以是任意类型的对象。从最基础的层次上看,KVC 有两个方法:一个是设置 key 的值,另一个是获取 key 的值。如下面的例子
void changeName(Person *p, NSString *newName)
{

    // using the KVC accessor (getter) method
    NSString *originalName = [p valueForKey:@"name"];

    // using the KVC  accessor (setter) method.
    [p setValue:newName forKey:@"name"];

    NSLog(@"Changed %@'s name to: %@", originalName, newName);

}
现在,如果 Person 有另外一个 key 配偶(spouse),spouse 的 key 值是另一个 Person 对象,用 KVC 可以这样写:


void logMarriage(Person *p)
{

    // just using the accessor again, same as example above
    NSString *personsName = [p valueForKey:@"name"];

    // this line is different, because it is using
    // a "key path" instead of a normal "key"
    NSString *spousesName = [p valueForKeyPath:@"spouse.name"];

    NSLog(@"%@ is happily married to %@", personsName, spousesName);

}
key 与 key path 要区分开来,key 可以从一个对象中获取值,而 key path 可以将多个 key 用点号 “.” 分割连接起来,比如:
[p valueForKeyPath:@"spouse.name"];
相当于这样……
[[p valueForKey:@"spouse"] valueForKey:@"name"];

Key-Value Observing (KVO) 建立在 KVC 之上,它能够观察一个对象的 KVC key path 值的变化。
优点 
当 有属性改变,KVO会提供自动的消息通知。这样的架构有很多好处。首先,开发人员不需要自己去实现这样的方案:每次属性改变了就发送消息通知。这是KVO机制提供的最大的优点。因为这个方案已经被明确定义,获得框架级支持,可以方便地采用。开发人员不需要添加任何代码,不需要设计自己的观察者模型,直接可以在工程里使用。其次,KVO的架构非常的强大,可以很容易的支持多个观察者观察同一个属性,以及相关的值。
使用方法
1. 注册,指定被观察者的属性
2. 实现回调方法
3. 移除观察
注意
只有符合KVC标准的对象才能使用kvo
KVO实例:
假设一个场景,股票的价格显示在当前屏幕上,当股票价格更改的时候,实时显示更新其价格。
1.定义DataModel,

1. @interface StockData : NSObject {
2.     NSString * stockName;
3. float price;
4. }
5. @end
6. @implementation StockData
7. @end

2.定义此model为Controller的属性,实例化它,监听它的属性,并显示在当前的View里边
[cpp] view plaincopy

• - (void)viewDidLoad
• {
• [super viewDidLoad];
    4      
1. stockForKVO = [[StockData alloc] init];
2. [stockForKVO setValue:@"searph" forKey:@"stockName"];
3. [stockForKVO setValue:@"10.0" forKey:@"price"];
4. [stockForKVO addObserver:self forKeyPath:@"price" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:NULL];
    9      
1. myLabel = [[UILabel alloc]initWithFrame:CGRectMake(100, 100, 100, 30 )];
2. myLabel.textColor = [UIColor redColor];
3. myLabel.text = [stockForKVO valueForKey:@"price"];
4. [self.view addSubview:myLabel];
    14         
•         UIButton * b = [UIButton buttonWithType:UIButtonTypeRoundedRect];
• b.frame = CGRectMake(0, 0, 100, 30);
• [b addTarget:self action:@selector(buttonAction) forControlEvents:UIControlEventTouchUpInside];
• [self.view addSubview:b];
    19      
1. }

3.当点击button的时候,调用buttonAction方法,修改对象的属性

[cpp] view plaincopy

1. -(void) buttonAction
2. {
3. [stockForKVO setValue:@"20.0" forKey:@"price"];
4. }

1. 实现回调方法
[cpp] view plaincopy

1. -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
2. {
3. if([keyPath isEqualToString:@"price"])
4. {
5. myLabel.text = [stockForKVO valueForKey:@"price"];
6. }
7. }

5.增加观察与取消观察是成对出现的,所以需要在最后的时候,移除观察者

• - (void)dealloc
• {
• [super dealloc];
• [stockForKVO removeObserver:self forKeyPath:@"price"];
• [stockForKVO release];
• }

KVB:Key Value Binding  键值绑定【补充内容】
KVB实现的两个基本方法
• 为对象添加观察者OBserver  --  addObserver:forKeyPath:options:context:
• )观察者OBserver收到信息的处理函数 -- observerValueForKeyPath:ofObject:change:context:

KVO和KVB最明显的使用场景就是在一些界面实现变化很强的敌方。例如股票走向、售票余数等,可及时更改参数变化情况。





CAAnimation的层级结构

如果使用CAAnimation
创建CAAnimation对象
设置CAAnimation对象的属性
添加CAAnimation对象到CALayer上,CALayer就会自动执行这个动画

UIButton与UITableView的层级结构
层级结构  label  UIImage  NSObjcet->UIResponder->UIView->UIControl->UIButton
内部的子控件结构    cell 分割线  UIView->UIScrollView>UITableView
  设置scroll view的contensize能在Viewdidload里设置么,为什么
1. ,可能不太安全。子控制器的frame在viewDidLoad和ViewWillAppear时可能不一样,如果scrollView的contentSize = 375 是基于子控制器的View(等于),当子控制器变小时,contentSize就变小了。




按钮或者其它UIView控件的事件传递的具体过程

UIResponder有一个nextResponder属性,通过该属性可以组成一个响应者链,事件或消息在其路径上进行传递
如果UIResponder没有处理传给它的事件,会将未处理的消息转发给自己的nextResponder




控制器View的生命周期及相关函数是什么?你在开发中是如何用的?
• 1.首先判断控制器是否有视图,如果没有就调用loadView方法创建:通过storyboard或者代码;
• 2.随后调用viewDidLoad,可以进行下一步的初始化操作;只会被调用一次;
• 3.在视图显示之前调用viewWillAppear;该函数可以多次调用;
• 4.视图viewDidAppear

• 3.在视图显示之前调用viewWillDisappear;该函数可以多次调用;
如需要);
• 5.在布局变化前后,调用viewWill/DidLayoutSubviews处理相关信息;
6.viewWillDisappear ViewDidDisappear   
8.父子关系  
1.控制器 子控制器调用navigationController 会看一下当前控制器是否在一个导航控制器里面,在就把这个导航控制器拿过来,没有就看一下父控制器是否在导航控制器里,再拿来
2.旋转屏幕默认只有window的rootViewController才会旋转,只有具备父子关系,子控制器才会触发旋转方法。
1. NSRunLoop的实现机制,及在多线程中如何使用

NSRunLoop是IOS消息机制的处理模式
>作用:控制NSRunLoop里面线程的执行和休眠,
>NSRunLoop 就是一直在循环检测,从线程start到线程end,检测inputsource(如点击,双击等操作)异步事件,检测timesource同步事件,检测到输入源会执行处理函数,首先会产生通知,core function向线程添加runloop observers来监听事件,意在监听事件发生时来做处理。
>3.runloopmode是一个集合,包括监听:事件源,定时器,以及需通知的runloop observers

1.  只有在为你的程序创建次线程的时候,才需要运行run loop。对于程序的主线程而言,run loop是关键部分。Cocoa提供了运行主线程run loop的代码同时也会自动运行run loop。IOS程序UIApplication中的run方法在程序正常启动的时候就会启动run loop。如果你使用xcode提供的模板创建的程序,那你永远不需要自己去启动run loop
2.  在多线程中,你需要判断是否需要run loop。如果需要run loop,那么你要负责配置run loop并启动。你不需要在任何情况下都去启动run loop。比如,你使用线程去处理一个预先定义好的耗时极长的任务时,你就可以毋需启动run loop。Run loop只在你要和线程有交互时才需要


3简单说一下APP的启动过程,从main文件开始说起
    程序启动分为两类:1.有storyboard 2.没有storyboard
有storyboard情况下:
1.main函数
2.UIApplicationMain
• 创建UIApplication对象
• 创建UIApplication的delegate对象
3.根据Info.plist获得最主要storyboard的文件名,加载最主要的storyboard(有storyboard)
• 创建UIWindow
• 创建和设置UIWindow的rootViewController
• 显示窗口

没有storyboard情况下:
1.main函数
2.UIApplicationMain
• 创建UIApplication对象
• 创建UIApplication的delegate对象
3.delegate对象开始处理(监听)系统事件(没有storyboard)
• 程序启动完毕的时候, 就会调用代理的application:didFinishLaunchingWithOptions:方法
• 在application:didFinishLaunchingWithOptions:中创建UIWindow
• 创建和设置UIWindow的rootViewController
• 显示窗口

4把程序自己关掉和程序进入后台,远程推送的区别
1. 关掉后不执行任何代码, 不能处理事件
2. 应用程序进入后台状态不久后转入挂起状态。在这种状态下,应用程序不执行任何代码,并有可能在任意时候从内存中删除。只有当用户再次运行此应用,应用才会从挂起状态唤醒,代码得以继续执行
3.或者进入后台时开启多任务状态,保留在内存中,这样就可以执行系统允许的动作
4.远程推送是由远程服务器上的程序发送到APNS,再由APNS把消息推送至设备上的程序,当应用程序收到推送的消息会自动调用特定的方法执行事先写好的代码
5(void)application:(UIApplication*)application   didReceiveRemoteNotification:(NSDictionary*)userInfo 

{// alert   // 前台
 
if (application.applicationState == UIApplicationStateActive) { 

        UILocalNotification *notification=[[UILocalNotification alloc] init]; 
        
if(notification!=nil){ 
NSDate*date=[NSDate dateWithTimeIntervalSinceNow:10]; 


         notification.fireDate=date ; 
          
notification.timeZone=[NSTimeZone defaultTimeZone];
           
notification.alertBody= [[userInfo objectForKey:@"aps"] objectForKey:@"alert"]; 

notification.soundName= UILocalNotificationDefaultSoundName;  

notification.userInfo = userInfo;

[[UIApplicationsharedApplication] scheduleLocalNotification:notification]; 
[self playSound]; 



5本地通知和远程推送通知对基本概念和用法?





键盘呼出时的通知

  // 注册通知
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textChange) name:UITextViewTextDidChangeNotification object:textView];
       // 监听键盘的弹出的隐藏
    // 监听键盘弹出和退下
    [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
    [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
-(void)keyboardWillShow:(NSNotification *)noti
{
    // 取出键盘弹出的时间
    CGFloat duration = [noti.userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue];

    // 取出键盘高度
    CGRect keyBoardRect = [noti.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
    CGFloat keyBoardHeight = keyBoardRect.size.height;

1. IView animateWithDuration:duration delay:0.0 options:7 << 16 animations:^{
        self.toolBar.transform = CGAffineTransformMakeTranslation(0, -keyBoardHeight);

    } completion:^(BOOL finished) {

    }];

}

-(void)keyboardWillHide:(NSNotification *)noti
{
    // 取出键盘隐藏的时间
    CGFloat duration = [noti.userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue];
    // 清空transform
    [UIView animateWithDuration:duration animations:^{
        self.toolBar.transform = CGAffineTransformIdentity;
    }];

1. IView animateWithDuration:duration delay:0.0 options:7 << 16 animations:^{
         self.toolBar.transform = CGAffineTransformIdentity;

    } completion:^(BOOL finished) {

    }];

}

copy、retain、assign、strong、weak怎样用,如何区别,原子性和非原子性的区别
 声明property的语法为:@property (参数1,参数2) 类型 名字;

其中参数主要分为三类:

读写属性: (readwrite/readonly)
setter语意:(assign/retain/copy)
原子性: (atomicity/nonatomic)

各参数意义如下:

readwrite: 产生setter\getter方法
readonly: 只产生简单的getter,没有setter。
assign: 默认类型,setter方法直接赋值,而不进行retain操作  一般基本数据类型用该属性声明,比如,int, BOOL。
retain: setter方法对参数进行release旧值,再retain新值。 该属性与 strong 一致;只是可读性更强一些。
copy: setter方法进行Copy操作,与retain一样        与 strong 的区别是声明变量是拷贝对象的持有者。
nonatomic: 禁止多线程,变量保护,提高性能
weak:该属性与 strong 一致;只是可读性更强一些。

如果使用多线程,有时会出现两个线程互相等待对方导致锁死的情况(在没有(nonatomic)的情况下,即默认(atomic),会防止这种线程互斥出现,但是会消耗一定的资源。所以如果不是多线程的程序,打上(nonatomic)即可

10、block写一个方法,该方法可以快速查找到离某个视图最近的父视图
12、代理为什么要用weak
防止循环引用
在MRC的时候是用assign来修饰,在ARC之后用
unsafe_unretained,作用是跟weak类似的。主要是为了防止循环引用。比如A引用了B,B引用了C,C又引用了A,这样循环引用之后,如果用strong强引用来修饰,这个代理就永远释放不掉了。
14、pickerView的使用
和tableView差不多  记得遵守协议和代理
//数据源的代理方法
-(NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView//返回显示的列数  
-(NSInteger) pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component //返回当前列显示的行数 
//代理方法
-(NSString*)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
//返回当前行的内容,此处是将数组中数值添加到滚动的那个显示栏上
15、极光推送(JPUSH)的使用流程及原理

1. ush iOS Push 包括 2 个部分,APNs 推送(代理),与 JPush 应用内消息。
红色部分是 APNs 推送,JPush 代理开发者的应用(需要基于开发者提供的应用证书),向苹果 APNs 服务器推送。由 APNs Server 推送到 iOS 设备上。
蓝色部分是 JPush 应用内推送部分,即 App 启动时,内嵌的 JPush SDK 会开启长连接到 JPush Server,从而 JPush Server 可以推送消息到 App 里。
应用内消息
应用内消息:JPush iOS SDK 提供的应用内消息功能,在 App 在前台时能够收到推送下来的消息。App 可使用此功能来做消息下发动作。
此消息不经过 APNs 服务器,完全由 JPush 提供功能支持。



JPush APNs 有神魔用
iOS 平台上,只有 APNs 这个官方的推送通道,是可以随时送达的。一般开发者都是自己部署应用服务器向 APNs Server 推送。
JPush APNs 做推送代理,其意义又在哪里呢?JPush APNs 相比直接向 APNs 推送有什么好处呢?
    •    减少开发及维护成本:
    ◦    应用开发者不需要去开发维护自己的推送服务器与 APNs 对接。
    ◦    集成了 JPush iOS SDK 后不必自己维护更新 device token。
    ◦    通过 JPush 的 Web Portal 直接推送,也可以调用JPush的 HTTP 协议 API 来完成,开发工作量大大减少。
    •    减少运营成本:
    ◦    极光推送支持一次推送,同时向 Android, iOS, WinPhone 三个平台。支持统一的 API 与推送界面。
    ◦    极光推送提供标签、别名绑定机制,以及提供了非常细分的用户分群方式,运营起来非常简单、直观。
    •    提供应用内推送:
    ◦    除了使得 APNs 推送更简单,也另外提供应用内消息推送。这在类似于聊天的场景里很有必要。




16、MJExtion如何使用,如果写的model里有这个属性,后台数据没有,程序会不会崩
MJExtension很强大,几乎支持现有所有的模型、字典、json数据转换,而且效率非常高
MJExtension非常好用但是容易被忽略的功能:不管你的模型属性有几百个,只需要加一句宏MJCodingImplementation,就能实现归档解档,不用再编写恶心的encodeWithCoder:和initWithCoder:了
通过plist来创建一个模型
1.( filename 文件名(仅限于mainBundle中的文件)
(instancetype)objectWithFilename:(NSString *)filename;
2.(file 文件全路径)
+(instancetype)objectWithFile:(NSString *)file;
通过字典数组来创建一个模型数组
(NSMutableArray *)objectArrayWithKeyValuesArray:(id)keyValuesArray;


19、如何改变代码块儿里的值  

22、深拷贝和浅拷贝的区别,如何实现深拷贝
浅拷贝    只是对指针的拷贝,拷贝后两个指针指向同一个内存空间
深拷贝    不但对指针进行拷贝,而且对指针指向的内容进行拷贝,经深拷贝后的指针是指向两个不同地址的指针
24、常用的第三方框架,他们解决了哪些问题
       1.AFNetworking
       2.MBProgressHUD
       3.MJExtension
       4.MJRefresh
       5.SDWebImage
       6.UMSocial_sdk<友盟分享>

25、ios开发传值方式有哪些
       1.设置委托
        2.extern   @interface之前定义extern NSString *strZhi;
        3.对象的property属性传值
          4.方法的参数传值
          5.静态方法传值
          6.用给 指向 指针的指针 赋值 的方式传值
          7.NSNotification (观察者模式)
          8.单例
1. 3 NSUserDefaults
 .h
#define myAvgcost @"myavgcost"
.m
[[NSUserDefaults standardUserDefaults] setObject:p_Avgcost_arr forKey:myAvgcost];//写道磁盘
传到另一个类
NSArry *myAvgcost_arr=[[NSUserDefaults standardUserDefaults] arrayForKey:myAvgcost];
          10.delegate
              主要是要把共享的数据设置为XXDelegate的一个成员变量;
              然后在需要的地方通过如下方法获得一个XXDelegate的对象,如下:
              XXDelegate*app = (XXDelegate *) [[UIApplicationsharedApplication] delegate];
              每次获取delegate并不是创建一个新app,每个app只有一个delegate。



26、ios怎么做到性能优化


30、介绍一下MVC以及动态方法和静态方法的区别
 1.静态的方法在整个应用程序其间存储在内存中,速度快,但占用内存. 
  2.动态的方法在先声明类实例才能调用类中的方法
   3.一般使用频繁的方法用静态方法,用的少的方法用动态的。静态的速度快,占内存。动态的速度相对慢些,但调用完后,立即释放类,可以节省内存,
4.静态方法主要的问题就是数据同步的问题。如果你的静态方法的类中不保存私有变量那么什么问题都不会有的。最好是包要操作的数据全部以参数的方式传到方法中去
1. 静态方法是类方法,调用时不需要创建类实例。
2. 静态方法是静态绑定到子类,不是被继承
7.从面向对象的角度来看: 
静态方法面向的是类的操作,而实力方法面向的是对象.
8.静态方法修改的是类的状态,而对象修改的是各个对象的状态,这点也是它们重要的区别

9.类的实例化调用是在类的生命周期中存在,当类没有了以后,对应的实例也就没有了,对应的方法也就没有了,静态类不然,只要你引用了那个静态类的命名空间,他就会一直存在,直到你退出系统。

31、谈谈MVC在CocoaTouch中的实现

 M-Model(模型)是应用系统中与视图对应部分的数据;
V-View(视图)是应用系统中用户看到并与之交互的界面;
C-Controller(控制器)在应用系统中起到控制器作用,用来接受用户事件、显示数据、与视图进行交互等。

32、有两个字符串@“hello”,@“world”你有几种方法将它俩拼接在一起

//方法1.
1. ring = [NSString initWithFormat:@"%@,%@", string1, string2 ];
//方法2.
1. ring = [string1 stringByAppendingString:string2];
2. 方法3 .
string = [string stringByAppendingFormat:@"%@,%@",string1, string2];
//截取字符串
• (NSString *)substringFromIndex:(NSUInteger)from;
• (NSString *)substringToIndex:(NSUInteger)to;
• (NSString *)substringWithRange:(NSRange)range;
33、一个列表有足够多得显示区域,滑动了一下,如何判断是向上滑动还是向下滑动。
偏移量
• (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
    oldY = scrollView.contentOffset.y;
}

• (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
   if( scrollView.contentOffset.y > oldY) {
  向下
}else{
向上

34、有这样一段json数据{“title”:“null”},转成字典之后将title对应的value赋值在一个label.text上,会出现什么问题


35、请简单描述一下ios中的KVO实现方式

36、如何判断一个字典中是否含有某个key
       1.for in   2.遍历器  3.dictionary.allkeys  containt 
37、属性readwrite,readonly,assign,copy,nonatomic各是什么作用?在哪些情况下用

38、OC创建线程的方法是什么?如果在主线程中执行代码,方法是什么?如果想演示执行代码,方法又是什么

39、#import,#include@class有什么区别?

40、OC中书写一个单例模式,使用GCD书写单例

41、说明weak与_weak的作用及常用在什么时候


46、通知跟代理的区别分别写一个通知及代理





//自我发挥
1.是否有自己的设备
2.做过什么项目
3.参与整个项目开发的有多少人,除了跟自己的团队沟通,有跟后台沟通过么
posted @ 2016-01-06 14:49  kunzir  阅读(497)  评论(0编辑  收藏  举报