1、Object-C有多继承吗?没有的话用什么代替?
你不用去考虑繁琐的多继承 ,虚基类的概念.
ood的多态特性 在 obj-c 中通过委托来实现.
使用指针 会涉及到两个对象 一个是指针本身,另一个是它指向的对象. 将指针声明为 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
View: Controller的奴隶。。。
- Controller可以直接和Model通信
- Controller也可以直接和View通信
- Model和View永远不能直接通信
- iOS中View和Controller的通信是透明和固定的,主要通过outlet和action实现
- View使用Delegate接口和Controller同步信息
- View不直接和数据通信,使用dataSource接口从Controller处获取数据
- View的delegate和dataSource一般就是Controller
- Controller负责为View翻译和格式化Model的数据
- Model使用Notification & KVO的方式分发数据更新信息,Controller可以有选择的监听自己感兴趣的信息。
- View也可以监听广播信息,但一般不是Model发出的信息
- 一个完整的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) (id, SEL, …)。这样说来, 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显示的那样,如果一个响应者对象不能处理某个事件或动作-也就是说,它不响应那个消息,或者不认识那个事件,则将该消息重新发送给链中的下一个响应者。消息沿着响应者链向上、向更高级别的对象传递,直到最终被处理(如果最终还是没有被处理,就会被抛弃)。
当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,但是他们是不同的量
iOS面试题总结
目录
- 1. 多线程的底层实现?
- 2. 线程间怎么通信?
- 3. 网络图片处理问题中怎么解决一个相同的网络地址重复请求的问题?
- 4. 用NSOpertion和NSOpertionQueue处理A,B,C三个线程,要求执行完A,B后才能执行C,怎么做?
- 5. 列举cocoa中常见对几种多线程的实现,并谈谈多线程安全的几种解决办法及多线程安全怎么控制?
- 6. GCD内部怎么实现的?
- 7. 你用过NSOperationQueue么?如果用过或者了解的话,你为什么要使用NSOperationQueue,实现了什么?请描述它和GCD的区别和类似的地方(提示:可以从两者的实现机制和适用范围来描述)。
- 8. 既然提到GCD,那么问一下在使用GCD以及block时要注意些什么?它们两是一回事儿吗?block在ARC中和传统的MRC中的行为和用法有没有什么区别,需要注意些什么?
- 9. 在异步线程中下载很多图片,如果失败了,该如何处理?请结合RunLoop来谈谈解决方案.(提示:在异步线程中启动一个RunLoop重新发送网络请求,下载图片)。
- 10. 怎么保证多人开发进行内存泄露的检查?
- 11. 非自动内存管理情况下怎么做单例模式?
- 12. 对于类方法(静态方法)默认是autorelease的,所有类方法都会这样吗?
- 13. block在ARC中和MRC中的用法有什么区别,需要注意什么?
- 14. 什么情况下会发生内存泄漏和内存溢出?
- 15.
[NSArray arrayWithobject:(id)obj]
这个方法添加对象后,需要对这个数组做释放操作吗? - 16. 自动释放池底层怎么实现?
- 17. KVO内部实现原理是什么?
- 18. 是否可以把比较耗时的操作放在NSNotificationCenter中?
- 19. Foundation对象与Core Foundation对象有什么区别?
- 20. 如何不用中间变量,用两种方法交换A和B的值?
- 21. 简单描述下对单利模式设计的理解?
- 22. runtime实现的机制是什么,如何用,用来做什么?你所使用的相关的头文件或者某些方法的名称有哪些?
- 23. 是否使用Core Text或者Core Image等?如果使用过,请谈谈你使用Core Text或者Core Image的体验。
- 24. NSNotification和KVO的区别和用法是什么?什么时候应该使用通知,什么时候应该使用KVO,它们的实现上有什么区别吗?如果用protocol和delegate(或者delegate的Array)来实现类似的功能可能吗?如果可能,会有什么潜在的问题?如果不能,为什么?(虽然protocol和delegate这种东西面试已经面烂了…)?
- 25. Block内部的实现原理
- 26. 有两个数组a和b,大小都为n,通过交换a,b中的元素,使sum(a)-sum(b)最小
- 27. 如果后期需要增加数据库中的字段怎么实现,如果不使用CoreData呢?
- 28. SQLite数据存储是怎么用?
- 29. 简单描述下客户端的缓存机制?
- 30. 你实现过多线程的Core Data么?NSPersistentStoreCoordinator,NSManagedObjectContext和NSManagedObject中的哪些需要在线程中创建或者传递?你是用什么样的策略来实现的?
- 31. Core Data数据迁移
- 32. 怎么解决缓存池满的问题(cell)
- 33. CAAnimation的层级结构
- 34. 按钮或者其它UIView控件的事件传递的具体过程
- 35. 控制器View的生命周期及相关函数是什么?你在开发中是如何用的?
- 36. NSRunLoop的实现机制,及在多线程中如何使用?
- 37. iOS7之前,后台执行内容有几种形式,都是什么?
- 38. 简单说一下APP的启动过程,从main文件开始说起
- 39. 把程序自己关掉和程序进入后台,远程推送的区别?
- 40. SIP是什么?
- 41. 有些图片加载的比较慢怎么处理?你是怎么优化程序的性能的?
- 42. 你实现过一个框架或者库以供别人使用么?如果有,请谈一谈构建框架或者库时候的经验;如果没有,请设想和设计框架的public的API,并指出大概需要如何做,需要注意一些什么方面,来使别人容易地使用你的框架。
- 43. App需要加载超大量的数据,给服务器发送请求,但是服务器卡住了如何解决?
- 44. 利用NSNotificationCenter实现跨多控制器传输数据和消息中用同步还是异步?
- 45. SDWebImage具体如何实现?
- 46. AFN 与 ASI 有什么区别
- 47. Runloop定时源和输入源
- 48. 如果在网络数据处理过程中,发现一处比较卡,一般怎么解决
- 49. 怎么解决sqlite锁定的问题
- 50. 讲下主流框架的实现原理(AFNetworking SDWebImage)
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数据迁移
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)