引用自:http://blog.sina.com.cn/s/blog_a7c44c880101aibh.htmlhtml
一、Object-C有多继承吗?没有的话用什么代替?cocoa 中全部的类都是NSObject 的子类
多继承在这里是用protocol 委托代理 来实现的
你不用去考虑繁琐的多继承 ,虚基类的概念.
ood的多态特性 在 obj-c 中经过委托来实现.
二、Object-C有私有方法吗?私有变量呢?objective-c – 类里面的方法只有两种, 静态方法和实例方法. 这彷佛就不是完整的面向对象了,按照OO的原则就是一个对象只暴露有用的东西. 若是没有了私有方法的话, 对于一些小范围的代码重用就不那么顺手了. 在类里面声名一个私有方法@interface Controller : NSObject { NSString *something; }+ (void)thisIsAStaticMethod;– (void)thisIsAnInstanceMethod;@end @interface Controller (private) -(void)thisIsAPrivateMethod;@end @private能够用来修饰私有变量在Objective‐C中,全部实例变量默认都是私有的,全部实例方法默认都是公有的三、关键字const什么含义?const意味着”只读”,下面的声明都是什么意思?const int a;int const a;const int *a;int * const a;int const * a const; 前两个的做用是同样,a是一个常整型数。第三个意味着a是一个指向常整型数的指针(也就是,整型数是不可修改的,但指针能够)。第四个意思a是一个指向整型数的常指针(也就是说,指针指向的整型数是能够修改的,但指针是不可修改的)。最后一个意味着a是一个指向常整型数的常指针(也就是说,指针指向的整型数是不可修改的,同时指针也是不可修改的)。结论:•; 关键字const的做用是为给读你代码的人传达很是有用的信息,实际上,声明一个参数为常量是为了告诉了用户这个参数的应用目的。若是你曾花不少时间清理其它人留下的垃圾,你就会很快学会感谢这点多余的信息。(固然,懂得用const的程序员不多会留下的垃圾让别人来清理的。)•; 经过给优化器一些附加的信息,使用关键字const也许能产生更紧凑的代码。•; 合理地使用关键字const可使编译器很天然地保护那些不但愿被改变的参数,防止其被无心的代码修改。简而言之,这样能够减小bug的出现。 欲阻止一个变量被改变,可使用 const 关键字。在定义该 const 变量时,一般须要对它进行初始化,由于之后就没有机会再去改变它了;(2)对指针来讲,能够指定指针自己为 const,也能够指定指针所指的数据为 const,或两者同时指定为 const;(3)在一个函数声明中,const 能够修饰形参,代表它是一个输入参数,在函数内部不能改变其值;(4)对于类的成员函数,若指定其为 const 类型,则代表其是一个常函数,不能修改类的成员变量;(5)对于类的成员函数,有时候必须指定其返回值为 const 类型,以使得其返回值不为“左值”。四、关键字volatile有什么含义?并给出三个不一样例子?一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。精确地说就是,优化器在用到这个变量时必须每次都当心地从新读取这个变量的值,而不是使用保存在寄存器里的备份。下面是volatile变量的几个例子:• 并行设备的硬件寄存器(如:状态寄存器)• 一个中断服务子程序中会访问到的非自动变量(Non-automatic variables)• 多线程应用中被几个任务共享的变量 • 一个参数既能够是const还能够是volatile吗?解释为何。• 一个指针能够是volatile 吗?解释为何。 下面是答案:• 是的。一个例子是只读的状态寄存器。它是volatile由于它可能被意想不到地改变。它是const由于程序不该该试图去修改它。• 是的。尽管这并不很常见。一个例子是当一个中服务子程序修该一个指向一个buffer的指针时。 static做用?函数体内 static 变量的做用范围为该函数体,不一样于 auto 变量,该变量的内存只被分配一次,所以其值在下次调用时仍维持上次的值;(2)在模块内的 static 全局变量能够被模块内所用函数访问,但不能被模块外其它函数访问;(3)在模块内的 static 函数只可被这一模块内的其它函数调用,这个函数的使用范围被限制在声明它的模块内;(4)在类中的 static 成员变量属于整个类所拥有,对类的全部对象只有一份拷贝;(5)在类中的 static 成员函数属于整个类所拥有,这个函数不接收 this 指针,于是只能访问类的static 成员变量。六、#import和#include的区别,@class表明什么?@class通常用于头文件中须要声明该类的某个实例变量的时候用到,在m文件中仍是须要使用#import而#import比起#include的好处就是不会引发重复包含七、线程和进程的区别?进程和线程都是由操做系统所体会的程序运行的基本单元,系统利用该基本单元实现系统对应用的并发性。进程和线程的主要差异在于它们是不一样的操做系统资源管理方式。进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不一样执行路径。线程有本身的堆栈和局部变量,但线程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉,因此多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差一些。但对于一些要求同时进行而且又要共享某些变量的并发操做,只能用线程,不能用进程。八、堆和栈的区别?管理方式:对于栈来说,是由编译器自动管理,无需咱们手工控制;对于堆来讲,释放工做由程序员控制,容易产生memory leak。申请大小:栈:在Windows下,栈是向低地址扩展的数据结构,是一块连续的内存的区域。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的,在WINDOWS下,栈的大小是2M(也有的说是1M,总之是一个编译时就肯定的常数),若是申请的空间超过栈的剩余空间时,将提示overflow。所以,能从栈得到的空间较小。堆:堆是向高地址扩展的数据结构,是不连续的内存区域。这是因为系统是用链表来存储的空闲内存地址的,天然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。因而可知,堆得到的空间比较灵活,也比较大。碎片问题:对于堆来说,频繁的new/delete势必会形成内存空间的不连续,从而形成大量的碎片,使程序效率下降。对于栈来说,则不会存在这个问题,由于栈是先进后出的队列,他们是如此的一一对应,以致于永远都不可能有一个内存块从栈中间弹出分配方式:堆都是动态分配的,没有静态分配的堆。栈有2种分配方式:静态分配和动态分配。静态分配是编译器完成的,好比局部变量的分配。动态分配由alloca函数进行分配,可是栈的动态分配和堆是不一样的,他的动态分配是由编译器进行释放,无需咱们手工实现。分配效率:栈是机器系统提供的数据结构,计算机会在底层对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高。堆则是C/C++函数库提供的,它的机制是很复杂的。九、Object-C的内存管理?1.当你使用new,alloc和copy方法建立一个对象时,该对象的保留计数器值为1.当你再也不使用该对象时,你要负责向该对象发送一条release或autorelease消息.这样,该对象将在使用寿命结束时被销毁.2.当你经过任何其余方法得到一个对象时,则假设该对象的保留计数器值为1,并且已经被设置为自动释放,你不须要执行任何操做来确保该对象被清理.若是你打算在一段时间内拥有该对象,则须要保留它并确保在操做完成时释放它.3.若是你保留了某个对象,你须要(最终)释放或自动释放该对象.必须保持retain方法和release方法的使用次数相等.十、为何不少内置的类,如TableViewController的delegate的属性是assign不是retain?循环引用全部的引用计数系统,都存在循环应用的问题。例以下面的引用关系: • 对象a建立并引用到了对象b. • 对象b建立并引用到了对象c. • 对象c建立并引用到了对象b.这时候b和c的引用计数分别是2和1。当a再也不使用b,调用release释放对b的全部权,由于c还引用了b,因此b的引用计数为1,b不会被释放。b不释放,c的引用计数就是1,c也不会被释放。今后,b和c永远留在内存中。这种状况,必须打断循环引用,经过其余规则来维护引用关系。好比,咱们常见的delegate每每是assign方式的属性而不是retain方式 的属性,赋值不会增长引用计数,就是为了防止delegation两端产生没必要要的循环引用。若是一个UITableViewController 对象a经过retain获取了UITableView对象b的全部权,这个UITableView对象b的delegate又是a, 若是这个delegate是retain方式的,那基本上就没有机会释放这两个对象了。本身在设计使用delegate模式时,也要注意这点。十一、定义属性时,什么状况使用copy、assign、retain?assign用于简单数据类型,如NSInteger,double,bool,retain和copy用于对象,copy用于当a指向一个对象,b也想指向一样的对象的时候,若是用assign,a若是释放,再调用b会crash,若是用copy 的方式,a和b各自有本身的内存,就能够解决这个问题。retain 会使计数器加一,也能够解决assign的问题。另外:atomic和nonatomic用来决定编译器生成的getter和setter是否为原子操做。在多线程环境下,原子操做是必要的,不然有可能引发错误的结果。加了atomic,setter函数会变成下面这样:if (property != newValue) {[property release];property = [newValue retain];}十二、对象是何时被release的?引用计数为0时。autorelease实际上只是把对release的调用延迟了,对于每个Autorelease,系统只是把该Object放入了当前的Autorelease pool中,当该pool被释放时,该pool中的全部Object会被调用Release。对于每个Runloop, 系统会隐式建立一个Autorelease pool,这样全部的release pool会构成一个象CallStack同样的一个栈式结构,在每个Runloop结束时,当前栈顶的Autorelease pool会被销毁,这样这个pool里的每一个Object(就是autorelease的对象)会被release。那什么是一个Runloop呢? 一个UI事件,Timer call, delegate call, 都会是一个新的Runloop1三、iOS有没有垃圾回收?Objective-C 2.0也是有垃圾回收机制的,可是只能在Mac OS X Leopard 10.5 以上的版本使用。1四、tableView的重用机制?查看UITableView头文件,会找到NSMutableArray* visiableCells,和NSMutableDictnery* reusableTableCells两个结构。visiableCells内保存当前显示的cells,reusableTableCells保存可重用的cells。 TableView显示之初,reusableTableCells为空,那么tableView dequeueReusableCellWithIdentifier:CellIdentifier返回nil。开始的cell都是经过[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]来建立,并且cellForRowAtIndexPath只是调用最大显示cell数的次数。 好比:有100条数据,iPhone一屏最多显示10个cell。程序最开始显示TableView的状况是: 1. 用[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]建立10次cell,并给cell指定一样的重用标识(固然,能够为不一样显示类型的cell指定不一样的标识)。而且10个cell所有都加入到visiableCells数组,reusableTableCells为空。 2. 向下拖动tableView,当cell1彻底移出屏幕,而且cell11(它也是alloc出来的,缘由同上)彻底显示出来的时候。cell11加入到visiableCells,cell1移出visiableCells,cell1加入到reusableTableCells。3. 接着向下拖动tableView,由于reusableTableCells中已经有值,因此,当须要显示新的cell,cellForRowAtIndexPath再次被调用的时候,tableView dequeueReusableCellWithIdentifier:CellIdentifier,返回cell1。cell1加入到visiableCells,cell1移出reusableTableCells;cell2移出visiableCells,cell2加入到reusableTableCells。以后再须要显示的Cell就能够正常重用了。1五、ViewController 的loadView、viewDidLoad、viewDidUnload分别是何时调用的,在自定义ViewCointroller时在这几个函数中应该作什么工做?由init、loadView、viewDidLoad、viewDidUnload、dealloc的关系提及init方法在init方法中实例化必要的对象(听从LazyLoad思想)init方法中初始化ViewController自己loadView方法当view须要被展现而它倒是nil时,viewController会调用该方法。不要直接调用该方法。若是手工维护views,必须重载重写该方法若是使用IB维护views,必须不能重载重写该方法loadView和IB构建view你在控制器中实现了loadView方法,那么你可能会在应用运行的某个时候被内存管理控制调用。 若是设备内存不足的时候, view 控制器会收到didReceiveMemoryWarning的消息。 默认的实现是检查当前控制器的view是否在使用。 若是它的view不在当前正在使用的view hierarchy里面,且你的控制器实现了loadView方法,那么这个view将被release, loadView方法将被再次调用来建立一个新的view。viewDidLoad方法viewDidLoad 此方法只有当view从nib文件初始化的时候才被调用。重载重写该方法以进一步定制view在iPhone OS 3.0及以后的版本中,还应该重载重写viewDidUnload来释放对view的任何索引viewDidLoad后调用数据ModelviewDidUnload方法当系统内存吃紧的时候会调用该方法(注:viewController没有被dealloc)内存吃紧时,在iPhone OS 3.0以前didReceiveMemoryWarning是释放无用内存的惟一方式,可是OS 3.0及之后viewDidUnload方法是更好的方式在该方法中将全部IBOutlet(不管是property仍是实例变量)置为nil(系统release view时已经将其release掉了)在该方法中释放其余与view有关的对象、其余在运行时建立(但非系统必须)的对象、在viewDidLoad中被建立的对象、缓存数据等 release对象后,将对象置为nil(IBOutlet只须要将其置为nil,系统release view时已经将其release掉了)通常认为viewDidUnload是viewDidLoad的镜像,由于当view被从新请求时,viewDidLoad还会从新被执行viewDidUnload中被release的对象必须是很容易被从新建立的对象(好比在viewDidLoad或其余方法中建立的对象),不要release用户数据或其余很难被从新建立的对象dealloc方法viewDidUnload和dealloc方法没有关联,dealloc仍是继续作它该作的事情1六、ViewController的didReceiveMemoryWarning是在何时调用的?默认的操做是什么?当程序接到内存警告时View Controller将会收到这个消息:didReceiveMemoryWarning从iOS3.0开始,不须要重载这个函数,把释放内存的代码放到viewDidUnload中去。这个函数的默认实现是:检查controller是否能够安全地释放它的view(这里加粗的view指的是controller的view属性),好比view自己没有superview而且能够被很容易地重建(从nib或者loadView函数)。若是view能够被释放,那么这个函数释放view并调用viewDidUnload。你能够重载这个函数来释放controller中使用的其余内存。但要记得调用这个函数的super实现来容许父类(通常是UIVIewController)释放view。若是你的ViewController保存着view的子view的引用,那么,在早期的iOS版本中,你应该在这个函数中来释放这些引用。而在iOS3.0或更高版本中,你应该在viewDidUnload中释放这些引用。1七、列举Cocoa中常见的集中多线程的实现,并谈谈多线程安全的几种解决办法,通常什么地方会用到多线程?NSThread,GCD等。尽可能用上层分装好的方法去实现多线程而不是手动调用NSThread。1八、怎么理解MVC,在Cocoa中MVC是怎么实现的?Model: 表明你的应用程序是什么(不是怎么展示)Controller: 控制你的Model怎么展示给用户(UI逻辑)
View: Controller的奴隶。。。
Model,Controller,View相互通信的规则:
ios
Controller能够直接和Model通讯c++
Controller也能够直接和View通讯程序员
Model和View永远不能直接通讯面试
iOS中View和Controller的通讯是透明和固定的,主要经过outlet和action实现objective-c
View使用Delegate接口和Controller同步信息设计模式
View不直接和数据通讯,使用dataSource接口从Controller处获取数据数组
View的delegate和dataSource通常就是Controller缓存
Controller负责为View翻译和格式化Model的数据安全
Model使用Notification & KVO的方式分发数据更新信息,Controller能够有选择的监听本身感兴趣的信息。
View也能够监听广播信息,但通常不是Model发出的信息
一个完整的App就是不少MVC的集合
1九、delegate和notification区别,分别在什么状况下使用?
Delegate:
消息的发送者(sender)告知接收者(receiver)某个事件将要发生,delegate赞成然而后发送者响应事件,delegate机制使得接收者能够改变发送者的行为。一般发送者和接收者的关系是直接的一对多的关系。
Notification:
消息的发送者告知接收者事件已经发生或者将要发送,仅此而已,接收者并不能反过来影响发送者的行为。一般发送者和接收者的关系是间接的多对多关系。
1. 效率确定是delegate比nsnotification高。
2. delegate方法比notification更加直接,最典型的特征是,delegate方法每每须要关注返回值,也就是delegate方法的结果。好比-windowShouldClose:,须要关心返回的是yes仍是no。因此delegate方法每每包含should这个很传神的词。也就是比如你作个人delegate,我会问你我想关闭窗口你愿意吗?你须要给我一个答案,我根据你的答案来决定如何作下一步。相反的,notification最大的特点就是不关心接受者的态度,我只管把通告放出来,你接受不接受就是你的事情,同时我也不关心结果。因此notification每每用did这个词汇,好比NSWindowDidResizeNotification,那么nswindow对象放出这个notification后就什么都无论了也不会等待接受者的反应。
1)两个模块之间联系不是很紧密,就用notification传值,例如多线程之间传值用notificaiton。
2)delegate只是一种较为简单的回调,且主要用在一个模块中,例如底层功能完成了,须要把一些值传到上层去,就事先把上层的函数经过delegate传到底层,而后在底层call这个delegate,它们都在一个模块中,完成一个功能,例如说 NavgationController 从 B 界面到A 点返回按钮 (调用popViewController方法) 能够用delegate比较好。
20、self.跟self什么区别?
2一、id、nil表明什么?
id和void *并不是彻底同样。在上面的代码中,id是指向struct objc_object的一个指针,这个意思基本上是说,id是一个指向任何一个继承了Object(或者NSObject)类的对象。须要注意的是id是一个指针,因此你在使用id的时候不须要加星号。好比id foo=nil定义了一个nil指针,这个指针指向NSObject的一个任意子类。而id *foo=nil则定义了一个指针,这个指针指向另外一个指针,被指向的这个指针指向NSObject的一个子类。
nil和C语言的NULL相同,在objc/objc.h中定义。nil表示一个Objctive-C对象,这个对象的指针指向空(没有东西就是空)。
首字母大写的Nil和nil有一点不同,Nil定义一个指向空的类(是Class,而不是对象)。
SEL是“selector”的一个类型,表示一个方法的名字
Method(咱们常说的方法)表示一种类型,这种类型与selector和实现(implementation)相关
IMP定义为 id (*IMP) (id, SEL, …)。这样说来, IMP是一个指向函数的指针,这个被指向的函数包括id(“self”指针),调用的SEL(方法名),再加上一些其余参数.说白了IMP就是实现方法。
2二、内存管理 Autorelease、retain、copy、assign的set方法和含义?
1,你初始化(alloc/init)的对象,你须要释放(release)它。例如:
NSMutableArray aArray = [[NSArray alloc] init];
后,须要
[aArray release];
2,你retain或copy的,你须要释放它。例如:
[aArray retain]
后,须要
[aArray release];
3,被传递(assign)的对象,你须要斟酌的retain和release。例如:
obj2 = [[obj1 someMethod] autorelease];
对象2接收对象1的一个自动释放的值,或传递一个基本数据类型(NSInteger,NSString)时: 你或但愿将对象2进行retain,以防止它在被使用以前就被自动释放掉。可是在retain后,必定要在适当的时候进行释放。
关于索引计数(Reference Counting)的问题
retain值 = 索引计数(Reference Counting)
NSArray对象会retain(retain值加一)任何数组中的对象。当NSArray被卸载(dealloc)的时候,全部数组中的对象会被执行一次释放(retain值减一)。不只仅是NSArray,任何收集类(Collection Classes)都执行相似操做。例如NSDictionary,甚至UINavigationController。
Alloc/init创建的对象,索引计数为1。无需将其再次retain。
[NSArray array]和[NSDate date]等“方法”创建一个索引计数为1的对象,可是也是一个自动释放对象。因此是本地临时对象,那么无所谓了。若是是打算在全Class中使用的变量(iVar),则必须retain它。
缺省的类方法返回值都被执行了“自动释放”方法。(*如上中的NSArray)
在类中的卸载方法“dealloc”中,release全部未被平衡的NS对象。(*全部未被autorelease,而retain值为1的)
2三、类别的做用?
有时咱们须要在一个已经定义好的类中增长一些方法,而不想去重写该类。好比,当工程已经很大,代码量比较多,或者类中已经包住不少方法,已经有其余代码调用了该类建立对象并使用该类的方法时,可使用类别对该类扩充新的方法。
注意:类别只能扩充方法,而不能扩充成员变量。
2四、委托(举例)
委托代理(degegate),顾名思义,把某个对象要作的事情委托给别的对象去作。那么别的对象就是这个对象的代理,代替它来打理要作的事。反映到程序中,首先要明确一个对象的委托方是哪一个对象,委托所作的内容是什么。
委托机制是一种设计模式,在不少语言中都用到的,这只是个通用的思想,网上会有不少关于这方面的介绍。
那么在苹果开发过程当中,用到委托的程序实现思想以下,我主要拿如何在视图之间传输信息作个例子。
譬如:在两个页面(UIIview视图对象)实现传值,用委托(delegate)能够很好作到!
方法:
类A
@interface A:UIView
id transparendValueDelegate;
@property(nomatic, retain) id transparendValueDelegate;
@implemtion A
@synthesize transparendValueDelegate
-(void)Function
{
NSString* value = @"hello";
//让代理对象执行transparendValue动做
[transparendValueDelegate transparendValue: value];
}
类B
@interface B:UIView
NSString* value;
@implemtion B
-(void)transparendValue:(NSString*)fromValue
{
value = fromValue;
NSLog(@"the value is %@ ",value);
}
//下面的设置A代理委托对象为B
//在定义A和B类对象处:
A* a = [[A alloc] init];
B* b = [[B alloc] init];
a. transparendValueDelegate = b;//设置对象a代理为对象b
这样在视图A和B之间能够经过委托来传值!
2五、retainCount?
26..属性readwrite,readonly,assign,retain,copy,nonatomic 各是什么做用,在那种状况下用
assign:指定setter方法用简单的赋值,这是默认操做。你能够对标量类型(如int)使用这个属性。你能够想象一个float,它不是一个对象,因此它不能retain、copy。
retain:指定retain应该在后面的对象上调用,前一个值发送一条release消息。你能够想象一个NSString实例,它是一个对象,并且你可能想要retain它。
copy:指定应该使用对象的副本(深度复制),前一个值发送一条release消息。基本上像retain,可是没有增长引用计数,是分配一块新的内存来放置它。
readonly:将只生成getter方法而不生成setter方法(getter方法没有get前缀)。
readwrite:默认属性,将生成不带额外参数的getter和setter方法(setter方法只有一个参数)。
atomic:对于对象的默认属性,就是setter/getter生成的方法是一个原子操做。若是有多个线程同时调用setter的话,不会出现某一个线程执行setter所有语句以前,另外一个线程开始执行setter的状况,相关于方法头尾加了锁同样。
nonatomic:不保证setter/getter的原子性,多线程状况下数据可能会有问题。
27.类变量的@protected ,@private ,@public ,@package声明各有什么含义
Objective-C 对存取权限的设定。也是变量的做用域。
protected 该类和全部的子类中的方法能够直接访问这样的变量,这是默认的。
private — 该类中的方法能够访问这样的变量,子类不能够。 public — 除了本身和子类中的方法外,也能够被其余类或者其余模块中的方法所访问。开放性最大。 package — 对于64位图像,这样的成员变量能够在实现这个类的图像中随意访问。
28.浅拷贝和深拷贝区别是什么
简单的来讲就是,在有指针的状况下,浅拷贝只是增长了一个指针指向已经存在的内存,而深拷贝就是增长一个指针而且申请一个新的内存,使这个增长的指针指向这个新的内存,采用深拷贝的状况下,释放内存的时候就不会出如今浅拷贝时重复释放同一内存的错误
29.Cocoa中与虚基类的概念么?怎么简洁的实现
30.NSString 和 NSMutableString 有什么区别
NSString至关于一个const char* 不能够改变。
而 NSMutableString至关于 char* 能够改变内部的内容。
31.自动释放池跟GC有什么区别?iPhone上有GC么?[pool release] 和[pool drain]有什么区别
”Autorelease Pools”(自动释放池)在应用中的使用技巧。
1,Autorelease Pools概要
一个”Autorelease Pool”实例中“包含”其它各类调用了”autorelease”方法的对象。当它释放时,其中全部被管理对象都会收到”relrease”的消信。注意,同一个对象能够被屡次调用”autorelease”方法,并能够放到同一个”Autorelease Pool”中。引入这个自动释放池机制,对象的”autorelease”方法代替”relrease”方法能够延长它的生命周期,直接到当前”Autorelrease Pool”释放。若是想让此对象的生命周期超过”Autorelease Pool”,还能够再次”retain”,呵呵,有意思吧?且让我慢慢道来。
Cocoa老是认为当前至少有一个”Autorelease Pool”对象是可用的。若此对象并不存在,你调用的”autorelease”的全部对象都不会被自动释放掉,可想而知,形成内存泄露。Cocoa把这个错误信息写入日志??仅仅是为了之后分析。
你能够用”alloc”与”init”方法建立一个”NSAutoreleasePool”对象,而且能够调用”release”或”drain”(”release”与”drain”的区别是”drain”在有GC的环境中会引发GC回收操做,”release”反之。但在非GC环境中,二者相同。官方的说法是为了程序的兼容性,应该考虑用”drain”代替”release”,)方法来回收它(调用它的”autorelease”或”retain”方法会引发异常)。在一个完整的上下文最后”Autorelease Pool”对象应该被”release”掉(在方法内或一段循环体内建立的”Autorelease Pool”对象)。
“Autorelease Pools”的全部实例在栈中管理(咱们暂时叫他“自动释放池栈”),而且它们是能够被嵌套的(父生子,子生孙。。。子子孙孙 ^_^)。例如,当咱们建立一个”Autorelease Pool”对象后,它就被自动放到“自动释放池栈”的栈顶。当本池对象回收时,它就随之从这个栈中POP掉。那么也就是说,当任何一个对象调用”autorelease”方法后,它会被放入当前线程中当前栈顶的自动释放池中。
接下来咱们聊聊”Autorelease Pools”的嵌套问题。在你的应用中,你能够任意多的建立”Autorelease Pool”对象,而这些对象被当前线程的“自动释放池栈”所管理。那么除了一个接一个的顺序建立并销毁它的状况外,还有一种使用方式,就是嵌套式的建立与使用。例如:在你的主函数建立了一个”autorelease pool”,而后又调用了建立了”autorelease pool”实例的其它方法;或是在外循环中建立了”Autorelease Pool”的实例,而内循环中也作了相同的事情。有意思吧,呵呵,嵌套的机制使父Pool实例释放后,它的全部子Pool也将释放。但这里还存在一些反作用,后续文章会详细讨论。
“Application kit”在一个事件循环里会自动建立一个”autorelease pool”。像鼠标键的按下与释放,因此你编写的代码一般不须要考虑太多这方面的事情。固然,有如下三种状况你会建立与销毁本身的Pool实例:
1,应用不是基于”Application Kit”,像”Command-line tool”,由于它并无内置的”autorelease pools”的支持。
2,建立线程,你必需在线程开始时建立一个”Autorelease Pool”实例。反之,会形成内存池露(会在之后的文章详细说明线程与池的技巧)。
3,一个循环内建立了太多的临时对象,你应该为他们建立一个”Autorelease Pool”对象,并在下次循还前销毁它们。
2,自动释放池中的”Non-AppKit”应用
在”Non-AppKit”应用中使用自动释放池的机制实际上是至关简单的事情。你仅仅须要在main()起始处建立”Autorelease Pool”对象,并在结尾处释放掉它。就像在Xcode的Foundation Tool的建立模版里写的同样。这个确保你在应用生命周期内至少有一个”Autorelease Pool”是可用的。可是,这也使全部在此期间的全部”autorelease”的对象都必需在应用结束后才被释放。这也许会引发在应用的使用中不断的增加,因此,你仍然考虑在不一样的做用域建立新的”Autorelease Pool”。
大多应用中都存在各类级别的循环机制。在这些应用中,你能够在每一个循环内的开头建立一个”Autorelease Pool”对象,并在结尾处释放掉它。
例如:
void main()
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSArray *args = [[NSProcessInfo processInfo] arguments];
unsigned count, limit = [args count];
for (count = 0; count < limit; count++)
{
NSAutoreleasePool *loopPool = [[NSAutoreleasePool alloc] init];
NSString *fileContents;
NSString *fileName;
fileName = [args objectAtIndex:count];
fileContents = [[[NSString alloc] initWithContentsOfFile:fileName] autorelease];
// this is equivalent to using stringWithContentsOfFile:
[loopPool release];
}
[pool drain];
exit (EXIT_SUCCESS);
}
在命令行中处理全部以参数传来的文件。一次循环处理一个文件。在循环的开头建立一个”NSAutoreleasePool”对象,并在循环结束时释放掉。所以,任何在其中建立并调用“autorelease”的对象都将添加到这个Pool实例中,当本池被释放后,这些对象也将被回收。注意,任何在做用域内建立的”autoreleased”对象(像”fileName”),虽然并无显示的调用”autorelease”方法,但都将被当前池所管理并释放。
32.C和obj-c 如何混用
1)obj-c的编译器处理后缀为m的文件时,能够识别obj-c和c的代码,处理mm文件能够识别obj-c,c,c++代码,但cpp文件必须只能用c/c++代码,并且cpp文件include的头文件中,也不能出现obj-c的代码,由于cpp只是cpp
2) 在mm文件中混用cpp直接使用便可,因此obj-c混cpp不是问题
3)在cpp中混用obj-c其实就是使用obj-c编写的模块是咱们想要的。
若是模块以类实现,那么要按照cpp class的标准写类的定义,头文件中不能出现obj-c的东西,包括#import cocoa的。实现文件中,即类的实现代码中可使用obj-c的东西,能够import,只是后缀是mm。
若是模块以函数实现,那么头文件要按c的格式声明函数,实现文件中,c++函数内部能够用obj-c,但后缀仍是mm或m。
总结:只要cpp文件和cpp include的文件中不包含obj-c的东西就能够用了,cpp混用obj-c的关键是使用接口,而不能直接使用实现代码,实际上cpp混用的是obj-c编译后的o文件,这个东西实际上是无差异的,因此能够用。obj-c的编译器支持cpp
33.响应者链是什么
响应者链是Application Kit事件处理架构的中心机制。它由一系列连接在一块儿的响应者对象组成,事件或者动做消息能够沿着这些对象进行传递。如图6-20显示的那样,若是一个响应者对象不能处理某个事件或动做-也就是说,它不响应那个消息,或者不认识那个事件,则将该消息从新发送给链中的下一个响应者。消息沿着响应者链向上、向更高级别的对象传递,直到最终被处理(若是最终仍是没有被处理,就会被抛弃)。
当Application Kit在应用程序中构造对象时,会为每一个窗口创建响应者链。响应者链中的基本对象是对象及其视图层次。在视图层次中级别较低的视图将比级别更高的视图优先得到处理事件或动做消息的机会。中保有一个第一响应者的引用,它一般是当前窗口中处于选择状态的视图,窗口一般把响应消息的机会首先给它。对于事件消息,响应者链一般以发生事件的窗口对应的对象做为结束,虽然其它对象也能够做为下一个响应者被加入到对象的后面。
34..UIscrollVew用到了什么设计模式?还能再foundation库中找到相似的吗?
组合模式composition,全部的container view都用了这个模式
观察者模式observer,全部的UIResponder都用了这个模式。NSWindowNSWindowNSWindowNSWindow
模板(Template)模式,全部datasource和delegate接口都是模板模式的典型应用
33. .timer的间隔周期准吗?为何?怎样实现一个精准的timer?
NSTimer能够精确到50-100毫秒.
NSTimer不是绝对准确的,并且中间耗时或阻塞错过下一个点,那么下一个点就pass过去了
34.