XSLT存档  

不及格的程序员-八神

 查看分类:  ASP.NET XML/XSLT JavaScripT   我的MSN空间Blog
posts - 175,  comments - 1171,  trackbacks - 0

1、Object-C有多继承吗?没有的话用什么代替?

cocoa 中所有的类都是NSObject 的子类
多继承在这里是用protocol 委托代理 来实现的
你不用去考虑繁琐的多继承 ,虚基类的概念.
ood
的多态特性  obj-c 中通过委托来实现.
 
2、Object-C有私有方法吗?私有变量呢?
objective-c – 类里面的方法只有两种, 静态方法和实例方法. 这似乎就不是完整的面向对象了,按照OO的原则就是一个对象只暴露有用的东西. 如果没有了私有方法的话, 对于一些小范围的代码重用就不那么顺手了. 在类里面声名一个私有方法
@interface Controller : NSObject { NSString *something; }
+ (void)thisIsAStaticMethod;
– (void)thisIsAnInstanceMethod;
@end
@interface Controller (private) -
(void)thisIsAPrivateMethod;
@end
@private可以用来修饰私有变量
在Objective‐C中,所有实例变量默认都是私有的,所有实例方法默认都是公有的
 
 
3、关键字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 类型,以使得其返回值不为“左值”。
 +++++++++++++

使用指针 会涉及到两个对象 一个是指针本身,另一个是它指向的对象. 将指针声明为 const 就使对象为常量而不是指针为常量;

例如:

const char* p = "asdf";//指向常量的指针

p[2] = ‘d’;//wrong

p = "defc";//right

要把指针本身而不是它指向的对象声明为常,要运用 运算符 *const

char *const p = "asdf"; //常量指针

p[2] = ‘d’; // 正确

p = "defc"; //错误

要使两个对象都是常量,二者都要声明为const;

const char *const p = "asdf"; //指向常量的常指针

p[2] = ‘d’; // wrong

p = "defc"; //wrong

一对象当通过一个指针访问是常量,而用其它方法访问时可能是变量,这对于函数参数特别有用.

声明为一个const的指针参数,就禁止函数修改参数批向的对象.

char* strcpy (char* p, const char* q); //不能修改*q

 
4、关键字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 成员变量。
 
 
6、#import和#include的区别,@class代表什么?
@class一般用于头文件中需要声明该类的某个实例变量的时候用到,在m文件中还是需要使用#import
而#import比起#include的好处就是不会引起重复包含
 
7、线程和进程的区别?
进程和线程都是由操作系统所体会的程序运行的基本单元,系统利用该基本单元实现系统对应用的并发性。
进程和线程的主要差别在于它们是不同的操作系统资源管理方式。进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差一些。但对于一些要求同时进行并且又要共享某些变量的并发操作,只能用线程,不能用进程。
 
 
8、堆和栈的区别?
管理方式:对于栈来讲,是由编译器自动管理,无需我们手工控制;对于堆来说,释放工作由程序员控制,容易产生memory leak。
申请大小:
栈:在Windows下,栈是向低地址扩展的数据结构,是一块连续的内存的区域。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的,在WINDOWS下,栈的大小是2M(也有的说是1M,总之是一个编译时就确定的常数),如果申请的空间超过栈的剩余空间时,将提示overflow。因此,能从栈获得的空间较小。
堆:堆是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。
碎片问题:对于堆来讲,频繁的new/delete势必会造成内存空间的不连续,从而造成大量的碎片,使程序效率降低。对于栈来讲,则不会存在这个问题,因为栈是先进后出的队列,他们是如此的一一对应,以至于永远都不可能有一个内存块从栈中间弹出
分配方式:堆都是动态分配的,没有静态分配的堆。栈有2种分配方式:静态分配和动态分配。静态分配是编译器完成的,比如局部变量的分配。动态分配由alloca函数进行分配,但是栈的动态分配和堆是不同的,他的动态分配是由编译器进行释放,无需我们手工实现。
分配效率:栈是机器系统提供的数据结构,计算机会在底层对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高。堆则是C/C++函数库提供的,它的机制是很复杂的。
 
 
9、Object-C的内存管理?
1.当你使用new,alloc和copy方法创建一个对象时,该对象的保留计数器值为1.当你不再使用该对象时,你要负责向该对象发送一条release或autorelease消息.这样,该对象将在使用寿命结束时被销毁.
2.当你通过任何其他方法获得一个对象时,则假设该对象的保留计数器值为1,而且已经被设置为自动释放,你不需要执行任何操作来确保该对象被清理.如果你打算在一段时间内拥有该对象,则需要保留它并确保在操作完成时释放它.
3.如果你保留了某个对象,你需要(最终)释放或自动释放该对象.必须保持retain方法和release方法的使用次数相等.
 
 
 
10、为什么很多内置的类,如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模式时,也要注意这点。
 
 
11、定义属性时,什么情况使用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];
}
 
 
12、对象是什么时候被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
 
 
 
13、iOS有没有垃圾回收?
Objective-C 2.0也是有垃圾回收机制的,但是只能在Mac OS X Leopard 10.5 以上的版本使用。
 
 
 
14、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就可以正常重用了。
 
 
 
15、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还是继续做它该做的事情
 
 
 
16、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中释放这些引用。
 
 
 
17、列举Cocoa中常见的集中多线程的实现,并谈谈多线程安全的几种解决办法,一般什么地方会用到多线程?
NSThread,GCD等。尽量用上层分装好的方法去实现多线程而不是手动调用NSThread。
 
 
18、怎么理解MVC,在Cocoa中MVC是怎么实现的?
Model: 代表你的应用程序是什么(不是怎么展现)
Controller: 控制你的Model怎么展现给用户(UI逻辑)
View: Controller的奴隶。。。

Model,Controller,View相互通讯的规则:
  1. Controller可以直接和Model通信
  2. Controller也可以直接和View通信
  3. Model和View永远不能直接通信
  4. iOS中View和Controller的通信是透明和固定的,主要通过outlet和action实现
  5. View使用Delegate接口和Controller同步信息
  6. View不直接和数据通信,使用dataSource接口从Controller处获取数据
  7. View的delegate和dataSource一般就是Controller
  8. Controller负责为View翻译和格式化Model的数据
  9. Model使用Notification & KVO的方式分发数据更新信息,Controller可以有选择的监听自己感兴趣的信息。
  10. View也可以监听广播信息,但一般不是Model发出的信息
  11. 一个完整的App就是很多MVC的集合
 
 

19、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什么区别?


21、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) (idSEL, …)。这样说来, IMP是一个指向函数的指针,这个被指向的函数包括id(“self”指针),调用的SEL(方法名),再加上一些其他参数.说白了IMP就是实现方法。

 

 


22、内存管理 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的)

 


23、类别的作用?

 

有时我们需要在一个已经定义好的类中增加一些方法,而不想去重写该类。比如,当工程已经很大,代码量比较多,或者类中已经包住很多方法,已经有其他代码调用了该类创建对象并使用该类的方法时,可以使用类别对该类扩充新的方法。

  注意:类别只能扩充方法,而不能扩充成员变量。

 


24、委托(举例)

 

委托代理(degegate),顾名思义,把某个对象要做的事情委托给别的对象去做。那么别的对象就是这个对象的代理,代替它来打理要做的事。反映到程序中,首先要明确一个对象的委托方是哪个对象,委托所做的内容是什么。

委托机制是一种设计模式,在很多语言中都用到的,这只是个通用的思想,网上会有很多关于这方面的介绍。

那么在苹果开发过程中,用到委托的程序实现思想如下,我主要拿如何在视图之间传输信息做个例子。

譬如:在两个页面(UIIview视图对象)实现传值,用委托(delegate)可以很好做到!

方法:

类A

@interface A:UIView

        id transparendValueDelegate;

       @property(nomatic, retain) id transparendValueDelegate;

@end

 

@implemtion A

@synthesize transparendValueDelegate

-(void)Function

      NSString* value = @"hello";

      //让代理对象执行transparendValue动作

      [transparendValueDelegate transparendValue: value];

}

@end

 

类B

@interface B:UIView

      NSString* value;

@end

@implemtion B

-(void)transparendValue:(NSString*)fromValue

{

      value = fromValue;

      NSLog(@"the value is %@ ",value); 

}

@end

 

//下面的设置A代理委托对象为B

//在定义A和B类对象处:

A* a = [[A alloc] init];

B* b = [[B alloc] init];

a. transparendValueDelegate = b;//设置对象a代理为对象b

这样在视图A和B之间可以通过委托来传值!


25、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显示的那样,如果一个响应者对象不能处理某个事件或动作-也就是说,它不响应那个消息,或者不认识那个事件,则将该消息重新发送给链中的下一个响应者。消息沿着响应者链向上、向更高级别的对象传递,直到最终被处理(如果最终还是没有被处理,就会被抛弃)。
The responder chain
当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过去了






34.objective-c有重载概念吗?

35. 单例(singleton)
 1 IOS中的单例模式
 2   在objective-c中要实现一个单例类,至少需要做以下四个步骤:
 3   1、为单例对象实现一个静态实例,并初始化,然后设置成nil,
 4   2、实现一个实例构造方法检查上面声明的静态实例是否为nil,如果是则新建并返回一个本类的实例,
 5   3、重写allocWithZone方法,用来保证其他人直接使用alloc和init试图获得一个新实力的时候不产生一个新实例,
 6   4、适当实现allocWitheZone,copyWithZone,release和autorelease。
 7 下面以SurveyRunTimeData为例子:
 8  
 9 static SurveyRunTimeData *sharedObj = nil; //第一步:静态实例,并初始化。
10 @implementation SurveyRunTimeData
11 + (SurveyRunTimeData*) sharedInstance  //第二步:实例构造检查静态实例是否为nil
12 {
13     @synchronized (self)
14     {
15         if (sharedObj == nil)
16         {
17             [[self alloc] init];
18         }
19     }
20     return sharedObj;
21 }
22 
23 + (id) allocWithZone:(NSZone *)zone //第三步:重写allocWithZone方法
24 {
25     @synchronized (self) {
26         if (sharedObj == nil) {
27             sharedObj = [super allocWithZone:zone];
28             return sharedObj;
29         }
30     }
31     return nil;
32 }
33 
34 - (id) copyWithZone:(NSZone *)zone //第四步
35 {
36     return self;
37 }
38 
39 - (id) retain
40 {
41     return self;
42 }
43 
44 - (unsigned) retainCount
45 {
46     return UINT_MAX;
47 }
48 
49 - (oneway void) release
50 {
51     
52 }
53 
54 - (id) autorelease
55 {
56     return self;
57 }
58 
59 - (id)init
60 {
61     @synchronized(self) {
62         [super init];//往往放一些要初始化的变量.
63         return self;
64     }
65 }

 

 1 //创建一个单例很多办法。我先列举一个苹果官方文档中的写法。
 2  
 3 
 4 static AccountManager *DefaultManager = nil;  
 5    
 6 + (AccountManager *)defaultManager {  
 7     if (!DefaultManager) DefaultManager = [[self allocWithZone:NULL] init];  
 8     return DefaultManager;  
 9 }  
10 
11 //当然,在iOS4之后有了另外一种写法:
12  
13  
14 [cpp] view plaincopy
15 
16 + (AccountManager *)sharedManager  
17 {  
18         static AccountManager *sharedAccountManagerInstance = nil;  
19         static dispatch_once_t predicate;  
20         dispatch_once(&predicate, ^{  
21                 sharedAccountManagerInstance = [[self alloc] init];   
22         });  
23     return sharedAccountManagerInstance;  
24 }  
25 
26 //该写法来自 objcolumnist,文中提到,该写法具有以下几个特性:
27  
28 //1. 线程安全。
29 //2. 满足静态分析器的要求。
30 //3. 兼容了ARC

 


c中static与extern的区别?

有几种情况:
首先,extern和static完全不同,extern不能定义一个变量,extern表示的是“已经存在一个变量,但是不在当前的编译单元内,需要在其他编译单元中寻找。”static会定义一个变量,但是分成多种情况。
---------------------------------------------------------------------
先说extern 和 变量的关系。

先说只有一个文件(编译单元)的:
int i=10; //这个是定义一个全局变量,值为10
extern int i=10; //这个是错误的,变量已经存在,怎么赋初值呢?
extern int i; //这个和第一句 int i=10; 可以同时存在在一个文件中。

再说跨文件(多个编译单元)的:
文件一:(假设这个文件没有错误!!)
int a=10;
文件二:
extern int a; // 这个正确
extern float a; // 这个编译不会错,赋值会怎样呢?
extern int b; //这个找不到
int a=9; //这个出错,全局变量多次定义
int a; //同上
static int a=9; //这个正确,这个产生一个仅在文件二中有效的全局变量a,初值为9,注意在文件二中将看不到那个值为10的全局变量!!!!

static就是刚才说的最后一种,此外就是函数内的使用了,不再多说了。
特别的,这样是错误的:
a.c:
static int x=10;
b.c:
extern int x; //因为x只在a.c中,b.c中根本看不到x,所以这个extern还是找不到x,因此会在链接时报错。
其他:extern尽量写到.h文件中,写到.c里就是错误的种子,以后它只能得到苦果!
static是静态存储类型,属于局部变量,只能用于同一个函数内,在其他函数内使用是错误的。extern是外部存储类型,属于全局变量,可以用于从他定义开始的后续所有函数内。

假设 在note1.c文件中定义static int A; 那么在note2.c文件中,是不能用A做为变量名吗?note2.c不能引用note1.c内的A,但是可以用A做变量名,切记:虽然都是命名为A,但是他们是不同的量
 

随笔- 99  文章- 0  评论- 16 

iOS面试题总结

 

目录


1. 多线程的底层实现?

1. 首先搞清楚什么是线程、什么是多线程

2. Mach是第一个以多线程方式处理任务的系统,因此多线程的底层实现机制是基于Mach的线程

3. 开发中很少用Mach级的线程,因为Mach级的线程没有提供多线程的基本特征,线程之间是独立的

4. 开发中实现多线程的方案

C语言的POSIX接口:#include <pthread.h>

OC的NSThread

C语言的GCD接口(性能最好,代码更精简)

OC的NSOperation和NSOperationQueue(基于GCD) 

2. 线程间怎么通信?

1. performSelector:onThread:withObject:waitUntilDone:

2. NSMachPort

3. 网络图片处理问题中怎么解决一个相同的网络地址重复请求的问题?

利用字典(图片地址为key,下载操作为value),具体可以查看SD缓存机制

4. 用NSOpertion和NSOpertionQueue处理A,B,C三个线程,要求执行完A,B后才能执行C,怎么做?

NSOperationQueue *queue = [[NSOperationQueue alloc] init];
NSOperation *A = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"SuperLog------  NSOperationA");
}];
NSOperation *B = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"SuperLog------  NSOperationB");
}];
NSOperation *C = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"SuperLog------  NSOperationC");
}];

[C addDependency:A];
[C addDependency:B];
[queue addOperation:A];
[queue addOperation:B];
[queue addOperation:C];

5. 列举cocoa中常见对几种多线程的实现,并谈谈多线程安全的几种解决办法及多线程安全怎么控制?

1. 只在主线程刷新访问UI
2. 如果要防止资源抢夺,得用synchronized进行加锁保护
3. 如果异步操作要保证线程安全等问题, 尽量使用GCD(有些函数默认就是安全的)

6. GCD内部怎么实现的?

1. iOS和OS X的核心是XNU内核,GCD是基于XNU内核实现的

2. GCD的API全部在libdispatch库中

3. GCD的底层实现主要有Dispatch Queue和Dispatch Source

Dispatch Queue :管理block(操作)

Dispatch Source :处理事件

7. 你用过NSOperationQueue么?如果用过或者了解的话,你为什么要使用NSOperationQueue,实现了什么?请描述它和GCD的区别和类似的地方(提示:可以从两者的实现机制和适用范围来描述)。

1. GCD是纯C语言的API,NSOperationQueue是基于GCD的OC版本封装
2. GCD只支持FIFO的队列,NSOperationQueue可以很方便地调整执行顺序、设置最大并发数量
3. NSOperationQueue可以在轻松在Operation间设置依赖关系,而GCD需要写很多的代码才能实现
4. NSOperationQueue支持KVO,可以监测operation是否正在执行(isExecuted)、是否结束(isFinished),是否取消(isCanceld)
5. GCD的执行速度比NSOperationQueue快

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

8. 既然提到GCD,那么问一下在使用GCD以及block时要注意些什么?它们两是一回事儿吗?block在ARC中和传统的MRC中的行为和用法有没有什么区别,需要注意些什么?

Block的使用注意:
1. block的内存管理
2. 防止循环retian

非ARC(MRC):__block
ARC:__weak\__unsafe_unretained

9. 在异步线程中下载很多图片,如果失败了,该如何处理?请结合RunLoop来谈谈解决方案.(提示:在异步线程中启动一个RunLoop重新发送网络请求,下载图片)。

1. 重新下载图片
2. 下载完毕, 利用RunLoop的输入源回到主线程刷新UIImageView

10. 怎么保证多人开发进行内存泄露的检查?

1. 使用Analyze进行代码的静态分析
2. 尽量使用ARC

11. 非自动内存管理情况下怎么做单例模式?

创建单例设计模式的基本步骤:

1. 声明一个单件对象的静态实例,并初始化为nil
2. 创建一个类的类工厂方法,当且仅当这个类的实例为nil时生成一个该类的实例
3. 实现NScopying协议, 覆盖allocWithZone:方法,确保用户在直接分配和初始化对象时,不会产生另一个对象
4. 覆盖release、autorelease、retain、retainCount方法, 以此确保单例的状态。 
5. 在多线程的环境中,注意使用@synchronized关键字或GCD,确保静态实例被正确的创建和初始化。 

12. 对于类方法(静态方法)默认是autorelease的,所有类方法都会这样吗?

1. 系统自带的绝大数类方法返回的对象,都是经过autorelease的

13. block在ARC中和MRC中的用法有什么区别,需要注意什么?

1. 对于没有引用外部变量的Block,无论在ARC还是非ARC下,类型都是__NSGlobalBlock__,这种类型的block可以理解成一种全局的block,不需要考虑作用域问题。同时,对他进行Copy或者Retain操作也是无效的
2. 应注意避免循环引用 

14. 什么情况下会发生内存泄漏和内存溢出?

1. 当程序在申请内存后,无法释放已申请的内存空间(例如一个对象或者变量使用完成后没有释放,这个对象一直占用着内存),一次内存泄露危害可以忽略,但内存泄露堆积后果很严重,无论多少内存,迟早会被占光。内存泄露会最终会导致内存溢出!
2. 当程序在申请内存时,没有足够的内存空间供其使用,出现out of memory;比如申请了一个int,但给它存了long才能存下的数,那就是内存溢出。

15. [NSArray arrayWithobject:(id)obj]这个方法添加对象后,需要对这个数组做释放操作吗?

不需要这个对象被放到自动释放池中 

16. 自动释放池底层怎么实现?

自动释放池以栈的形式实现:当你创建一个新的自动释放池时,它将被添加到栈顶。当一个对象收到发送autorelease消息时,它被添加到当前线程的处于栈顶的自动释放池中,当自动释放池被回收时,它们从栈中被删除, 并且会给池子里面所有的对象都会做一次release操作.

17. KVO内部实现原理是什么?

1. KVO是基于runtime机制实现的
2. 当某个类的对象第一次被观察时,系统就会在运行期动态地创建该类的一个派生类,在这个派生类中重写基类中任何被观察属性的setter方法。 
3. 派生类在被重写的 setter 方法实现真正的通知机制(NSKVONotifying_Class)

18. 是否可以把比较耗时的操作放在NSNotificationCenter中?

如果在异步线程发的通知,那么可以执行比较耗时的操作

如果在主线程发的通知,那么就不可以执行比较耗时的操作

19. Foundation对象与Core Foundation对象有什么区别?

1. Foundation对象是OC的,Core Foundation对象是C对象
2. 数据类型之间的转换
ARC:__bridge_retained、__bridge_transfer
非ARC: __bridge

20. 如何不用中间变量,用两种方法交换A和B的值?

A = A + B
B = A - B
A = A - B

A = A^B;
B = A^B;
A = A^B;

21. 简单描述下对单利模式设计的理解?

节省内存资源,一个应用就一个对象。

22. runtime实现的机制是什么,如何用,用来做什么?你所使用的相关的头文件或者某些方法的名称有哪些?

运行时机制,runtime库里面包含了跟类、成员变量、方法相关的API,比如获取类里面的所有成员变量,为类动态添加成员变量,动态改变类的方法实现,为类动态添加新的方法等 需要导入<objc/message.h> <objc/runtime.h>
1. runtime,运行时机制,它是一套C语言库
2. 实际上我们编写的所有OC代码,最终都是转成了runtime库的东西,比如类转成了runtime库里面的结构体等数据类型,方法转成了runtime库里面的C语言函数,平时调方法都是转成了objc_msgSend函数(所以说OC有个消息发送机制)。因此,可以说runtime是OC的底层实现,是OC的幕后执行者
3. 有了runtime库,能做什么事情呢?runtime库里面包含了跟类、成员变量、方法相关的API,比如获取类里面的所有成员变量,为类动态添加成员变量,动态改变类的方法实现,为类动态添加新的方法等。因此,有了runtime,想怎么改就怎么改

23. 是否使用Core Text或者Core Image等?如果使用过,请谈谈你使用Core Text或者Core Image的体验。

CoreText
1. 随意修改文本的样式
2. 图文混排(纯C语言)
3. 国外:Niumb
Core Image(滤镜处理)
- 能调节图片的各种属性(对比度, 色温, 色差等)

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

通知比较灵活(1个通知能被多个对象接收, 1个对象能接收多个通知)

代理比较规范,但是代码多(默认是1对1)

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

更详细参考:

原文

翻译

25. Block内部的实现原理

Objective-C是对C语言的扩展,block的实现是基于指针和函数指针

26. 有两个数组a和b,大小都为n,通过交换a,b中的元素,使sum(a)-sum(b)最小

算法题,百度自己学习。
思路
1. 计算 differ = sum(a) - sum(b)
2. 寻找 a b 数组中差值最接近differ/2 的元素
3. 交换元素

27. 如果后期需要增加数据库中的字段怎么实现,如果不使用CoreData呢?

编写SQL语句来操作原来表中的字段

1. 增加表字段
ALTER TABLE 表名 ADD COLUMN 字段名 字段类型;

2. 删除表字段
ALTER TABLE 表名 DROP COLUMN 字段名;

3. 修改表字段
ALTER TABLE 表名 RENAME COLUMN 旧字段名 TO 新字段名;

28. SQLite数据存储是怎么用?

1. 添加SQLite动态库
2. 导入主头文件:#import <sqlite3.h>
3. 利用C语言函数创建/打开数据库,编写SQL语句

29. 简单描述下客户端的缓存机制?

1. 缓存可以分为:内存数据缓存、数据库缓存、文件缓存
2. 每次想获取数据的时候
2.1 先检测内存中有无缓存
2.2 再检测本地有无缓存(数据库\文件)
2.3 最终发送网络请求
2.4 将服务器返回的网络数据进行缓存(内存、数据库、文件),以便下次读取

30. 你实现过多线程的Core Data么?NSPersistentStoreCoordinator,NSManagedObjectContext和NSManagedObject中的哪些需要在线程中创建或者传递?你是用什么样的策略来实现的?

1. CoreData是对SQLite数据库的封装
2. CoreData中的NSManagedObjectContext在多线程中不安全
3. 如果想要多线程访问CoreData的话,最好的方法是一个线程一个NSManagedObjectContext
4. 每个NSManagedObjectContext对象实例都可以使用同一个NSPersistentStoreCoordinator实例,这是因为NSManagedObjectContext会在便用NSPersistentStoreCoordinator前上锁

31. Core Data数据迁移

Core Data数据迁移

32. 怎么解决缓存池满的问题(cell)

ios中不存在缓存池满的情况,因为通常我们ios中开发,对象都是在需要的时候才会创建,有种常用的说话叫做懒加载,还有在UITableView中一般只会创建刚开始出现在屏幕中的cell,之后都是从缓存池里取,不会在创建新对象。缓存池里最多也就一两个对象,缓存池满的这种情况一般在开发java中比较常见,java中一般把最近最少使用的对象先释放。 

33. CAAnimation的层级结构

Core Animation Programming Guide

// cnblog mermaid 使用后,[TOC] 目录失效,所以暂时放上源码和一张截图。
 graph TB
 A(CAAnimation) --> B1(CAPropertyAnimation)
 A --> B2(CAAnimationGroup)
 A --> B3(CATransition)
 B1 --> C1(CABasicAnimation)
 B1 --> C2(CAKeyframeAnimation)
 C1 --> D(CASpringAnimation) 

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

如何找到最合适的视图
1. 自己是否能接收触摸事件
2. 触摸点是否在自己身上
3. 从后往前遍历子控件,重复前面的两个步骤
4. 如果没有符合条件的子控件,那么自己最适合处理

35. 控制器View的生命周期及相关函数是什么?你在开发中是如何用的?

1. 首先判断控制器是否有视图,如果没有就调用loadView方法创建(storyboard/代码)
2. 随后调用viewDidLoad,可以进行下一步的初始化操作(只会被调用一次)
3. 在视图显示之前调用viewWillAppear(该函数可以多次调用)
4. viewDidAppear 
3. 在视图显示之前调用viewWillDisappear;该函数可以多次调用(如需要)
5. 在布局变化前后,调用viewWill/DidLayoutSubviews处理相关信息

36. NSRunLoop的实现机制,及在多线程中如何使用?

NSRunLoop是iOS消息机制的处理模式
1. NSRunLoop的主要作用:控制NSRunLoop里面线程的执行和休眠,在有事情做的时候使当前NSRunLoop控制的线程工作,没有事情做让当前NSRunLoop的控制的线程休眠。
2. NSRunLoop 就是一直在循环检测,从线程start到线程end,检测inputsource(如点击,双击等操作)异步事件,检测timesource同步事件,检测到输入源会执行处理函数,首先会产生通知,corefunction向线程添加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只在你要和线程有交互时才需要

37. iOS7之前,后台执行内容有几种形式,都是什么?

一般的应用在进入后台的时候可以获取一定时间来运行相关任务,也就是说可以在后台运行一小段时间(10S左右)。
1. 后台播放音乐
2. 后台GPS跟踪
3. 后台voip支持

38. 简单说一下APP的启动过程,从main文件开始说起

程序启动分为两类:
1. 有storyboard 
2. 没有storyboard

情况一:
1.main函数
2.UIApplicationMain
* 创建UIApplication对象
* 创建UIApplication的delegate对象
3.根据Info.plist获得最主要storyboard的文件名,加载最主要的storyboard(有storyboard)
* 创建UIWindow
* 创建和设置UIWindow的rootViewController
* 显示窗口

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

39. 把程序自己关掉和程序进入后台,远程推送的区别?

1. 关掉后不执行任何代码,不能处理事件
2. 应用程序进入后台状态不久后转入挂起状态。在这种状态下,应用程序不执行任何代码,并有可能在任意时候从内存中删除。只有当用户再次运行此应用,应用才会从挂起状态唤醒,代码得以继续执行
3. 或者进入后台时开启多任务状态,保留在内存中,这样就可以执行系统允许的动作
4. 远程推送是由远程服务器上的程序发送到APNS,再由APNS把消息推送至设备上的程序,当应用程序收到推送的消息会自动调用特定的方法执行事先写好的代码
5. 本地通知和远程推送通知对基本概念和用法?
* 本地通知和远程推送通知都可以向不在前台运行的应用发送消息,这种消息既可能是即将发生的事件,也可能是服务器的新数据.不管是本地通知还是远程通知,他们在程序界面的显示效果相同,都可能显示为一段警告信息或应用程序图标上的微章.
* 本地通知和远程推送通知的基本目的都是让应用程序能够通知用户某些事情,而且不需要应用程序在前台运行.二者的区别在于本地通知由本应用负责调用,只能从当前设备上的iOS发出, 而远程通知由远程服务器上的程序发送到APNS,再由APNS把消息推送至设备上的程序

40. SIP是什么?

1. SIP(Session Initiation Protocol),会话发起协议
2. SIP是建立VOIP连接的 IETF 标准,IETF是全球互联网最具权威的技术标准化组织
3. 所谓VOIP,就是网络电话,直接用互联网打电话,不用耗手机话费

41. 有些图片加载的比较慢怎么处理?你是怎么优化程序的性能的?

1. 图片下载放在异步线程
2. 图片下载过程中使用占位图片
3. 如果图片较大,可以考虑多线程断点下载

42. 你实现过一个框架或者库以供别人使用么?如果有,请谈一谈构建框架或者库时候的经验;如果没有,请设想和设计框架的public的API,并指出大概需要如何做,需要注意一些什么方面,来使别人容易地使用你的框架。

1. 提供给外界的接口功能是否实用、够用
2. 能不能根据类名、方法名就猜出接口的具体作用
3. 提供的参数是否够用、调用起来是否简单
4. 要不要再导入依赖其他的框架

43. App需要加载超大量的数据,给服务器发送请求,但是服务器卡住了如何解决?

1. 设置请求超时
2. 给用户提示请求超时
3. 根据用户操作再次请求数据

44. 利用NSNotificationCenter实现跨多控制器传输数据和消息中用同步还是异步?

1. 如果通知是在主线程发出,那么接收通知的方法中的耗时操作要放到异步线程中
2. 如果通知实在异步线程中发出,那么接收通知后调用的方法会默认在异步线程中执行

45. SDWebImage具体如何实现?

1. 利用NSOperationQueue和NSOperation下载图片, 还使用了GCD的一些函数(解码GIF图片)
2. 利用URL作为key,NSOperation作为value
3. 利用URL作为key,UIImage作为value
待完善...

46. AFN 与 ASI 有什么区别

1. AFN基于NSURL,ASI基于底层的CFNetwork框架,因此ASI的性能优于AFN
2. AFN采取block的方式处理请求,ASI最初采取delegate的方式处理请求,后面也增加了block的方式
3. AFN只封装了一些常用功能,满足基本需求,直接忽略了很多扩展功能,比如没有封装同步请求;ASI提供的功能较多,预留了各种接口和工具供开发者自行扩展
4. AFN直接解析服务器返回的JSON、XML等数据,而ASI比较原始,返回的是NSData二进制数据 

47. Runloop定时源和输入源

1. 你创建的程序不需要显示的创建run loop;每个线程,包括程序的主线程(main thread)都有与之相应的run loop对象, 主线程会自行创建并运行run loop
2. Runloop处理的输入事件有两种不同的来源:输入源(input source)和定时源(timer source)
3. 输入源传递异步消息,通常来自于其他线程或者程序。定时源则传递同步消息,在特定时间或者一定的时间间隔发生

48. 如果在网络数据处理过程中,发现一处比较卡,一般怎么解决

1. 检查网络请求操作是否被放在主线程了
2. 看看异步请求的数量是否太多了(子线程数量)
3. 数据量是否太大?如果太大,先清除一些不必要的对象(看不见的数据、图片)
4. 手机CPU使用率和内存问题

49. 怎么解决sqlite锁定的问题

1. 设置数据库锁定的处理函数
int sqlite3_busy_handler(sqlite3*, int(*)(void*,int), void*);
2. 设定锁定时的等待时间
int sqlite3_busy_timeout(sqlite3*, 60);

50. 讲下主流框架的实现原理(AFNetworking SDWebImage)

 
posted on 2013-01-29 10:05  不及格的程序员-八神  阅读(...)  评论(...编辑  收藏