iOS面试整理

////大部分来自于网络 看着太多?那几 ctrl+F

问题1:求以下程序段的输出
int test(int x, int y){    
x = x + y;    
return  x * y;
}
int main(int argc, const char * argv[]){    
@autoreleasepool {   
     int x = 3, y = 10, z = test(x, y);        
NSLog(@"%d%d", x++, +
+z);    
}    
return 0;
}答案:3131
-----------------------------------------------------------------------
问题2:求以下程序段的输出
int func(int x){    
int countx = 0;    
while(x) {        
countx++;        x = x&(x-1);    
}    
return countx;
}int 
main(int argc, const char * argv[]){    
@autoreleasepool {        
NSLog(@"%d", func(2013));    
}    
return 0;
}答案:9
-----------------------------------------------------------------------
问题3:简述两个for循环的优缺点
for (i = 0; i < N; i++) {    
if (condition) {        
doSomeThing();    
} else {        
doOtherThing();  
  }}
if (condition) {    
for (i = 0; i < N; i++) {        
doSomeThing(); 
   }} else {    
for (i = 0; i < N; i++) {        
doOtherThing();    
}}
答案:循环判断N次;先判断,后执行
问题4:请指出下面代码的问题
UIView *tmpView = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
[self.view addSubview:tmpView];答案:[[UIScreen mainScreen] bounds] 和[UIScreen mainScreen] applicationFrame]的区别:bounds就是屏幕的全部区域,applicationFrame就是app显示的区域,不包含状态栏(高度20,如果状态栏隐藏的话,那么,这个结果就和bounds一样了
问题5:你所了解的单例有哪些?请写了一个单例的示例代码。
答案:
@interface Manager : NSObject
+ (id)sharedManager;
@endstatic Manager *instance = nil;
@implementation Manager
+ (id)sharedManager{    
if (!instance) {     
   instance = [[super allocWithZone:NULL] init];    
}    
return instance;
}// 复写allocWithZone和copyWithZone的目的是在外部多次调用alloc
的时候,内部能够确保对象只创建了一次
+ (id)allocWithZone:(NSZone *)zone{  
  return [[self sharedManager] retain];
}
- (id)copyWithZone:(NSZone *)zone{    
return self;
}// 复写retain、retainCount、release、autorelease
避免单件对象被外部释放
- (id)retain{    
return self;
}
- (NSUInteger)retainCount{    
return NSUIntegerMax;
}
- (void)release{}
- (id)autorelease{    
return self;
}
-----------------------------------------------------------------
-问题6:在你的日常开发过程中,是否遇到过崩溃问题?怎么解决?答案:无

问题7:请写出使用委托(代理)的示例代码。
答案:A委托B
H
@protocol ADelegate;
@interface A : NSObject
@property (nonatomic, assign) id<ADelegate> delegate;
- (void)go;
@end
@protocol ADelegate <NSObject>
- (void)doSomeThing;
@end
M
@implementation A
- (void)go{    
if ([_delegate respondsToSelector:@selector(doSomeThing)]) {        
[_delegate doSomeThing];    
}}
@end
B.h
#import "A.h"
@interface B : NSObject<ADelegate>
@end
B.m

@implementation B- (void)doSomeThing{    NSLog(@"do something...");}
@endman.m#import "A.h"#import "B.h"int main(int argc, const char * 
argv[]){    @autoreleasepool {        A *a = [[A alloc] init];        B 
*b = [[B alloc] init];        a.delegate = b;        [a go];        [a 
release];        [b release];    return 0;    }}// 输出do 
something...-----------------------------------------------------------
问题8:写出控制器加载视图的常规调用方法流程。
答案:loadView   viewDidLoad   viewWillAppear   viewWillLayoutSub viewsviewDidLayoutSubviews    viewDidAppear
--------------------------------------------------------------------------------
问题10:请写出下面代码的打印结果(默认在32位机器下运行)。char a[] = 
"hello world";char *p = a;NSLog(@"%ld", sizeof(a));NSLog(@"%ld", 
sizeof(p));答案:124如果在64位机器上运行128
-----------------------------------------------------------------------
问题11: 请完成下面的函数
@interface NSCustomArray : NSArray
@property (nonatomic, retain) NSArray *targets;
- (void)updateTargetsByArray:(NSArray *)newArray; 
// 将newArray赋值给targets
@end
@implementation NSCustomArray
- (void)updateTargetsByArray:(NSArray *)newArray{    
NSArray *tmpArray = [[NSArray alloc] initWithArray:newArray];    
// 将tmpArray赋值给targets}
@end答案:无---------------------------------------------------------------------

问题12:检查如下代码是否有问题,如果有问题,正确的写法是?
- (void)setTarget:(NSObject *)target{    self.target = target;}答案:无
---------------------------------------------------------------------
问题13:指出下面代码的问题
- (void)willEndStepOne:(NSObject *)userInfo{   
 [NSThread detachNewThreadSelector:@selector(doSomeThing:) 
toTarget:self withObject:userInfo];}
- (void)doSomeThing:(NSObject *)userInfo{    
int max_loop_times = 999999;    
for (int i=0; i<max_loop_times; i++) {        
int randNum = rand();        
NSString *tmpString = [NSString stringWithFormat:@"%d", randNum];        
NSLog (@"%@", tmpString);    
}}

3、你所了解的单例有哪些?请写了一个单例的示例代码
@interface Manager : NSObject
+ (id)sharedManager;
@end
static Manager *instance = nil;
@implementation Manager
+ (id)sharedManager{    
	if (!instance) {        
	instance = [[super allocWithZone:NULL] init];    
	}    
	return instance;
}
// 复写allocWithZone和copyWithZone的目的是在外部多次调用alloc的时候,内
部能够确保对象只创建了一次
+ (id)allocWithZone:(NSZone *)zone{    
	return [[self sharedManager] retain];
}
- (id)copyWithZone:(NSZone *)zone{    
	return self;
}
// 复写retain、retainCount、release、autorelease避免单件对象被外部释放
- (id)retain{    
	return self;
}
- (NSUInteger)retainCount{    
	return NSUIntegerMax;
}
- (void)release{}
- (id)autorelease{    
	return self;
}

4、请写出使用委托(代理)的示例代码
A委托B

A.h
@protocol ADelegate;
@interface A : NSObject
	@property (nonatomic, assign) id<ADelegate> delegate;
	- (void)go;
@end
@protocol ADelegate <NSObject>
	- (void)doSomeThing;
@end

A.m
@implementation A
- (void)go{    
	if ([_delegate respondsToSelector:@selector(doSomeThing)]) {    
    		[_delegate doSomeThing];    
	}}
@end

B.h
#import "A.h"
	@interface B : NSObject<ADelegate>
@end

B.m
@implementation B
- (void)doSomeThing{    
	NSLog(@"do something...");
}
@end

man.m
#import "A.h"
#import "B.h"
int main(int argc, const char * argv[]){    
@autoreleasepool {        
	A *a = [[A alloc] init];        
	B *b = [[B alloc] init];        
	a.delegate = b;        
	[a go];        
	[a release];        
	[b release];    
	return 0;    
}}
// 输出do something...

12、
 谈谈对Block 的理解?并写出一个使用Block执行UIVew动画?
答案:Block是可以获取其他函数局部变量的匿名函数,其不但方便开发,并且可
以大幅提高应用的执行效率(多核心CPU可直接处理Block指令)
[UIView transitionWithView:self.view  
   duration:0.2  options:UIViewAnimationOptionTransitionFlipFromLeft  
   animations:^{
 [[blueViewController view] removeFromSuperview]; [[self view] 
insertSubview:yellowViewController.view atIndex:0];
 }  
 completion:NULL];  


写一个NSString类的实现
+ (id)initWithCString:(const char *)nullTerminatedCString encoding:
(NSStringEncoding)encoding;

+ (id) stringWithCString: (const char*)nullTerminatedCString 
            encoding: (NSStringEncoding)encoding
{
  NSString  *obj;

  obj = [self allocWithZone: NSDefaultMallocZone()];
  obj = [obj initWithCString: nullTerminatedCString encoding: 
encoding];
  return AUTORELEASE(obj);
}

写一个setter方法用于完成@property (nonatomic,retain)NSString *name,
写一个setter方法用于完成@property(nonatomic,copy)NSString *name
答:
- (void) setName:(NSString*) str
{
[str retain];
[name release];
name = str;
}
- (void)setName:(NSString *)str
{
id t = [str copy];
[name release];	
name = t;
}


#define SECONDS_PER_YEAR (60 * 60 * 24 * 365)UL

使用GCD处理多线程,在多核心CPU下,会提高执行效率
- (void)gcdDownload
{
    
static dispatch_once_t once;
    
static dispatch_queue_t queue;    
//create download queue
    dispatch_once(&once, ^{        
queue =dispatch_queue_create
("com.xxx.download.background",DISPATCH_QUEUE_CONCURRENT);    
});
   
 //__block type
  __block BOOL downloadFlag = NO;
  dispatch_async(queue, ^{
//        downloadFlag = [Download sendRequest:request];    
NSLog(@"长时间任务,如网络下载");
});
dispatch_barrier_async(queue,^{        
if (downloadFlag) {         
NSLog(@"下载成功完成");  
}
dispatch_async(dispatch_get_main_queue(), ^{         
NSLog(@"执行完下载,回掉回主线程,例如刷新UI"); 
});                   
 });
}

1、
按位与运算符(&)--- 两位同时为“1”,结果才为“1”,否则为0
按位或运算符(|)---参加运算的两个对象只要有一个为1,其值为1。  
异或运算符(^)  ---如果两个相应位为“异”(值不同),则该位结果为1,否
则为0。
取反运算符(~) ----对一个二进制数按位取反,即将0变1,1变0。
左移运算符(<<)----将一个运算对象的各二进制位全部左移若干位(左边的二
进制位丢弃,右边补0)。
左移运算符(<<) ---- 将一个数的各二进制位全部右移若干位,正数左补0,负
数左补1,右边丢弃。操作数每右移一位,相当于该数除以2。
无符号右移运算符(>>>)--- 右移后左边空出的位用零来填充。移出右边的位被
丢弃。
不同长度的数据进行位运算----如果两个不同长度的数据进行位运算时,系统会
将二者按右端对齐,然后进行位运算。

2、 什么时候使用NSMutableArray,什么时候使用NSArray?
当数组在程序运行时,需要不断变化的,使用NSMutableArray;当数组在初始化
后,便不再改变的,使用NSArray。需要指出的是,使用NSArray只表明该数组在
运行时不发生改变,即不能往NSAarry数组里新增和删除元素,但并不是说其数组
內的元素的内容不可发生改变。NSArray是线程安全的,NSMutableArray不是线程安全的,多线程使用到NSMutableArray需要注意。mutable的可以add, replace, remove,而不带mutable的就不可以了。就是c++说的静态数组和动态数组的区别

Object-c的类可以多重继承么?可以实现多个接口么?Category是什么?
重写一个类的方式用继承好还是分类好?为什么?
Object-c的类不可以多重继承;多继承在这里是用protocol 委托代理来实现
Category是类别,一般情况用分类好,用Category去重写类的方
法,仅对本Category有效,不会影响到其他类与原有类的关系。


assign:指定setter方法用简单的赋值,这是默认操作。你可以对标量类型(如
int)使用这个属性。你可以想象一个float,它不是一个对象,所以它不能
retain、copy。
assign:简单赋值,不更改索引计数(Reference Counting).使用assign: 对基础
数据类型 (NSInteger)和C数据类型(int, float, double, char,等)
retain:指定retain应该在后面的对象上调用,前一个值发送一条release消息。
你可以想象一个NSString实例,它是一个对象,而且你可能想要retain它。
retain:释放旧的对象,将旧对象的值赋予输入对象,再提高输入对象的索引计
数为1 ,使用retain: 对其他NSObject和其子类 ,retain,是说明该属性在赋
值的时候,先release之前的值,然后再赋新值给属性,引用再加1。
copy:指定应该使用对象的副本(深度复制),前一个值发送一条release消息。
基本上像retain,但是没有增加引用计数,是分配一块新的内存来放置它。copy
是创建一个新对象,retain是创建一个指针,引用对象计数加1。copy: 建立一
个索引计数为1的对象,然后释放旧对象,copy是创建一个新对象,retain是创建
一个指针,引用对象计数加1
readonly:将只生成getter方法而不生成setter方法(getter方法没有get前缀)。
readwrite:默认属性,将生成不带额外参数的getter和setter方法(setter方法
只有一个参数)。
atomic:对于对象的默认属性,就是setter/getter生成的方法是一个原子操作。
如果有多个线程同时调用setter的话,不会出现某一个线程执行setter全部语句
之前,另一个线程开始执行setter的情况,相关于方法头尾加了锁一样。
nonatomic:不保证setter/getter的原子性,多线程情况下数据可能会有问题。
nonatomic,非原子性访问,不加同步,多线程并发访问会提高性能。先释放原先
变量,再将新变量retain然后赋值;
NSInteger是基本数据类型Int或者Long的别名(NSInteger的定义typedef long 
NSInteger),它的区别在于,NSInteger会根据系统是32位还是64位来决定是本
身是int还是Long。 
static 关键字的作用:
函数体内 static 变量的作用范围为该函数体,不同于 auto 变量,该变量的内
存只被分配一次,因此其值在下次调用时仍维持上次的值;
关键字const有什么含意?修饰类呢?static的作用,用于类呢?还有extern c的作
用
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的出  现。  
(1)欲阻止一个变量被改变,可以使用 const 关键字。在定义该 const 变量时
,通常需要对它进行初
始化,因为以后就没有机会再去改变它了; 
(2)对指针来说,可以指定指针本身为 const,也可以指定指针所指的数据为 
const,或二者同时指
定为 const; 
(3)在一个函数声明中,const 可以修饰形参,表明它是一个输入参数,在函数
内部不能改变其值; 
(4)对于类的成员函数,若指定其为 const 类型,则表明其是一个常函数,不
能修改类的成员变量; 
(5)对于类的成员函数,有时候必须指定其返回值为 const 类型,以使得其返
回值不为“左值”。

关键字volatile有什么含意?并给出三个不同的例子。
一个定义为 volatile的变量是说这变量可能会被意想不到地改变,这样,编译器
就不会去假设这个变量的值了。
精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的
值,而不是使用保存在寄存器里的备份。

下面是volatile变量的几个例子: 
并行设备的硬件寄存器(如:状态寄存器)  
 一个中断服务子程序中会访问到的非自动变量(Non-automatic variables)  
 多线程应用中被几个任务共享的变量


 Object C中创建线程的方法是什么?如果在主线程中执行代码,方法是什么?如
果想延时执行代码、方法又是什么?
线程创建有三种方法:使用NSThread创建、使用GCD的dispatch、使用子类化的
NSOperation,然后将其加入NSOperationQueue;在主线程执行代码,方法是
performSelectorOnMainThread,如果想延时执行代码可以用
performSelector:onThread:withObject:waitUntilDone:

“线程”与“进程”的联系与区别?
一般你运行一个应用程序,就生成了一个进程, 这个进程拥有自己的内存空间,
这个进程还可以内部生成多个线程, 这些线程之间共用一个进程的内存空存空间,
所以线程之间共享内存是很容易做到的,多线程协作比多进程协作快一些,而且安全.

分线程回调主线程方法是什么,有什么作用? 
[self    performSelectorOnMainThread:@selector(buttonGo2) 
withObject:nil waitUntilDone:YES];
[self performSelector:@selector(buttonGo2) onThread:[NSThread 
mainThread] withObject:nil waitUntilDone:YES];
需要即时刷新ui控件的时候,经常使用。

如何对iOS设备进行性能测试?
Profile-> Instruments ->Time Profiler

id 声明的对象有什么特性?
Id 声明的对象具有运行时的特性,即可以指向任意类型的objcetive-c的对象;

持久化存储机制?
答案:存入到文件、 存入到NSUserDefaults(系统plist文件中)、存入到
Sqlite文件数据库   通过web服务,保存在服务器上

什么时候需要在程序中创建内存池?
答案:用户自己创建的数据线程,则需要创建该线程的内存池

自动释放池是什么,如何工作
当您向一个对象发送一个autorelease消息时,将该对象的一个引用放入到最新的
自动释放池。它仍然是个正当的对象,因此自动释放池定义的作用域内的其它对
象可以向它发送消息。当程序执行到作用域结束的位臵 时,自动释放池就会被释
放,池中的所有对象也就被释放。

在项目什么时候选择使用GCD,什么时候选择NSOperation?
项目中使用NSOperation的优点是NSOperation是对线程的高度抽象,在项目中使
用它,会使项目的程序结构更好,子类化NSOperation的设计思路,是具有面向对
象的优点(复用、封装),使得实现是多线程支持,而接口简单,建议在复杂项
目中使用。
项目中使用GCD的优点是GCD本身非常简单、易用,对于不复杂的多线程操作,会
节省代码量,而Block参数的使用,会是代码更为易读,建议在简单项目中使用。

引用与指针的区别
1.从内存上来讲  系统为指针分寸内存空间,而引用与绑定的对象共享内存空间
,系统不为引用变量分配内容空间。
2指针初始化以后可以改变指向的对象,而引用定义的时候必须要初始化,且初始
化以后不允许再重新绑定对象。
3.所以引用访问对象是直接访问。指针访问对象是间接访问。
4。如果pa是指针,那么*pa就是引用了

http和scoket通信的区别。
http是客户端用http协议进行请求,发送请求时候需要封装http请求头,并绑定
请求的数据,服务器一般有web服务器配合(当然也非绝对)。 http请求方式为
客户端主动发起请求,服务器才能给响应,一次请求完毕后则断开连接,以节省
资源。服务器不能主动给客户端响应(除非采取http长连接技术)。iphone主要
使用类是NSUrlConnection。
scoket是客户端跟服务器直接使用socket“套接字”进行连接,并没有规定连接
后断开,所以客户端和服务器可以保持连接通道,双方都可以主动发送数据。一
般在游戏开发或股票开发这种要求即时性很强并且保持发送数据量比较大的场合
使用。主要使用类是CFSocketRef。

协议是什么,有什么作用.?
协议很像java中的接口,某个类实现协议后,就必须实现协议中规定的@require
的方法,比如一个类A, 一个类B都实现某“协议”后,
这个类A的对象和B的对象都可以赋值给这个协议的类型变量,比如  id<协议> 变
量名 = A类或B类的对象,
于是这个变量就完成了能够指向多个不同的类的对象并调用对象中的实现协议的
方法。

类别有什么作用?
类别的使用 。 类别有三大作用,
1. 可以使本来需要在.h中声明的方法放到.m文件中声明,达到了可以使方法不对
外公开。
2. 可以方便的扩展类,甚至系统类都可以轻易扩展,维护了代码原本的结构不受
影响。
3. 类别可以写到不同的.h或.m文件中,可以分散代码到跟类别的扩展功能想关联
的地方,方便查看。

什么时候用delegate,什么时候用Notification?
delegate针对one-to-one关系,用于sender接受到reciever的某个功能反馈值。
notification针对one-to-one/many/none,reciver,用于通知多个object某个事件。
delegate和notification都是为了在不同的对象之间传递数据,那么何时该使用
delegate,何时该使用notification呢?
1.参数的不同
使用delegate参数更加直观,使用notification参数不那么直观,所以能使用
delegate的地方,尽量使用delegate
2.传递的长度
有时候你的页面会一次跳好几个页面,那么你想把这个页面的数据传回到底层是
很麻烦的事情,因为你要把delegate指针从底层界面一直传上来。
3.传递多个数据
当你在同一个对象传递给多个对象,用delegate就不可行了。
观察者模式,controller向defaultNotificationCenter添加自己的notification
,其他类注册这个notification就可以收到通知,这些类可以在收到通知时做自
己的操作(多观察者默认随机顺序发通知给观察者们,而且每个观察者都要等当
前的某个观察者的操作做完才能轮到他来操作,可以用NotificationQueue的方式
安排观察者的反应顺序,也可以在添加观察者中设定反映时间,取消观察需要在
viewDidUnload跟dealloc中都要注销)。
delegate针对one-to-one关系,并且reciever可以返回值给sender,
notification可以针对one-to-one/many/none,reciever无法返回值给sender.所
以,delegate用于sender希望接受到reciever的某个功能反馈值,
notification用于通知多个object某个事件。



用变量a给出下面的定义 
a) 一个整型数(An integer)  
b)一个指向整型数的指针( A pointer to an integer)  
c)一个指向指针的的指针,它指向的指针是指向一个整型数( A pointer to a 
pointer to an intege)r  
d)一个有10个整型数的数组( An array of 10 integers)  
e) 一个有10个指针的数组,该指针是指向一个整型数的。(An array of 10 
pointers to integers)  
f) 一个指向有10个整型数数组的指针( A pointer to an array of 10 
integers)  
g) 一个指向函数的指针,该函数有一个整型参数并返回一个整型数(A pointer 
to a function that takes an integer as an argument
 and returns an integer)  
h) 一个有10个指针的数组,该指针指向一个函数,该函数有一个整型参数并返回
一个整型数( An array of ten pointers to functions t
hat take an integer argument and return an integer )  
 
答案是:  
a) int a; // An integer  
b) int *a; // A pointer to an integer  
c) int **a; // A pointer to a pointer to an integer  
d) int a[10]; // An array of 10 integers  
e) int *a[10]; // An array of 10 pointers to integers  
f) int (*a)[10]; // A pointer to an array of 10 integers  
g) int (*a)(int); // A pointer to a function a that  takes an integer 
argument and returns an integer  
h) int (*a[10])(int); // An array of 10 pointers to functions  that 
take an integer argument and return an integer

说说响应链?
答案: 事件响应链。包括点击事件,画面刷新事件等。在视图栈内从上至下,或
者从下之上传播。?可以说点事件的分发,传递以及处理。具体可以去看下touch
事件这块。因为问的太抽象化了?严重怀疑题目出到越后面就越笼统。

简述静态链接库和动态链接库
静态库在程序运行时就会装入内存,而动态库在调用的时候才装入!
1.静态链接中,链接程序将需要的目标代码从库文件拷贝到执行文件中;动态链接
是执行文件在执行过程中根据需要从库文件中装入并使用目标代码
2.静态链接产生的执行文件执行是不需要库文件的支持,而动态链接产生的执行文
件运行过程中需要库文件支持,因为它需要从库文件中装入目标代码

你在开发大型项目的时候,如何进行内存泄露检测的?
 xcode的自带工具run---start with performance tool里有instruments下有个leaks工具,
  启动此工具后,运行项目,工具里可以显示内存泄露的情况,双击可找到源码
位置,可以帮助进行内存泄露的处理。

5. NSNotification和KVO的区别和用法是什么?什么时候应该使用通知,什么时
候应该使用KVO,它们的实现上有什么区别吗?如果用protocol和delegate(或者
delegate的Array)来实现类似的功能可能吗?如果可能,会有什么潜在的问题?
如果不能,为什么?
NSNotification是通知模式在iOS的实现,KVO的全称是键值观察(Key-value 
observing),其是基于KVC(key-value coding)的,KVC是一个通过属性名访问属
性变量的机制。例如将Module层的变化,通知到多个Controller对象时,可以使
用NSNotification;如果是只需要观察某个对象的某个属性,可以使用KVO。
对于委托模式,在设计模式中是对象适配器模式,其是delegate是指向某个对象
的,这是一对一的关系,而在通知模式中,往往是一对多的关系。委托模式,从
技术上可以现在改变delegate指向的对象,但不建议这样做,会让人迷惑,如果
一个delegate对象不断改变,指向不同的对象。  

6. 你用过NSOperationQueue么?如果用过或者了解的话,你为什么要使用
NSOperationQueue,实现了什么?请描述它和GCD的区别和类似的地方(提示:可
以从两者的实现机制和适用范围来描述)。
使用NSOperationQueue用来管理子类化的NSOperation对象,控制其线程并发数目
。GCD和NSOperation都可以实现对线程的管理,区别是 NSOperation和
NSOperationQueue是多线程的面向对象抽象。项目中使用NSOperation的优点是
NSOperation是对线程的高度抽象,在项目中使用它,会使项目的程序结构更好,
子类化NSOperation的设计思路,是具有面向对象的优点(复用、封装),使得实
现是多线程支持,而接口简单,建议在复杂项目中使用。
项目中使用GCD的优点是GCD本身非常简单、易用,对于不复杂的多线程操作,会
节省代码量,而Block参数的使用,会使代码更为易读,建议在简单项目中使用。

内存管理机制:
在objective-c中,通过给堆中开辟的内存设计一个计数器,这个计数器的初始值为0,在内存被开辟出来后,计数+1。当指针A不需要使用这块内存的时候,只要把计数器-1,这时候计数器计数变成0,ios框架会释放这块内存。对于int,bool等基本类型,这些直接在栈上开辟的内存,oc无需管理他们内存计数器,这个时候我们一般用assign;对于在堆中开辟的内存,我们需要维护内存的计数器,我们还引用上面的那个例子,首次创建内存后,内存计数器+1,当指针A付给指针B的时候,在这个时候,我们需要给内存计数器再+1,告诉其他指针,我B也引用了这块内存,这个时候,retain正是做这个工作的,只是oc封装了这个过程。其实copy更好理解,如果指针A和指针B不想相互牵扯,A管理A的内存,B管理B的内存,copy正是为这个而生。不是所有的成员变量都要设置属性,释放带属性的成员变量的时候,按照oc的约定,我们只需要用self.属性=nil,在一个方法中返回一个对象的指针,这个时候,我们不方便管理方法返回的对象,这种情况,用autorelease是比较明智的选择。不要轻易把autorelease对象付给retain属性,因为你很有可能忘记给属性设置nil。

指针与地址的区别
指针是变量类型,它的值是地址,它作为变量是可以变化的。
地址是一个数值而已




1 
没有多继承 是用protocol 委托代理 来实现的

2
@private可以用来修饰私有变量
在Objective‐C中,所有实例变量默认都是私有的,所有实例方法默认都是公有的

3
const意味着”只读”

4 static作用? 
函数体内 static 变量的作用范围为该函数体,不同于 auto 变量,该变量的内存只被分配一次,
因此其值在下次调用时仍维持上次的值;

5
线程和进程的区别?

进程和线程都是由操作系统所体会的程序运行的基本单元,系统利用该基本单元实现系统对应用的并发性。
进 程和线程的主要差别在于它们是不同的操作系统资源管理方式。进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个 进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序 健壮,但在进程切换时,耗费资源较大,效率要差一些。但对于一些要求同时进行并且又要共享某些变量的并发操作,只能用线程,不能用进程。

6 堆和栈的区别?

管理方式:对于栈来讲,是由编译器自动管理,无需我们手工控制;对于堆来说,释放工作由程序员控制,容易产生memory leak。
申请大小:
栈:在Windows下,栈是向低地址扩展的数据结构,是一块连续的内存的区域。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的,在WINDOWS下,栈的大小是2M(也有的说是1M,总之是一个编译时就确定的常数),如果申请的空间超过栈的剩余空间时,将提示overflow。因此,能从栈获得的空间较小。
堆:堆是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。
碎片问题:对于堆来讲,频繁的new/delete势必会造成内存空间的不连续,从而造成大量的碎片,使程序效率降低。对于栈来讲,则不会存在这个问题,因为栈是先进后出的队列,他们是如此的一一对应,以至于永远都不可能有一个内存块从栈中间弹出
分配方式:堆都是动态分配的,没有静态分配的堆。栈有2种分配方式:静态分配和动态分配。静态分配是编译器完成的,比如局部变量的分配。动态分配由alloca函数进行分配,但是栈的动态分配和堆是不同的,他的动态分配是由编译器进行释放,无需我们手工实现。
分配效率:栈是机器系统提供的数据结构,计算机会在底层对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高。堆则是C/C++函数库提供的,它的机制是很复杂的。



7
tableView的重用机制?

 查看UITableView头文件,会找到NSMutableArray*  visiableCells,和NSMutableDictnery* reusableTableCells两个结构。visiableCells内保存当前显示的cells,reusableTableCells保存可重用的cells。

  TableView显示之初,reusableTableCells为空,那么tableViewdequeueReusableCellWithIdentifier: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就可以正常重用了。


你可能感兴趣的:(iOS面试,iOS面试题)