一、Object-C有多继承吗?没有的话用什么代替?cocoa 中全部的类都是NSObject 的子类 html
多继承在这里是用protocol 委托代理 来实现的
你不用去考虑繁琐的多继承 ,虚基类的概念.
ood的多态特性 在 obj-c 中经过委托来实现. java
二、Object-C有私有方法吗?私有变量呢? ios
objective-c – 类里面的方法只有两种, 静态方法和实例方法. 这彷佛就不是完整的面向对象了,按照OO的原则就是一个对象只暴露有用的东西. 若是没有了私有方法的话, 对于一些小范围的代码重用就不那么顺手了. 在类里面声名一个私有方法 c++
@interface Controller : NSObject { NSString *something; } 程序员
+ (void)thisIsAStaticMethod; 面试
– (void)thisIsAnInstanceMethod; objective-c
@end 编程
@interface Controller (private) - 设计模式
(void)thisIsAPrivateMethod; 数组
@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, 都会是一个新的Runloop
1三、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后调用数据Model
viewDidUnload方法
当系统内存吃紧的时候会调用该方法(注: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的奴隶。。。
1 Model,Controller,View相互通信的规则:
Controller能够直接和Model通讯
1 Controller也能够直接和View通讯
1 Model和View永远不能直接通讯
1 iOS中View和Controller的通讯是透明和固定的,主要经过outlet和action实现
1 View使用Delegate接口和Controller同步信息
1 View不直接和数据通讯,使用dataSource接口从Controller处获取数据
1 View的delegate和dataSource通常就是Controller
1 Controller负责为View翻译和格式化Model的数据
1 Model使用Notification & KVO的方式分发数据更新信息,Controller能够有选择的监听本身感兴趣的信息。
1 View也能够监听广播信息,但通常不是Model发出的信息
1 一个完整的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在应用程序中构造对象时,会为每一个窗口创建响应者链。响应者链中的基本对象是NSWindow对象及其视图层次。在视图层次中级别较低的视图将比级别更高的视图优先得到处理事件或动做消息的机会。NSWindow中保有一个第一响应者的引用,它一般是当前窗口中处于选择状态的视图,窗口一般把响应消息的机会首先给它。对于事件消息,响应者链一般以发生事件的窗口对应的NSWindow对象做为结束,虽然其它对象也能够做为下一个响应者被加入到NSWindow对象的后面。
34..UIscrollVew用到了什么设计模式?还能再foundation库中找到相似的吗?
组合模式composition,全部的container view都用了这个模式
观察者模式observer,全部的UIResponder都用了这个模式。
模板(Template)模式,全部datasource和delegate接口都是模板模式的典型应用
33. .timer的间隔周期准吗?为何?怎样实现一个精准的timer?
NSTimer能够精确到50-100毫秒.
NSTimer不是绝对准确的,并且中间耗时或阻塞错过下一个点,那么下一个点就pass过去了
此份面试题包含40个题目,是如今网上能搜索到的一个比较热的一份,可是答案并非很详细和完整,基本答案来着cocoaChina,和一些本身的补充。
1.Difference between shallow copy and deep copy?
浅复制和深复制的区别?
答案:浅层复制:只复制指向对象的指针,而不复制引用对象自己。
深层复制:复制引用对象自己。
意思就是说我有个A对象,复制一份后获得A_copy对象后,对于浅复制来讲,A和A_copy指向的是同一个内存资源,复制的只不过是是一个指针,对象自己资源
仍是只有一份,那若是咱们对A_copy执行了修改操做,那么发现A引用的对象一样被修改,这其实违背了咱们复制拷贝的一个思想。深复制就好理解了,内存中存在了
两份独立对象自己。
用网上一哥们通俗的话将就是:
浅复制比如你和你的影子,你完蛋,你的影子也完蛋
深复制比如你和你的克隆人,你完蛋,你的克隆人还活着。
2.What is advantage of categories? What is difference between implementing a category and inheritance?
类别的做用?继承和类别在实现中有何区别?
答案:category 能够在不获悉,不改变原来代码的状况下往里面添加新的方法,只能添加,不能删除修改。
而且若是类别和原来类中的方法产生名称冲突,则类别将覆盖原来的方法,由于类别具备更高的优先级。
类别主要有3个做用:
(1)将类的实现分散到多个不一样文件或多个不一样框架中。
(2)建立对私有方法的前向引用。
(3)向对象添加非正式协议。
继承能够增长,修改或者删除方法,而且能够增长属性。
3.Difference between categories and extensions?
类别和类扩展的区别。
答案:category和extensions的不一样在于后者能够添加属性。另外后者添加的方法是必需要实现的。
extensions能够认为是一个私有的Category。
4.Difference between protocol in objective c and interfaces in java?
oc中的协议和java中的接口概念有何不一样?
答案:OC中的代理有2层含义,官方定义为 formal和informal protocol。前者和Java接口同样。
informal protocol中的方法属于设计模式考虑范畴,不是必须实现的,可是若是有实现,就会改变类的属性。
其实关于正式协议,类别和非正式协议我很早前学习的时候大体看过,也写在了学习教程里
“非正式协议概念其实就是类别的另外一种表达方式“这里有一些你可能但愿实现的方法,你能够使用他们更好的完成工做”。
这个意思是,这些是可选的。好比我门要一个更好的方法,咱们就会申明一个这样的类别去实现。而后你在后期能够直接使用这些更好的方法。
这么看,总以为类别这玩意儿有点像协议的可选协议。"
如今来看,其实protocal已经开始对二者都统一和规范起来操做,由于资料中说“非正式协议使用interface修饰“,
如今咱们看到协议中两个修饰词:“必须实现(@requied)”和“可选实现(@optional)”。
5.What are KVO and KVC?
答案:kvc:键 - 值编码是一种间接访问对象的属性使用字符串来标识属性,而不是经过调用存取方法,直接或经过实例变量访问的机制。
不少状况下能够简化程序代码。apple文档其实给了一个很好的例子。
kvo:键值观察机制,他提供了观察某一属性变化的方法,极大的简化了代码。
具体用看到嗯哼用到过的一个地方是对于按钮点击变化状态的的监控。
好比我自定义的一个button
[cpp]
[self addObserver:self forKeyPath:@"highlighted" options:0 context:nil];
#pragma mark KVO
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if ([keyPath isEqualToString:@"highlighted"] ) {
[self setNeedsDisplay];
}
}
对于系统是根据keypath去取的到相应的值发生改变,理论上来讲是和kvc机制的道理是同样的。
对于kvc机制如何经过key寻找到value:
“当经过KVC调用对象时,好比:[self valueForKey:@”someKey”]时,程序会自动试图经过几种不一样的方式解析这个调用。首先查找对象是否带有 someKey 这个方法,若是没找到,会继续查找对象是否带有someKey这个实例变量(iVar),若是尚未找到,程序会继续试图调用 -(id) valueForUndefinedKey:这个方法。若是这个方法仍是没有被实现的话,程序会抛出一个NSUndefinedKeyException异常错误。
(cocoachina.com注:Key-Value Coding查找方法的时候,不只仅会查找someKey这个方法,还会查找getsomeKey这个方法,前面加一个get,或者_someKey以及_getsomeKey这几种形式。同时,查找实例变量的时候也会不只仅查找someKey这个变量,也会查找_someKey这个变量是否存在。)
设计valueForUndefinedKey:方法的主要目的是当你使用-(id)valueForKey方法从对象中请求值时,对象可以在错误发生前,有最后的机会响应这个请求。这样作有不少好处,下面的两个例子说明了这样作的好处。“
来至cocoa,这个说法应该挺有道理。
由于咱们知道button倒是存在一个highlighted实例变量.所以为什么上面咱们只是add一个相关的keypath就好了,
能够按照kvc查找的逻辑理解,就说的过去了。
6.What is purpose of delegates?
代理的做用?
答案:代理的目的是改变或传递控制链。容许一个类在某些特定时刻通知到其余类,而不须要获取到那些类的指针。能够减小框架复杂度。
另一点,代理能够理解为java中的回调监听机制的一种相似。
7.What are mutable and immutable types in Objective C?
oc中可修改和不能够修改类型。
答案:可修改不可修改的集合类。这个我我的简单理解就是可动态添加修改和不可动态添加修改同样。
好比NSArray和NSMutableArray。前者在初始化后的内存控件就是固定不可变的,后者能够添加等,能够动态申请新的内存空间。
8.When we call objective c is runtime language what does it mean?
咱们说的oc是动态运行时语言是什么意思?
答案:多态。 主要是将数据类型的肯定由编译时,推迟到了运行时。
这个问题其实浅涉及到两个概念,运行时和多态。
简单来讲,运行时机制使咱们直到运行时才去决定一个对象的类别,以及调用该类别对象指定方法。
多态:不一样对象以本身的方式响应相同的消息的能力叫作多态。意思就是假设生物类(life)都用有一个相同的方法-eat;
那人类属于生物,猪也属于生物,都继承了life后,实现各自的eat,可是调用是咱们只需调用各自的eat方法。
也就是不一样的对象以本身的方式响应了相同的消息(响应了eat这个选择器)。
所以也能够说,运行时机制是多态的基础?~~~
9.what is difference between NSNotification and protocol?
通知和协议的不一样之处?
答案:协议有控制链(has-a)的关系,通知没有。
首先我一开始也不太明白,什么叫控制链(专业术语了~)。可是简单分析下通知和代理的行为模式,咱们大体能够有本身的理解
简单来讲,通知的话,它能够一对多,一条消息能够发送给多个消息接受者。
代理按咱们的理解,到不是直接说不能一对多,好比咱们知道的明星经济代理人,不少时候一个经济人负责好几个明星的事务。
只是对于不一样明星间,代理的事物对象都是不同的,一一对应,不可能说明天要处理A明星要一个发布会,代理人发出处理发布会的消息后,别称B的
发布会了。可是通知就不同,他只关心发出通知,而不关心多少接收到感兴趣要处理。
所以控制链(has-a从英语单词大体能够看出,单一拥有和可控制的对应关系。
10.What is push notification?
什么是推送消息?
答案:太简单,不做答~~~~~~~~~~
这是cocoa上的答案。
其实到不是说太简单,只是太泛泛的一个概念的东西。就比如说,什么是人。
推送通知更是一种技术。
简单点就是客户端获取资源的一种手段。
普通状况下,都是客户端主动的pull。
推送则是服务器端主动push。
11.Polymorphism?
关于多态性
答案:多态,子类指针能够赋值给父类。
这个题目其实能够出到一切面向对象语言中,
所以关于多态,继承和封装基本最好都有个自我意识的理解,也并不是必定要把书上资料上写的能背出来。
最重要的是转化成自我理解。
12.Singleton?
对于单例的理解
答案:11,12题目其实出的有点泛泛的感受了,可能说是编程语言须要或是必备的基础。
基本能用熟悉的语言写出一个单例,以及能够运用到的场景或是你编程中碰到过运用的此种模式的框架类等。
进一步点,考虑下如何在多线程访问单例时的安全性。
13.What is responder chain?
说说响应链
答案: 事件响应链。包括点击事件,画面刷新事件等。在视图栈内从上至下,或者从下之上传播。
能够说点事件的分发,传递以及处理。具体能够去看下touch事件这块。由于问的太抽象化了
严重怀疑题目出到越后面就越笼统。
14.Difference between frame and bounds?
frame和bounds有什么不一样?
答案:frame指的是:该view在父view坐标系统中的位置和大小。(参照点是父亲的坐标系统)
bounds指的是:该view在自己坐标系统中 的位置和大小。(参照点是自己坐标系统)
15.Difference between method and selector?
方法和选择器有何不一样?
答案:selector是一个方法的名字,method是一个组合体,包含了名字和实现.
详情能够看apple文档。
16.Is there any garbage collection mechanism in Objective C.?
OC的垃圾回收机制?
答案: OC2.0有Garbage collection,可是iOS平台不提供。
通常咱们了解的objective-c对于内存管理都是手动操做的,可是也有自动释放池。
可是差了大部分资料,貌似不要和arc机制搞混就行了。
求更多~~
17.NSOperation queue?
答案:存放NSOperation的集合类。
操做和操做队列,基本能够当作java中的线程和线程池的概念。用于处理ios多线程开发的问题。
网上部分资料提到一点是,虽然是queue,可是却并非带有队列的概念,放入的操做并不是是按照严格的先进现出。
这边又有个疑点是,对于队列来讲,先进先出的概念是Afunc添加进队列,Bfunc紧跟着也进入队列,Afunc先执行这个是必然的,
可是Bfunc是等Afunc彻底操做完之后,B才开始启动而且执行,所以队列的概念离乱上有点违背了多线程处理这个概念。
可是转念一想其实能够参考银行的取票和叫号系统。
所以对于A比B先排队取票可是B率先执行完操做,咱们亦然能够感性认为这仍是一个队列。
可是后来看到一票关于这操做队列话题的文章,其中有一句提到
“由于两个操做提交的时间间隔很近,线程池中的线程,谁先启动是不定的。”
瞬间以为这个queue名字有点忽悠人了,还不如pool~
综合一点,咱们知道他能够比较大的用处在于能够帮组多线程编程就行了。
18.What is lazy loading?
答案:懒汉模式,只在用到的时候才去初始化。
也能够理解成延时加载。
我以为最好也最简单的一个列子就是tableView中图片的加载显示了。
一个延时载,避免内存太高,一个异步加载,避免线程堵塞。
19.Can we use two tableview controllers on one viewcontroller?
是否在一个视图控制器中嵌入两个tableview控制器?
答案:一个视图控制只提供了一个View视图,理论上一个tableViewController也不能放吧,
只能说能够嵌入一个tableview视图。固然,题目自己也有歧义,若是不是咱们定性思惟认为的UIViewController,
而是宏观的表示视图控制者,那咱们却是能够把其当作一个视图控制者,它能够控制多个视图控制器,好比TabbarController
那样的感受。
20.Can we use one tableview with two different datasources? How you will achieve this?
一个tableView是否能够关联两个不一样的数据源?你会怎么处理?
答案:首先咱们从代码来看,数据源如何关联上的,实际上是在数据源关联的代理方法里实现的。
所以咱们并不关心如何去关联他,他怎么关联上,方法只是让我返回根据本身的须要去设置如相关的数据源。
所以,我以为能够设置多个数据源啊,可是有个问题是,你这是想干吗呢?想让列表如何显示,不一样的数据源分区块显示?
objective-c 关键字和概念
(2012-12-09 10:55:10)转载▼
标签:关键字 |
分类:objective-c |
@
看到这个关键字,咱们就应该想到,这是Object-C对C语言的扩展,例如@interface XXX。
声明类
实现类
声明协议
与@protocol配合使用,说明协议中的某个或者某几个方法能够不实现
与@protocol配合使用,说明协议中的某个方法或者某几个方法必须实现
与@interface ,@implementation,@protocol配合使用,表明声明或者实现结束
@encode为编译器宏,它能够将类型转换为相应的字符串。
id是指向Objective-C类对象的指针,它能够声明为任何类对象的指针,当在Objective-C中使用id时,编译器会假定你知道,id指向哪一个类的对象。与void*是不一样的是,void*编译器不知道也不假定指向任何类型的指针。
定义为一个常量,若是一个指针的值为nil,表明这个指针没有指向任何对象。
在Objective-C中,关键字self与c++中this是同一律念,就是类对象自身的地址,经过self能够调用本身的实例变量和方法
当子类须要调用父类的方法时,会用到Super关键字. Super指向的是父类的指针,子类重写父类的方法时,调用父类的方法是一个比较好的习惯。由于当咱们不知道父类在该方法中实现的功能时,若是不调用父类的方法,有可能咱们重写的方法会失去该功能,这是咱们不肯意看到的状况。
NSNull是没有的意思,若是一个字典的值为NSNull,那说明与该值对应的Key是没有值的,例如Key为address,说明与address对应的是值是没有。
self super class public protected private id
[self class] [super class] selector
objective-c runtime reference
标准用法
self = [super init]
1 Objective-C有一个特性,就是能够把类当成对象来发送消息,这种用法一般用于新建对像时,例如 XXX *object = [XXX new];
若是想声明属于类而不属于类对象的方法,用+。+用来修饰类的方法,使用+修饰的类方法,是整个类的方法,不属于哪个类对象,这与C++中的static在类中使用的概念同样,
在NSLog中,使用%@表示要调用对象的description方法。
是一种结构,它表示对象的类型,就像int与 char 同样,也能够声明类的变量(对像)
为类的对象分配内存和初始化,达到能够使用该 类对象的目的。
类的实例化后的产物
在Object-C中,类的对象执行的操做,是经过给该类或者该类对象发送消息实现,如:[object func];就是给object对象发送func消息,相似C++中的方法调用。给object对象发送func消息后,object对象查询所属类的func方法执行。
当向一个对象发送消息时(调用方法),这个方法是怎么被调用的呢?这就依赖于方法高度程序,方法调度程序查找的方法以下:
在本类的方法中,找被调用的方法,若是找到了,就调用,若是找不到被沿着继承路径去查找,从哪一个类找到,就调用哪一个类的方法,若是到最根上的类仍是没有找到,那编译就会出错。
在Objective-C中支持继承,但只是支持单一继承(有且只有一个父类有),若是想使用多继承的特性,能够使用分类和协议技术。
继承是is-a,复合是has-a。复合是经过包含指向对象的指针实现的,严格意义上讲,复合是针对于对象间来讲,对于基本数据类型来讲,它们被认为是对象的一部分。
因为NSArray,NSDirectory等类不能直接存储基本数据类型,因此要想在NSArray\NSDirectory中使用基本数据类型,就得使用装箱与拆箱。
在Objective-C中,能够使用NSNumber和NSValue来实现对数据类型的包装,NSNumber能够实现对基本数据类型的包装,NSValue能够实现对任意类型数据的包装。
将基本类型封装成对象叫装箱,从封装的对象中提取基本类型叫拆箱(取消装箱),其它语言如Java原生支持装箱与拆箱,Ojbective-C不支持自动装箱与拆箱,若是须要得须要本身来实现装箱与拆箱。
在使用类对象的实例变量(成员数据)时,不要直接使用对象中的实例,要使用存以方法来获取或者修改实例,既setter和getter,在Cocoa中,存取方法有命名习惯,咱们得符合这种习惯,以便于与其它团队成员合做。setter方法是修改或者设置实例值,命名习惯为set+实例名,例有一个类有path实例变量,那setter命名为setPath,getter命名为Path,为何不是getPath,由于get在Cocoa中有特殊的含义,这个含义就是带有get的方法就意味着这个方法经过形参指针(传入函数的参数指针)来返回值。咱们要遵照这个命名习惯或者说规则。
在Objective-C 2.0中加入了@property和@synthesize来代替setter和getter,这两个关键字为编译器指令。还有点表达式,存取类成员的值时,能够使用点表达式。
Object.attribute,当点表达式在=号左边时,调用的是setter方法,在=号右边时,调用的是getter方法。
@property 语法为:@property (参数) 类型 变量名.
在这里主要说明一下参数.
参数分为三种:
第一种:读写属性包括(readonly/readwrite/)
第二种:setter属性(assign,copy,retain),assign是简单的赋值,copy是释放旧成员变量,并新分配内存地址给成员变量,将传入参数内容复制一份,给成员变量。retain是将传入 参数引用计数加1,而后将原有的成员变量释放,在将成员变量指向该传入参数。
第三种:与多线程有关(atomic,nonatomic).当使用多线程时,使用atomic,在不使用多线程时使用nonatomic
在Objective-C中建立对象有两种方法,一种是[类 new];另外一种是[[类 alloc] init],这两种方法是等价的,但按惯例来说,使用[[类 alloc] init];
alloc操做是为对象分配内存空间,并将对象的数据成员都初始,int 为0,BOOL 为NO, float 为0.0等。
初始化,默认的初始化函数为init,init返回值为id,为何回返回id呢,由于要实现链式表达式,在Objective-C中叫嵌套调用。
为何要嵌套调用??由于初始化方法init返回值可能与alloc返回的对象不是同一个?为何会发生这种状况?基于类簇的初始化,由于init能够接受参数,在init内部有可能根据不一样的参数来返回不一样种类型的对象,因此最会发生上面说的状况。
在初始化时,建议使用if (self = [super init])
当一个类须要根据不一样的状况来初始化数据成员时,就须要便利初始化函数,与init初始化不一样的是,便利初始化函数有参数,参数个数能够有1到N个,N是类数据成员个数。
指定初始化函数:什么是指定初始化函数?在类中,某个初始化函数会被指定为指定的初始化函数,肯定指定初始化函数的规则是初始化函数中,参数最多的为指定初始化函数,
其它未被指定为指定初始化函数的初始化函数要调用指定初始化函数来实现。对于该类的子类也是同样,只要重写或者直接使用父类的指定初始化函数。上述文字有些绕,来个例子吧
@interface A{
int x;
int y;
}
-(id) init;
-(id) initWithX:(int) xValue;
-(id) initWithY:(int) yValue;
-(id) initWithXY:(int) xValue
yVal:(int) yValue;
这里initWithXY被肯定为指定初始化函数。
-(id) initWithXY:(int) xValue
yVal:(int) yValue{
if (self = [super init]){
x = xValue;
y = yValue;
}
return self;
}
-(id) init{
if (self = self initWithXY:10
yVal:20){
}
return self;
}
.......
@interface B: A{
int z;
}
-(jd) initWithXY......;
@implementation B
-(id) initWithXY:(int) xValue
yVal:(int) yValue{
if (self = [super initWithXY:10
yVal=20]){
z= 40;
}
return self;
}
内存管理是软件代码中的重中之重,内存管理的好坏,直接影响着软件的稳定性。在Cocoa中,有自动释放池,这相似于C++中的智能指针。
NSObject有一个方法是autorelease,当一个对象调用这个方法时,就会将这个对象放入到自动释放池中。
drain,该方法是清空自动释放池,不是销毁它。drain方法只适用于Mac OS X 10.4以上的版本,在咱们写的代码中要使用release,release适用于全部版本。
自动释放池是以栈的方式实现,当建立一个自动释放池A时,A被压入栈顶,这时将接入autorelease消息的对象放入A自动释放池,这时建立一个新的B自动释放池,B被压入栈顶,建立完成后删除B,这个接收autorelease消息的对象依然存在,由于A自动释放池依然存在。
每一个对象都有一个与之相应的整数,称它为引用计数,当该引用计数为0时,Objective-C自动向该对象发送dealloc,以销毁该对向,与该引用计数相关的方法(消息)有下面几个
1 增长引用计数:经过alloc,new,copy建立一个对象时,该对象的引用计数加1(其实就是1,由于以前为0)
2 增长引用计数: retain
3 减小引用计数: release
局部分配内存(临时对象):
1 若是使用alloc,new,copy建立对象,则须要主动调用对象的release方法
2 若是使用非alloc,new,copy建立对象,咱们认为该对象引用计数为1,并已经加入了自动释放池,咱们不须要主动的调用对象的release方法。
拥有对象(在类中以成员的方法存在):
1 若是使用alloc,new,copy建立对象,则须要在dealloc方法中,释放该对象
2 若是使用非alloc,new,copy建立对象,则在拥有该对象时,保留该对象(执行retain方法),在dealloc方法中,释放该对象。
当对象的引用计数为0时,Objective-C会自动发送对象的dealloc消息(自动调用对象的dealloc方法,相似于C++的析构函数),因此咱们能够本身重写dealloc方法,来实现类里的对其它使用资源的释放工做。
注意:不要直接在代码中显示调用dealloc方法。
在Objective-C 2.0中引入了垃圾回收机制(自动管理内存),在工程设置里设置Objective-C Garbage Collection为Required[-fobjc-gc-only]就能够使用垃圾回收机制。
启用垃圾回收机制后,一般的内存管理命令都变成了空操做指令,不执行任何操做。
Objective-C的垃圾回收机制是一种继承性的垃圾回收器,垃圾回收器按期检查变量和对象以及他们之间的指针,当发现没有任何变量指向对象时,就将该对象视为被丢弃的垃圾。因此在不在使用一个对象时,将指针他的指针设置为nil,这时垃圾回收器就会清理该对象。
注意:若是开发iPhone软件,则不能使用垃圾回收。在编写iPhone软件时,Apple公司建议不要在本身的代码中使用autorelease方法,而且不要使用建立自动释放对象的函数。
什么是类别?类别是一种为现有类添加新方法的方式。
为何使用类别或者说使用类别的目的是什么?有如下三点:
第一,能够将类的实现分散到多个不一样的文件或多个不一样的框架中。
若是一个类须要实现不少个方法,咱们能够将方法分类,把分好的类造成类别,能够有效的管理和驾驭代码。
第二,建立对私有方法的前向引用。
第三,向对象添加非正式协议。
委托的意思就是你本身想作某事,你本身不作,你委托给别人作。
在Ojbective-C中,实现委托是经过类别(或非正式协议)或者协议来实现。
举个例子:Apple要生产iPhone,Apple本身不生产(种种缘由,其中之一就是在中国生产成本低,他们赚的银子多),Apple委托富士康来生产,原本富士康原来不生产iPhone,如今要生产了,因此他得本身加一个生产iPhone的生产线(类别,增长生产iPhone方法),这就是经过类别来实现委托。下面用代码来讲明这个例子。
.....
Apple *apple = [[Apple alloc ] init];
Foxconn *fox = [[Foxconn alloc] init];
[apple setDelegate:fox];
[apple produceIPhone];
........
@implementation Apple
-(...) setDelegate:(id) x{
delegate = x; //! 将委托的生产对象指定为x
}
-(...) produceIPhone{
[delegate produceIPhone]; //! 委托对象生产iPhone
}
@interface Foxconn : NSObject
...
@interface NSObject(ProduceIPhone) //! Foxconn以前就能够生产其它产品,有过声明和定义
-(...) produceIPhone //! 增长生产iPhone能力
@implementation NSObject(ProduceIPhone)
//! 生产iPhone
-(...) produceIPhone{
......
}
建立一个NSObject的类别, 称为建立一个非正式协议。为何叫非正式协议呢?
也就是说能够实现,也能够不实现被委托的任务。
拿上面的例子来讲,Apple要求Foxconn除了能生产iPhone外,还有一个要求是在必定时间内完成.因为双方没有签合同,因此时间要求和生产要求规格都是非正式协议
选择器就是一个方法的名称。选择器是在Objective-C运行时使用的编码方式,以实现快速查找。能够使用@selector预编译指令,获取选择器@selector(方法名)。NSObject提供了一个方法respondsToSelector:的方法,来访问对象是否有该方法(响应该消息)。
拿上面的Apple请Foxconn生产iPhone为例,Apple怎么知道Foxconn有没有生产iPhone的能力呢?Apple就经过respondsToSelector方法询问Foxconn,是否能够生产iPhone(是否能够响应produceIPhone),询问结果是能够,那Apple就委托Foxconn生产,Foxconn就生产出来了人们比较喜欢的iPhone产品。
与非正式协议比较而言,在Ojbective-C中,正式协议规定的全部方法必须实现。在Ojbective-C2.0中,Apple又增长了两个关键字,协议中的方法也能够不彻底实现,是哪一个关键字见关键字部份的@optional,@required。
正式协议声明以下:
@protocol XXX
-(...) func1;
-(...) func2;
使用协议:
@interface Object : NSObject //! Object从NSObject派生,并遵循XXX协议,要实现func1,func2函数。
...
self = [super init];
在Objective-C中,全部对象间的交互都是经过指针实现。
for (Type *p in array)
Objective-C不支持多继承
objective-c只不过是拥有一些附加特性的C语言。本质上就是C语言
1.C语言使用#include通知编译器应在头文件中查询定义。objective-c也能够使用#include来实现这个目的,但你永远不可能这么作,你会用#import,它是GCC编译器提供的,#import能够保证头文件只被包含一次。
xcode会使用预编译头文件(一种通过压缩的,摘要形式的头文件),在经过#import导入这种文件时,加载速度会很是快。
2.什么是框架
框架是一种汇集在一个单元的部件集合,包含头文件,库,图像,声音文件等。苹果公司将cocoa,Carbon,QuickTime和OpenGL等技术做为框架集提供。cocoa的组成部分有Foundation和Application Kit框架。还有一个支持框架的套件,包含Core Animation和Core Image,这为Cocoa增添了多种精彩的功能。
每一个框架都是一个重要的技术集合,一般包含数十个甚至上百个头文件。每一个框架都有一个主头文件,它包含了全部框架的各个头文件。经过使用#import导入主头文件,能够使用全部框架的特性。
3.Foundation框架处理的是用户界面之下的层(layer)中得特性,例如数据结构和通讯机制。
4.NS前缀
NS这个前缀告诉你函数来自cocoa而不是其余工具包。
两个不一样事物使用相同标示符时会致使名称冲突,而前缀能够预防这个大问题。
5.BOOL类型
objective-c中得BOOL其实是一种对带符号的字符类型(signed char)的定义。它使用8位存储空间,YES为1,NO为0.
6.间接
不在代码中直接使用某个值,而是使用指向该值的指针。另外一个意思是,让别的类来完成本类的工做。
例子:1.循环次数的变量。变量与间接
2.使用从文件读取。文件与间接
在OOP(面向对象编程)中,间接十分重要。OOP使用间接来获取数据,OOP真正的革命性就是它在调用代码中使用间接。好比在调用函数时,不是直接调用,而是间接调用。
7.过程式程序与OOP的区别
过程式程序创建在函数之上,数据为函数服务。面向对象编程从相反的角度来看待问题。它以程序的数据为中心,函数为数据服务。在OOP中,不在重点关注程序中得函数,而是专一与数据。
8.id
id是一种泛型,用于表示任何种类的对象。
9.OOP中得一些术语
类:类是一种结构,它表示对象的类型。对象引用类来获取和自己有关的各类信息,特别是运行什么代码来处理每种操做。
对象:对象是一种结构,它包含值和指向其类的隐藏指针。
实例:实例是“对象”的另外一种称呼。
消息:消息是对象能够执行的操做,用于通知对象去作什么。
方法:方法是为响应消息而运行的代码。根据对象的类,消息能够调用不一样的方法。
方法调度程序:是objective-c使用的一种机制,用于推测执行什么方法以响应某个特定的消息。
接口:接口是对象的类应该提供的特性的描述。接口不提供实现细节。
实现:实现是使接口正常工做的代码。
10.中缀符
objective-c有一种名为中缀符的语法技术。方法的名称及其参数都是合在一块儿的。例如:[trxtThing setStringValue:@"Hello there" color:kBlueColor]; 中 setStringValue: 和color:其实是参数的名称(其实是方法名称的一部分)。使代码可读性更强,更容易理解参数的用途。
11.先行短线
-(void)draw;
前面的短线代表这是objective-c方法的生命。这是一种区分函数原型与方法声明的方式,函数原型中没有先行短线。-表明是实例方法。+表明是类方法。
12.@interface
建立某个特定类的对象以前,objective-c编译器须要一些有关该类的信息。他必须知道对象的数据成员和它提供的特性能够使用@interface指令把这种信息传递给编译器。用于定义类的公共接口。
13.@implementation
是一个编译器指令,代表你将为某个类提供代码。类名出如今@implementation以后。该行的结尾处没有分号。由于在objective-c编译器指令后没必要使用分号。
@interface和@implementation间的参数名不一样是正确的。
在@interface中没有声明却在@implementation中实现的方法是私有方法。
14.实例化
建立对象的过程叫作实例化。实例化对象时,须要分配内存,而后这些内存被初始化并保存一些有用的默认值,这些值不一样于你在得到新分配内存时获得的随机值。内存分配和初始化完成后,就建立了一个新的对象实例。
15.继承
建立一个新类时,一般须要定义新类以区别于其余类以及现有类。使用继承能够定义一个具备父类全部功能的新类,它继承了父类的这些功能。
objective-c没有多继承。
建立一个新类时,其对象首先从自身的超类中继承实例变量,而后添加他们本身的实例变量。
超类
父类
子类
孩子类
重写
方法调度:objective-c的方法调度程序将子当前类中搜索响应的方法。若是调度程序没法在接受消息的对象类中找到响应的方法,它就会在该类的超类中进行查找。顺着继承链找到下一个超类进行查找,直到NSObject类中也没有该方法,则会出现运行时错误。
16.复合
对象引用其余对象时,能够利用其余对象提供的特性,这就是复合。
17.UML
UML是一种用图表表示类,类的内容以及他们之间关系的常见方法。
18.多态
使用更具体种类的对象(子类对象)代替通常类型(父类),这种能力称为多态性。
19.self
是一个指向接收消息的对象的指针。指向第一个实例变量isa。由于objective-c编译器已经看到了全部这些类的@interface声明,所以,它能直到对象中实力变量的布局,经过这些重要的信息,编译器能够产生代码并查找任何须要的实例变量。
基地址加偏移:编译器使用“基地址加偏移”机制实现奇妙的功能。给定的对象基地址,是指第一个实例变量的首个字节在内存中得位置,经过在该地址加上偏移地址,编译器就能够查到其余实例变量的位置。
20.间接寻址方式,直接寻址方式
21.super
objective-c提供某种方式来重写方法,而且仍然调用超类的实现方式。当须要超类实现自身的功能,同时在前面或者后面执行某些额外的工做时,这种机制很是有用。为了调用继承方法的实现,须要使用super做为方法调用的目标。
22.cocoa
cocoa其实是由2个不一样的框架组成的:Foundation Kit和 Application Kit。Application Kit包含了全部的用户接口对象和高级类。
Foundation Kit
23.NSAutoreleasePool
mian()函数建立了(经过alloc)并初始化(经过init)了一个NSAutoreleasePool实例。在mian()函数结尾,这个池被排空。这就是Cocoa内存管理的预览。
24.NSRange
typedef struct _NSRange {
unsigned int location;
unsigned int length;
}NSRange;
这个结构体用来表示相关事务的范围,一般是字符串里的字符范围或者数组里的元素范围。
25.三种赋值方式
1.NSRange range;
range.location = 17;
range.length = 4;
2.C语言的聚合结构赋值机制
NSRange range = {17, 4};
3.Cocoa提供的一个快捷函数NSMakeRange()
NSRange range = NSMakeRange(17, 4);
使用NSMakeRange()的好处是你能够在任何可以使用函数的地方使用它,例如在方法调用中将其当成参数传递。
26.几何数据类型
1.NSPoint 表明笛卡儿平面中得一个点(x, y).
typedef struct _NSPoint {
float x;
float y;
}NSPoint;
2.NSSize 用来存储长度和宽度
typedef struct NSSize {
float width;
float height;
}NSSize;
3.NSRect 矩形数据类型,它是由点和大小复合而成
typedef struct _NSRect {
NSPoint origin;
NSSize size;
}NSRect;
27.字符串NSString
stringWithFormat:就是一个工厂方法,它根据你提供的参数建立新对象。
length:长度
isEqualToString:比较字符串内容是否相同
compart:将接受对象和传递来的字符串逐个字符的进行比较。返回一个enum数据
NSCaseInsensitiveSearch:不区分大小写字符。
NSLiteralSearch:进行彻底比较,区分大小写
NSNumericSearch:比较字符串的字符个数,而不是字符值。
-(NSRange)rangeOfString:(NSString *)aString;
返回的range.start为开始位置,range.length为长度。
28.NSMutableString可变字符串。
stringWithCapacity:建立一个新的NSMutableString
字符串的大小并不只限于所提供的容量,这个容量仅是个最优值。若是要建立一个40mb的字符串。
NSMutableString *str = [NSMutableString stringWithCapacity:42];
appendString接受参数aString,而后将其复制到接收对象的末尾。
appendFormat与stringWithFormat:相似,但它将格式化的字符串附加在接收字符串的末尾,而不是建立新的字符串对象。
29.集合家族
1.NSArray:是一个Cocoa类,用来存储对象的有序列表。
两个限制:1.只能存储objective-c的对象,不能存储C语言中得基本数据类型。
2.也不能存储nil。
30.枚举器,快速枚举
31.NSDictionary字典
关键字及其定义的集合。
32.NSNumber包装(以对象形式实现)基本数据类型
装箱:将一个基本类型的数据包装成对象。
取消装箱:从对象中提取基本类型的数据。
objective-c不支持自动装箱。
33.NSValue是NSNumber的父类。
+(NSValue *)valueWithBytes:(const void *)value objCType:(const char *)type;
传递的参数是你想要包装的数值的地址(如一个NSSize或你本身的struct)。一般,获得的是你想要存储的变量的地址(在C语言中使用操做符&)。你也能够提供一个用来描述这个数据类型的字符串,一般用来讲明struct中实体的类型和大小。你不用本身写代码来生成这个字符串,@encode编译器指令能够接受数据类型的名称并为你生成合适的字符串。
NSRect rect = NSMakeRect(1, 2, 30, 40);
NSValue *value;
value = [NSValue valueWithBytes:&rect objCType:@encode(NSRect)];
[array addObject:value];
34.NSNull只有一个方法[NSNull null];
[NSNull null]老是返回同样的数值,因此你能够使用运算符==将该值与其余值进行比较。
35.单实例架构:只须要一个实例。
查找文件:
例如:NSFileManager *manager;
manager = [NSFileManager defaultManager];
defaultManager能够为咱们建立一个属于咱们本身的NSFileManger对象。
NSString *home = [@"~" stringByExpandingTildeInPath];将~替换成当前用户的主目录。
NSDirectoryEnumerator *direnum = [manager enumeratorAtPath:home];返回一个NSDictionaryEnumerator,它是NSEnumerator的子类。每次在这个枚举器对象中调用nextObject时,都会返回该目录中得一个文件的另外一个路径。
36.内存管理
1)对象生命周期
对象的生命周期包括诞生(alloc或者new方法实现),生存(接受消息和执行操做),交友(借助方法的组合和参数)以及当他们的生命结束时最终死去(被释放)。当对象的生命周期结束时,他们的原材料(内存)将被回收以供新的对象使用。
2)引用计数
cocoa采用了一种称为引用计数的技术,有时候也叫保留计数。每一个对象有一个与之相关联的整数,称做它的引用计数器或保留计数器。当某段代码须要访问一个对象时,该代码将该对象的保留计数器值+1,表示“我要访问该对象”。当这段代码结束对象访问时,将对象的保留计数器值-1,表示它再也不访问该对象,当保留计数器值为0时,表示再也不有代码访问该对象了,所以该对象被销毁,其占用的内存被系统回收以便重用。
alloc,new,copy 1
retain +1
release -1
3)对象全部权
若是一个对象具备指向其余对象的实力变量,则称该对象拥有这些对象。
在类A中 B对象拥有其指向的C对象,则B对象拥有C对象。
若是一个函数建立了一个对象,则称该函数拥有它建立的这个对象。
main()函数建立了对象a 称main()函数拥有a对象
当多个实体拥有某个特定的对象时,对象的全部权关系就更加复杂了,这也是保留计数器值可能大于1的缘由。
例子:
main() {
Engine *engine = [Engine new];
[car setEngine:engine];
}
如今哪一个实体拥有engine对象?是main函数仍是car类?哪一个实体负责确保当engine对象再也不被使用时可以收到release消息?由于car类正在使用engine对象,因此不多是main函数。由于main函数随后还可能会使用engine对象,因此也不多是car类。
解决方法是让car类保留engine对象,将engine对象的保留计数器值增长到2。这是由于car类和main函数这2个实体都正在使用engine对象。car类应该在setEngine:方法中保留engine对象,而main函数应该释放engine对象。而后,当car类完成其任务时再释放engine对象(在其dealloc方法中),最后engine对象占用的资源被回收。
若是您使用名字以“alloc”或“new”开头或名字中包含“copy”的方法(例如alloc,newObject或mutableCopy)建立了一个对象,则您会得到该对象的全部权;或者若是您向一个对象发送了一条retain消息,则您也会得到该对象的全部权。
4)访问方法中得保留和释放
5)自动释放池NSAutoreleasePool
是一个存放实体的池(集合)。你能够用NSMutableArray来编写本身的自动释放池,以容纳对象并在dealloc方法中向池中得全部对象发送release消息。
autorelease
当给一个对象发送autorelease消息时,其实是将该对象添加到NSAutoreleasePool中。当自动释放池被销毁时,会向该池中得全部对象发送release消息。
6)自动释放池的销毁时间
在咱们一直使用的Foudation库工具中,建立和销毁自动释放池的方法很是明确:
NSAutoreleasePool *pool;
pool = [[NSAutoreleasePool alloc] init];
...
[pool release];
建立一个自动释放池时,该池自动成为活动的池。释放该池时,其保留计数器值归0,而后该池被销毁。在销毁的过程当中,该池释放其包含的全部对象。当使用Application Kit时,cocoa按期自动为你建立和销毁自动释放池。一般是在程序处理完当前事件之后执行这些操做。你能够使用任意多得自动释放对象,当再也不使用它们时,自动释放池将自动为你清理这些对象。
你可能已经在xcode自动生成代码中碰见过另外一种销毁自动释放池中对象的方式:-drain方法。该方法只是清空自动释放池而不是销毁它。而且只适用于mac os x10.4以上的版本。
7)自动释放池的工做过程
咱们在任什么时候候向一个对象发送autorelease消息,该对象都会呗添加到这个自动释放池中。被加入到自动释放池的对象的引用计数器值不会变化。当自动释放池被销毁时(向自动释放池发送release消息,自动释放池的引用计数器值变为0,调用自身的dealloc函数),会调用自身的dealloc函数,会向池中得对象发送release消息。
37.cocoa内存管理规则
1)当你使用new,alloc或copy方法建立一个对象时,该对象的保留计数器值为1。当再也不使用该对象时,你要负责向该对象发送一条release或autorelease消息。这样,该对象将在其使用寿命结束时被销毁。
2)当你经过任何其余方法得到一个对象时,则假设该对象的保留计数器值为1,并且已经被设置为自动释放,你不须要执行任何操做来确保该对象被清理。若是你打算在一段时间内拥有该对象,则须要保留它并确保在操做完成时释放它。
3)若是你保留了某个对象,你须要(最终)释放或自动释放该对象。必须保持retain方法和release方法的使用次数相同。
38.清理自动释放池
因为自动释放池的销毁时间是彻底确立的,因此它在循环执行过程当中不会被销毁。在迭代中或者循环中,须要创建本身的自动释放池。
39.垃圾回收gc
自动内存管理机制。objective-c的垃圾回收器是一种继承性的垃圾回收器。与那些已经存在了一段时间的对象相比,新建立的对象更可能被当成垃圾。垃圾回收器按期检查变量和对象以及他们之间的指针,当发现没有任何变量指向某个对象时,就将该对象视为应该被丢弃的垃圾。若是你再一个实例变量中指向某个对象,必定要在某个时候使该实例变量赋值为nil,以取消对该对象的引用并使垃圾回收器知道该对象能够被清理了。
与自动释放池同样,垃圾回收器也是在时间循环结束时才触发。
ARC是什么?
ARC是iOS 5推出的新功能,全称叫 ARC(Automatic Reference Counting)。简单地说,就是代码中自动加入了retain/release,原先须要手动添加的用来处理内存管理的引用计数的代码能够自动地由编译器完成了。
该机能在 iOS 5/ Mac OS X 10.7 开始导入,利用 Xcode4.2 能够使用该机能。简单地理解ARC,就是经过指定的语法,让编译器(LLVM 3.0)在编译代码时,自动生成实例的引用计数管理部分代码。有一点,ARC并非GC,它只是一种代码静态分析(Static Analyzer)工具。
40.分配
是一个新对象诞生的过程。是从操做系统得到一块内存并将其指定为存放对象的实例变量的位置。
40.初始化
与分配对应的操做是初始化。初始化从操做系统取得一块内存。准备用于存储对象。
嵌套调用技术很是重要,由于初始化方法返回的对象可能与分配的对象不一样。
1)初始化时作什么?
给实例变量赋值并建立你得对象完成任务所须要的其余对象。
2)便利初始化函数
许多类包含便利初始化函数。用来完成某些额外的工做的初始化方法,能够减小你本身完成这些工做的麻烦。
例如:NSString类中-(id)initWithFormat:(NSString *)format,...;
3)指定初始化函数
类中的某个初始化方法被指派为指定初始化函数。该类全部初始化方法使用指定初始化函数执行初始化操做。子类使用其超类的指定初始化函数实现超类的初始化。
例如:其余初始化函数经过指定初始化函数实现。
41.初始化函数规则
不须要为你本身的类建立初始化函数方法。若是不须要设置任何状态,或者只须要alloc方法将内存清零的默认行为,则不须要担忧init。
若是构造了一个初始化函数,则必定要在你本身的指定初始化函数中调用超类的指定初始化函数。必定要将超类的初始化函数的值赋给self对象,并返回你本身的初始化方法的值。由于超类可能决定返回一个彻底不一样的对象。
若是初始化函数不止一个,则要选择一个座位指定初始化函数。被选定的方法应该调用超类指定初始化函数。要按照指定初始化函数的形式实现全部其余初始化函数,就像咱们在前面的实现同样。
42.特性@property
objective-c2.0的特性只适用于mac os x 10.5或更高版本。特性主要应用于cocoa的新组件(尤为是华丽夺目的core Animation效果)。
1)简化接口
@property预编译指令的做用是自动生命属性的setter和getter方法。
2)@synthesize也是一种新的编译器功能,表示“建立该属性的访问器”。
3)点表达式
若是点表达式出如今=左边,该属性名称的setter方法(set方法)将被调用。若是点表达式出如今对象变量右边,则该属性名称的getter方法(get方法)将被调用。
4)特性扩展
@property()括号里面的东西,是对应在set方法中要添加的语句。好比我在括号里写retain,就至关于在它的set方法里添加了一句 [xx retain]。
@property属性
属性分为3类:
1.读写属性(Writability)包含:readwrite / readonly
2.setter语义(Setter Semantics)包含:assign / retain / copy
3.原子性(Atomicity)包含:nonatomic
下面具体说明各个属性的含义
readwrite / readonly:
决定是否生成set访问器,readwrite是默认属性,生成getter和setter方法;readonly只生成getter方法,不生成setter方法。
readonly关键字表明setter不会被生成, 因此它不能够和 copy/retain/assign组合使用。
assign / retain / copy:
这些属性用于指定set访问器的语义,也就是说,这些属性决定了以何种方式对数据成员赋予新值。
assign:
直接赋值,索引计数不改变,适用于简单数据类型,例如:NSIngeter、CGFloat、int、char等。
retain:
指针的拷贝,使用的是原来的内存空间。
对象的索引计数加1。
此属性只能用于Objective-C对象类型,而不能用于Core Foundation对象。(缘由很明显,retain会增长对象的引用计数,而基本数据类型或者Core Foundation对象都没有引用计数)。
copy:
对象的拷贝,新申请一块内存空间,并把原始内容复制到那片空间。
新对象的索引计数为1。
此属性只对那些实行了NSCopying协议的对象类型有效。
不少Objective-C中的object最好使用用retain,一些特别的object(例如:string)使用copy。
nonatomic:
非原子性访问,不加同步,多线程并发访问会提升性能。若是不加此属性,则默认是两个访问方法都为原子型事务访问。默认值是atomic,为原子操做。
(atomic是Objc使用的一种线程保护技术,基本上来说,是防止在写未完成的时候被另一个线程读取,形成数据错误。而这种机制是耗费系统资源的,因此在iPhone这种小型设备上,若是没有使用多线程间的通信编程,那么nonatomic是一个很是好的选择。)
5)保留周期retain cycle
引用计数器在该周期中归零。
6)什么是属性访问器
属性访问器(Property Accessor),包括 get 访问器和 set 访问器分别用于字段的读写操做
其设计目的主要是为了实现面向对象(OO)中的封装思想。根据该思想,字段最好设为private,一个精巧的类最好不要直接把字段设为公有提供给客户调用端直接访问
另外要注意属性自己并不必定和字段相联系
7)self.a与a的区别
self.a使编译器知道咱们指望使用访问器访问a。若是只使用裸名a,编译器将假设咱们直接修改了实例变量。
8)self.a = nil
这行代码表示使用nil参数调用setName:方法。生成的访问器方法将自动释放之前的name对象,并使用nil替代a。该方法完成了释放name对象所占用内存的操做。固然,也能够只释放name对象以清理其占用的内存。若是你再dealloc方法之外的地方清除特性,那么使用"将nil赋值给对象"的方法能够将特性设置为nil,同时能够使咱们避免对已释放内存的悬空引用问题。
9)特性不是万能的
有些方法不适合特性所能涵盖的方法的至关狭小的范围。特性不支持那些须要接受额外参数的方法。
43.类别@category
1)声明类别
@interface NSString (NumberConvenience)
-(NSNumber *)lengthAsNumber;
该声明具备2个特色。首先,现有类位于@interface关键字以后,其后是位于圆括号中的一个新名称。该声明表示,类别的名称是NumberConvenience,并且该类别将向NSString类中添加方法。只要保证类别名称的惟一性,你能够向一个类中添加任意多得类别。
其次,你能够指定但愿向其添加类别的类以及类别的名称,并且你还能够列出添加的方法,最后以@end结束。因为不能添加新实现变量,所以与类声明不一样的是,类别的声明中没有实例变量部分。
2)实现类别
3)类别的局限性
第一,没法向类中添加新的实例变量。类别没有位置容纳实例变量。
第二,名称冲突,即类别中得方法与现有的方法重名。当发生名称冲突时,类别具备更高的优先级。你得类别方法将彻底取代初始方法,从而没法再使用初始方法。有些编程人员在本身的类别方法中增长一个前缀,以确保不发生名称冲突。
有一些技术能够克服类别没法增长新实例变量的局限。例如,能够使用全局字典存储对象与你想要关联的额外变量之间的映射。但此时你可能须要认真考虑一下,类别是不是完成当前任务的最佳选择。
4)类别的做用
cocoa中得类别主要用于3个目的:第一,将类的实现分散到不一样文件或者不一样框架中。第二,建立对私有方法的前向引用。第三,向对象添加非正式协议。
44.run循环是一种cocoa构造,它一直处于阻塞状态(即不执行任何处理),知道某些事件发生为止。
45.响应选择器
一个类别如何知道其委托对象是否可以处理那些发送给它的消息?
类别首先检查对象,询问其可否响应该选择器。若是该对象可以响应该选择器,
1)选择器@selector()
选择器只是一个方法名称,但它以objective-c运行时使用的特殊方式编码,以快速执行查询。你能够使用@selector()预编译指令选择器,其中方法名位于圆括号中。
46.委托 非正式协议
47.正式协议
与非正式协议同样,正式协议是一个命名的方法列表。但与非正式协议不一样的是,正式协议要求显式的采用协议。采用协议的办法是在类的@interface声明中列出协议名称。采用协议意味着你承诺实现该协议的全部方法。
1)声明协议
@protocol NSCopying
-(id)copyWithZone:(NSZone *)zone;
2)采用协议
@interface Car: NSObject <NSCopying>
{
}
3)协议和数据类型
若是一个用尖括号括起来的协议名称跟随在id以后,则编译器将知道你指望任意类型的对象,只要其遵照该协议。
4)objective-c2.0的新特性@optional @required
@optional可选择实现的方法
@required必须实现的方法
所以cocoa中得非正式协议正被带有@optional的正式协议所取代。
48.Application Kit
1)IBOutlet与IBAction
他们实际上只是APPKit提供的#defines。IBOutlet的定义没有任何做用,所以将不会对它进行编译。IBAction定义为void,这意味着在AppController中声明的方法的返回类型将使void。IBOutlet和IBAction不执行任何操做,他们并非用于编译的,实际上他们是为Interface Builder以及阅读代码的人提供的标记。经过查找IBOutlet和IBAction,Interface Builder知道AppController对象具备两个可以链接的实例变量。
2)IBOutlet是如何工做的
当加载nib文件时(MainMenu.nib会在应用程序启动时自动加载,能够建立你本身的nib文件并自行加载),存储在nib文件中得任何对象都会被从新建立。这意味着会再后台执行alloc和init方法。因此,当应用程序启动时,会分配并初始化一个AppController实例。在执行init方法期间,全部IBOutlet实例变量都为nil。只有建立了nib文件中得全部对象(这包括窗口和文本域和按钮),全部链接才算完成。
一旦创建了全部链接(也就是将NSTextField对象的地址添加到AppController的实例变量中),会向建立的每一个对象发送消息awakeFromNib。一个很是常见的错误是试图在init方法中使用IBOutlet执行一些操做。因为全部实例变量都为nil,发送给他们的全部消息不执行任何操做,因此在init中得任未尝试都会发生无提示失败。(这是Cocoa致使效率低和占用大量调试时间的一个方面)。若是你想知道为何这些操做不起做用,能够使用NSLog输出实例变量的值,并查看他们是否都为nil。对于建立的对象和发送的awakeFromNib消息,都不存在预约义顺序。
文件加载与保存
49.属性列表
1)自动释放对象
NSDate
NSData NSData对象是不可改变的。他们被建立后就不能改变。能够使用他们,但不能改变其中的内容。
2)编码对象 编码和解码
cocoa具有一种机制来将对象自身转换为某种格式并保存到磁盘中。对象能够将他们的实例变量和其余数据块编码为数据块,而后保存到磁盘中。之后将这些数据块读回到内存中,而且还能基于保存的数据建立新对象。这个过程称为编码和解码。或称为序列化和反序列化。
50.键/值编码 KVC
是一种间接改变对象状态的方式,其实现方法是使用字符串描述要更改的对象状态部分。
1)valueForKey与setValue:forKey:
这两种方法的工做方式相同。他们首先查找名称的setter(getter)方法,若是不存在setter(getter)方法,他们将在类中查找名为名称或_名称的实例变量。而后给它赋值(取值)。无需经过对象指针直接访问实例变量。
2)路径
键路径的深度是任意的,具体取决于对象图。
键路径不只能引用对象值,还能够引用一些运算符来进行一些运算,例如获取一组值的平均值或返回这组值中得最小值和最大值。
例如:NSNumber *count;
count = [garage valueForKeyPath:@"cars.@count"];
NSLog(@"We have %@ cars", count);
咱们将路径“cars.@count”拆开,cars用于获取cars属性,它是来自garage的NSArray类型的值。接下来的部分是@count ,其中@符号意味着后面将进行一些运算。
和 cars@sun.mileage
最大值 cars@min.mileage
最小值 cars@max.mileage
3)总体操做
KVC很是棒的一点是,若是向NSArray请求一个键值,它实际上会查询数组中得每一个对象来查找这个键值,而后将查询结果打包到另外一个数组中并返回给你。这种方法也适用于经过键路径访问的对象内部的数组。
4)批处理
KVC包含两个调用,能够使用他们对对象进行批量更改。第一个调用是dictionaryWith-ValuesForKeys:。它接受一个字符串数组。该调用获取一些键,对每一个键使用valueForKey:,而后为键字符串和刚才获取的值构建一个字典。