1、#import和#include的区别,@class代表什么?
@class一般用于头文件中需要声明该类的某个实例变量的时候用到,在m文件中还是需要使用#import
而#import比起#include的好处就是不会引起重复包含
2、谈谈Object-C的内存管理方式及过程?
1.当你使用new,alloc和copy方法创建一个对象时,该对象的保留计数器值为1.当你不再使用该对象时,你要负责向该对象发送一条release或autorelease消息.这样,该对象将在使用寿命结束时被销毁.
2.当你通过任何其他方法获得一个对象时,则假设该对象的保留计数器值为1,而且已经被设置为自动释放,你不需要执行任何操作来确保该对象被清理.如果你打算在一段时间内拥有该对象,则需要保留它并确保在操作完成时释放它.
3.如果你保留了某个对象,你需要(最终)释放或自动释放该对象.必须保持retain方法和release方法的使用次数相等.
3、Object-C有私有方法吗?私有变量呢?
objective-c – 类里面的方法只有两种, 静态方法和实例方法. 这似乎就不是完整的面向对象了,按照OO的原则就是一个对象只暴露有用的东西. 如果没有了私有方法的话, 对于一些小范围的代码重用就不那么顺手了. 在类里面声名一个私有方法
@interface Controller : NSObject { NSString *something; }
+ (void)thisIsAStaticMethod;
– (void)thisIsAnInstanceMethod;
@end
@interface Controller (private) -
(void)thisIsAPrivateMethod;
@end
@private可以用来修饰私有变量
在Objective‐C中,所有实例变量默认都是私有的,所有实例方法默认都是公有的
4、Object-C有多继承吗?没有的话用什么代替?cocoa 中所有的类都是NSObject 的子类
多继承在这里是用protocol 委托代理 来实现的
你不用去考虑繁琐的多继承 ,虚基类的概念.
ood的多态特性 在 obj-c 中通过委托来实现.
5、内存管理 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的)
6、浅拷贝和深拷贝区别是什么
简单的来说就是,在有指针的情况下,浅拷贝只是增加了一个指针指向已经存在的内存,而深拷贝就是增加一个指针并且申请一个新的内存,使这个增加的指针指向这个新的内存,采用深拷贝的情况下,释放内存的时候就不会出现在浅拷贝时重复释放同一内存的错误
7、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
8、Objective-C中类别和类扩展的区别。
答案:category和extensions的不同在于后者可以添加属性。另外后者添加的方法是必须要实现的。
extensions可以认为是一个私有的Category。
9、我们说的Objective-C是动态运行时语言是什么意思?
答案:多态。 主要是将数据类型的确定由编译时,推迟到了运行时。
这个问题其实浅涉及到两个概念,运行时和多态。
简单来说,运行时机制使我们直到运行时才去决定一个对象的类别,以及调用该类别对象指定方法。
多态:不同对象以自己的方式响应相同的消息的能力叫做多态。意思就是假设生物类(life)都用有一个相同的方法-eat;
那人类属于生物,猪也属于生物,都继承了life后,实现各自的eat,但是调用是我们只需调用各自的eat方法。
也就是不同的对象以自己的方式响应了相同的消息(响应了eat这个选择器)。
因此也可以说,运行时机制是多态的基础?
10、Objective-C堆和栈的区别?
管理方式:对于栈来讲,是由编译器自动管理,无需我们手工控制;对于堆来说,释放工作由程序员控制,容易产生memory leak。
申请大小:
栈:在Windows下,栈是向低地址扩展的数据结构,是一块连续的内存的区域。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的,在 WINDOWS下,栈的大小是2M(也有的说是1M,总之是一个编译时就确定的常数),如果申请的空间超过栈的剩余空间时,将提示overflow。因 此,能从栈获得的空间较小。
堆:堆是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。
碎片问题:对于堆来讲,频繁的new/delete势必会造成内存空间的不连续,从而造成大量的碎片,使程序效率降低。对于栈来讲,则不会存在这个问题,因为栈是先进后出的队列,他们是如此的一一对应,以至于永远都不可能有一个内存块从栈中间弹出
分配方式:堆都是动态分配的,没有静态分配的堆。栈有2种分配方式:静态分配和动态分配。静态分配是编译器完成的,比如局部变量的分配。动态分配由alloca函数进行分配,但是栈的动态分配和堆是不同的,他的动态分配是由编译器进行释放,无需我们手工实现。
分配效率:栈是机器系统提供的数据结构,计算机会在底层对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高。堆则是C/C++函数库提供的,它的机制是很复杂的。
MVC是模型、试图、控制开发模式,对于iOS SDK,所有的View都是视图层的,它应该独立于模型层,由视图控制层来控制。所有的用户数据都是模型层,它应该独立于视图。所有的ViewController都是控制层,由它负责控制视图,访问模型数据。
12、category是什么? 扩展一个类的方式用继承好还是类目好? 为什么?
category是类目.用类目好,因为继承要满足A is a B的关系,而类目只需要满足A has a B的关系,局限性更小,你不用定义子类就能扩展一个类的功能,还能将类的定义分开放在不同的源文件里,用category去重写类的方法,仅对本category有效,不会影响到其他类与原有类的关系。
13、延展是什么? 作用是什么?
延展(extension):在自己类的实现文件中添加类目来声明私有方法。
14、解释一下懒汉模式?
懒汉模式,只在用到的时候才去初始化。
也可以理解成延时加载。
我觉得最好也最简单的一个列子就是tableView中图片的加载显示了。
一个延时载,避免内存过高,一个异步加载,避免线程堵塞
15、@property中有哪些属性关键字?
属性可以拥有的特质分为四类:
- 原子性—- nonatomic 特质
在默认情况下,由编译器合成的方法会通过锁定机制确保其原子性(atomicity)。如果属性具备 nonatomic 特质,则不使用同步锁。请注意,尽管没有名为“atomic”的特质(如果某属性不具备 nonatomic 特质,那它就是“原子的” ( atomic) ),但是仍然可以在属性特质中写明这一点,编译器不会报错。若是自己定义存取方法,那么就应该遵从与属性特质相符的原子性。
-
读/写权限—-readwrite(读写)、readonly (只读)
-
内存管理语义—-assign、strong、 weak、copy
方法名—-getter= 、setter=
16、你经常使用一些第三方库有哪些?
- AFNetworking
- SDWebImage
- FMDB
- JSONKit
- MJRefresh
- MJExtension
- Masonry
- 友盟,shareSDK等三方库。
17、你经常用的设计模式有哪些?
- MVC
- 代理模式
- 观察者模式
- 单例模式
- 工厂模式
18、本地存储有哪些方式?
属性列表(NSUserDefault 或 plist)
对象归档 (NSKeyedArchiver)
SQLite
CoreData
19、weak属性需要在dealloc中置nil么?
不需要,在ARC环境无论是强指针还是弱指针都无需在deallco设置为nil,ARC会自动帮我们处理。
20、@synthesize和@dynamic分别有什么作用?
- @property有两个对应的词,一个是@synthesize,一个是@dynamic。如果@synthesize和@dynamic都没写,那么默认的就是@syntheszie var = _var;
- @synthesize的语义是如果你没有手动实现setter方法和getter方法,那么编译器会自动为你加上这两个方法。
- @dynamic告诉编译器,属性的setter与getter方法由用户自己实现,不自动生成。
21、用@property声明的NSString(或NSArray,NSDictionary)经常使用copy关键字,为什么?如果改用strong关键字,可能造成什么问题?
- 因为父类指针可以指向子类对象,使用copy的目的是为了让本对象的属性不受外界影响,使用copy无论给我传入是一个可变对象还是不可对象,我本身持有的就是一个不可变的副本.
- 如果我们使用是strong,那么这个属性就有可能指向一个可变对象,如果这个可变对象在外部被修改了,那么会影响该属性.
22、什么时候会报unrecognized selector的异常?
当该对象上某个方法,而该对象上没有实现这个方法的时候
23、使用block时什么情况会发生引用循环,如何解决?
- 只要是一个对象对该block进行了强引用,在block内部有直接使用到该对象。
- 解决方案:__weak id weakSelf = self;
24、GCD的队列(dispatch_queue_t)分哪两种类型?
串行队列和并行队列
25、如何用GCD同步若干个异步调用?(如根据若干个url异步加载多张图片,然后在都下载完成后合成一张整图)
总体上说: 使用 dispatch group,然后 wait forever 等待完成, 或者采取 group notify 来通知回调。
1 2 3 4 5 6 7 8 | dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_group_t group = dispatch_group_create(); dispatch_group_async(group, queue, ^{ /*加载图片1 */ }); dispatch_group_async(group, queue, ^{ /*加载图片2 */ }); dispatch_group_async(group, queue, ^{ /*加载图片3 */ }); dispatch_group_notify(group, dispatch_get_main_queue(), ^{ // 合并图片 }) |
26、以下代码运行结果如何?
1 2 3 4 5 6 7 8 9 | - (void)viewDidLoad { [super viewDidLoad]; NSLog(@"1"); dispatch_sync(dispatch_get_main_queue(), ^{ NSLog(@"2"); }); NSLog(@"3"); } |
27、若一个类有实例变量NSString *_foo,调用setValue:forKey:时,可以以foo还是_foo作为key?
都可以
28、IBOutlet连出来的视图属性为什么可以被设置成weak?
因为视图已经对它有一个强引用了
29、你单例怎么理解怎么用的?
Singleton Pattern单例设计模式,通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源。如果希望在系统中某个类的对象只能存在一个,单例模式是最好的解决方案。类只能有一个实例,而且必须从一个为人熟知的访问点对其进行访问,比如工厂方法。这个唯一的实例只能通过子类化进行扩展,而且扩展的对象不会破坏客户端代码。例如,UIApplication的sharedApplication方法,任何时候都会返回一个当前应用程序的UIApplication实例。
30、lldb(gdb)常用的调试命令?
最常用就是 : po 对象
31、什么是谓词?
谓词是通过NSPredicate,是通过给定的逻辑条件作为约束条件,完成对数据的筛选。
32、+(void)load; +(void)initialize; 的区别?
+(void)load; 在程序运行后立即执行。
+(void)initialize; 在类的方法第一次被调时执行.
33、什么是KVC,什么是KVO?
- kvc:键 - 值编码是一种间接访问对象的属性使用字符串来标识属性,而不是通过调用存取方法,直接或通过实例变量访问的机制。
- kvo:键值观察机制,他提供了观察某一属性变化的方法,极大的简化了代码。
34、什么时候用delegate,什么时候用Notification?
delegate针对one-to-one关系,并且reciever可以返回值 给sender,notification 可以针对one-to-one/many/none,reciever无法返回值给sender.所以,delegate用于sender希望接受到 reciever的某个功能反馈值,notification用于通知多个object某个事件
35、block和weak区别?
- __block不管是ARC还是MRC模式下都可以使用,可以修饰对象,还可以修饰基本数据类型。
- __weak只能在ARC模式下使用,也只能修饰对象(NSString),不能修饰基本数据类型(int)。
- block对象可以在block中被重新赋值,weak不可以。
36、frame和bounds有什么不同?
- frame指的是:该view在父view坐标系统中的位置和大小。(参照点是父亲的坐标系统)
- bounds指的是:该view在本身坐标系统中 的位置和大小。(参照点是本身坐标系统)
37、UIView和CALayer有什么不同?
两者最大的区别是,图层不会直接渲染到屏幕上,UIView是iOS系统中界面元素的基础,所有的界面元素都是继承自它。它本身完全是由CoreAnimation来实现的。它真正的绘图部分,是由一个CALayer类来管理。UIView本身更像是一个CALayer的管理器。一个UIView上可以有n个CALayer,每个layer显示一种东西,增强UIView的展现能力。
38、TCP和UDP的区别?
- TCP:(传输控制协议),提供面向连接的、可靠地点对点的通信;
- UDP:(用户数据报协议),提供非连接的不可靠的点对多点的通信;
- 实际运用中,看程序注重的是哪一方面,是可靠还是快速;
39、socket连接与http连接
- http连接:短连接。即客户端向服务端发送一次请求,服务端响应之后,链接即会断掉;
- socket连接:长连接。即客户端一旦与服务器建立接连,便不会主动断掉。
40、HTTP 的post与get区别与联系,实践中如何选择它们?
- get是从服务器上获取数据,post是向服务器传送数据。
- 在客户端,Get方式在通过URL提交数据,数据在URL中可以看到;POST方式,数据放置在HTML HEADER内提交。
- 对于get方式,服务器端用Request.QueryString获取变量的值,对于post方式,服务器端用Request.Form获取提交的数据。
- GET方式提交的数据最多只能有1024字节,而POST则没有此限制。
- 安全性问题。正如在(1)中提到,使用 Get 的时候,参数会显示在地址栏上,而 Post 不会。所以,如果这些数据是中文数据而且是非敏感数据,那么使用 get;如果用户输入的数据不是中文字符而且包含敏感数据,那么还是使用 post为好。
Http定义了与服务器交互的不同方法,最基本的方法有4种,分别是GET,POST,PUT,DELETE。URL全称是资源描述符,我们可以这样认为:一个URL地址,它用于描述一个网络上的资源,而HTTP中的GET,POST,PUT,DELETE就对应着对这个资源的查,改,增,删4个操作。GET一般用于获取/查询资源信息,而POST一般用于更新资源信息。
41、检查内存管理问题的方式有哪些
- 点击Xcode顶部菜单中的ProductàAnalyze。这种方法主要可以查看内存泄露,变量未初始化,变量定义后没有被使用到
- 使用Instrument工具检查。点击Xcode顶部菜单中的Product Profile,弹出一个界面,选择左侧的Memory后,再选右侧的Leaks。
- 人工检查
42、谈安卓与苹果的优缺点
苹果系统优点是左右流畅,软件多,界面华丽,图标统一,很美观;缺点是系统封闭,不允许用户过多的个性化设置,而且只能在苹果手机上用。安卓系统优点是开放,可以自己扩展的东西很多,支持的硬件也多,各个价位的手机都有;缺点就是软件太杂乱,兼容性有问题,图标混乱不美观。iOS的确比android流畅,这仅仅体现在较大软件切换时,其他差不多流畅,iOS并不能做到完全后台,如果它完全后台估计也不会比安卓流畅多少。反之,如果安卓只是注重单个运行,流畅度也会大大提升,iOS系统更新没有android那么频繁,爱体验的人会选安卓,那些怕烦的会选iOS。iOS的硬件需求选不及android,以至于android机会相对iOS较热,较费电额。
43、运行时你是怎么理解的?
ObjC Runtime 其实是一个 Runtime 库,基本上用 C 和汇编写的,这个库使得 C 语言有了面向对象的能力(脑中浮现当你乔帮主参观了施乐帕克的 SmallTalk 之后嘴角一抹浅笑)。这个库做的事前就是加载类的信息,进行方法的分发和转发之类的。OC是一种面向runtime(运行时)的语言,也就是说,它会尽可能地把代码执行的决策从编译和链接的时候,推迟到运行时。这给程序员写代码带来很大的灵活性,比如说你可以把消息转发给你想要的对象,或者随意交换一个方法的实现之类的。这就要求runtime能检测一个对象是否能对一个方法进行响应,然后再把这个方法分发到对应的对象去。
44、@protocol 和 category 中如何使用 @property
- 在 protocol 中使用 property 只会生成 setter 和 getter 方法声明,我们使用属性的目的,是希望遵守我协议的对象能实现该属性
- category 使用 @property 也是只会生成 setter 和 getter 方法的声明,如果我们真的需要给 category 增加属性的实现,需要借助于运行时的两个函数:
- objc_setAssociatedObject
- objc_getAssociatedObject
45、runtime如何通过selector找到对应的IMP地址?
每一个类对象中都一个方法列表,方法列表中记录着方法的名称,方法实现,以及参数类型,其实selector本质就是方法名称,通过这个方法名称就可以在方法列表中找到对应的方法实现.
46、一个objc对象如何进行内存布局?
- 所有父类的成员变量和自己的成员变量都会存放在该对象所对应的存储空间中.
- 每一个对象内部都有一个isa指针,指向他的类对象,类对象中存放着本对象的
- 对象方法列表(对象能够接收的消息列表,保存在它所对应的类对象中)
- 成员变量的列表,
- 属性列表,
它内部也有一个isa指针指向元对象(meta class),元对象内部存放的是类方法列表,类对象内部还有一个superclass的指针,指向他的父类对象。
47、什么是GCD?
GCD全称Grand Central Dispatch,我们通俗的翻译叫牛逼的中心调度。
48、我们用GCD干什么?
通过 GCD,开发者不用再直接跟线程打交道了,只需要向队列中添加代码块即可,GCD 在后端管理着一个线程池。GCD 不仅决定着你的代码块将在哪个线程被执行,它还根据可用的系统资源对这些线程进行管理。这样可以将开发者从线程管理的工作中解放出来,通过集中的管理线程,来缓解大量线程被创建的问题。
GCD 带来的另一个重要改变是,作为开发者可以将工作考虑为一个队列,而不是一堆线程,这种并行的抽象模型更容易掌握和使用。
首先,系统提供给你一个叫做 主队列(main queue) 的特殊队列。和其它串行队列一样,这个队列中的任务一次只能执行一个。然而,它能保证所有的任务都在主线程执行,而主线程是唯一可用于更新 UI 的线程。这个队列就是用于发生消息给 UIView 或发送通知的。
系统同时提供给你好几个并发队列。它们叫做 全局调度队列(Global Dispatch Queues) 。目前的四个全局队列有着不同的优先级:background、low、default 以及 high。要知道,Apple 的 API 也会使用这些队列,所以你添加的任何任务都不会是这些队列中唯一的任务。
最后,你也可以创建自己的串行队列或并发队列。这就是说,至少有五个队列任你处置:主队列、四个全局调度队列,再加上任何你自己创建的队列。
49、GCD相比其他多线程有哪些优点?
- GCD 能通过推迟昂贵计算任务并在后台运行它们来改善你的应用的响应性能。
- GCD 提供一个易于使用的并发模型而不仅仅只是锁和线程,以帮助我们避开并发陷阱。
- GCD 具有在常见模式(例如单例)上用更高性能的原语优化你的代码的潜在能力。
- GCD 会自动利用更多的CPU内核(比如双核、四核)
50、GCD术语
- 串行(Serial):让任务一个接着一个地执行(一个任务执行完毕后,再执行下一个任务)
- 并发(Concurrent):可以让多个任务并发(同时)执行(自动开启多个线程同时执行任务)并发功能只有在异步(dispatch_async)函数下才有效。
- 同步(Synchronous):在当前线程中执行任务,不具备开启新线程的能力
- 异步(Asynchronous):在新的线程中执行任务,具备开启新线程的能力
51、使用GCD
1.认识主队列,感受串行队列的运行,运行结果打印的是 1,2,3,4,顺序执行。
1 2 3 4 5 6 7 8 9 10 11 12 13 | dispatch_queue_t mainQueue = dispatch_get_main_queue(); dispatch_async(mainQueue, ^{ NSLog(@"1"); }); dispatch_async(mainQueue, ^{ NSLog(@"2"); }); dispatch_async(mainQueue, ^{ NSLog(@"3"); }); dispatch_async(mainQueue, ^{ NSLog(@"4"); }); |
2.认识全局队列,体验并发队列的运行,运行结果随机打印:2,3,1,4,随机执行。
1 2 3 4 5 6 7 8 9 10 11 12 13 | dispatch_queue_t defaultQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_async(defaultQueue, ^{ NSLog(@"1"); }); dispatch_async(defaultQueue, ^{ NSLog(@"2"); }); dispatch_async(defaultQueue, ^{ NSLog(@"3"); }); dispatch_async(defaultQueue, ^{ NSLog(@"4"); }); |
3.创建自定义队列
1 2 3 4 5 6 7 8 9 10 | dispatch_queue_t concurrentQueue = dispatch_queue_create("concurrentQueue", DISPATCH_QUEUE_CONCURRENT); dispatch_async(concurrentQueue, ^{ NSLog(@"4"); dispatch_sync(concurrentQueue, ^{ [NSThread sleepForTimeInterval:3]; NSLog(@"5"); }); NSLog(@"6"); }); |
4.GCD在单例中的运用dispatch_once
1 2 3 4 | static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ NSLog(@"onceToken"); }); |
5.延迟加载dispatch_after
1 2 3 4 5 6 | double delayInSeconds = 2.0; dispatch_queue_t mainQueue = dispatch_get_main_queue(); dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW,delayInSeconds * NSEC_PER_SEC); dispatch_after(popTime, mainQueue, ^{ NSLog(@"延时执行的2秒"); }); |
6.调度组dispatch_group_t
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | dispatch_group_t group = dispatch_group_create(); dispatch_queue_t defaultQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_group_async(group, defaultQueue, ^{ [NSThread sleepForTimeInterval:3]; NSLog(@"1"); }); dispatch_group_async(group, defaultQueue, ^{ [NSThread sleepForTimeInterval:2]; NSLog(@"2"); }); dispatch_group_notify(group, defaultQueue, ^{ NSLog(@"3"); }); //等价于 // dispatch_group_enter(group); // dispatch_async(defaultQueue, ^{ // // NSLog(@"1"); // dispatch_group_leave(group); // }); |
7.dispatch_barrier_async
在前面的任务执行结束后它才执行,而且它后面的任务等它执行完成之后才会执行.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | dispatch_queue_t queue = dispatch_queue_create("barrierExecute", DISPATCH_QUEUE_CONCURRENT); dispatch_async(queue, ^{ [NSThread sleepForTimeInterval:2]; NSLog(@"1"); }); dispatch_async(queue, ^{ [NSThread sleepForTimeInterval:4]; NSLog(@"2"); }); dispatch_barrier_async(queue, ^{ NSLog(@"3"); [NSThread sleepForTimeInterval:4]; }); dispatch_async(queue, ^{ [NSThread sleepForTimeInterval:1]; NSLog(@"4"); }); |
8.执行某个代码dispatch_apply
1 2 3 4 | dispatch_queue_t defaultQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_apply(5, defaultQueue, ^(size_t i) { NSLog(@"%lu",i); }); |
int location = range.location;
NSString *str1 = [responseString substringToIndex:location];
NSString *str2 = [responseString substringFromIndex:location+1];
name = “object”会直接把object赋值给当前对象的name 属性。
并且 self.name 这样retainCount会加1,而name就不会。
NSString *documentsDirectory = [paths objectAtIndex:];
// 创建文件系统管理器
NSFileManager *fileManager = [[NSFileManager alloc] init];
// 判断userData目录是否存在
if(![fileManager fileExistsAtPath:[NSString stringWithFormat:@"%@/userData", documentsDirectory]]) {
// 不存在,创建一个userData目录
[fileManager createDirectoryAtPath:[NSString stringWithFormat:@"%@/userData", documentsDirectory]withIntermediateDirector
}
+ (id)initWithCString:(c*****t char *)nullTerminatedCString encoding:(NSStringEncoding)encoding;
+ (id) stringWithCString: (c*****t char*)nullTerminatedCString
encoding: (NSStringEncoding)encoding
{
NSString *obj;
obj = [self allocWithZone: NSDefaultMallocZone()];
obj = [obj initWithCString: nullTerminatedCString encoding: encoding];
return AUTORELEASE(obj);
}
56、static 关键字的作用:
(1)函数体内 static 变量的作用范围为该函数体,不同于 auto 变量,该变量的内存只被分配一次,
因此其值在下次调用时仍维持上次的值;
(2)在模块内的 static 全局变量可以被模块内所用函数访问,但不能被模块外其它函数访问;
(3)在模块内的 static 函数只可被这一模块内的其它函数调用,这个函数的使用范围被限制在声明
它的模块内;
(4)在类中的 static 成员变量属于整个类所拥有,对类的所有对象只有一份拷贝;
(5)在类中的 static 成员函数属于整个类所拥有,这个函数不接收 this 指针,因而只能访问类的static 成员变量。
57、线程与进程的区别和联系?
进程和线程都是由操作系统所体会的程序运行的基本单元,系统利用该基本单元实现系统对应用的并发性。
程和线程的主要差别在于它们是不同的操作系统资源管理方式。进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差一些。但对于一些要求同时进行并且又要共享某些变量的并发操作,只能用线程,不能用进程。
58、堆和栈的区别
管理方式:对于栈来讲,是由编译器自动管理,无需我们手工控制;对于堆来说,释放工作由程序员控制,容易产生memory leak。
申请大小:
栈:在Windows下,栈是向低地址扩展的数据结构,是一块连续的内存的区域。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的,在 WINDOWS下,栈的大小是2M(也有的说是1M,总之是一个编译时就确定的常数),如果申请的空间超过栈的剩余空间时,将提示overflow。因此,能从栈获得的空间较小。
堆:堆是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。
碎片问题:对于堆来讲,频繁的new/delete势必会造成内存空间的不连续,从而造成大量的碎片,使程序效率降低。对于栈来讲,则不会存在这个问题,因为栈是先进后出的队列,他们是如此的一一对应,以至于永远都不可能有一个内存块从栈中间弹出
分配方式:堆都是动态分配的,没有静态分配的堆。栈有2种分配方式:静态分配和动态分配。静态分配是编译器完成的,比如局部变量的分配。动态分配由alloca函数进行分配,但是栈的动态分配和堆是不同的,他的动态分配是由编译器进行释放,无需我们手工实现。
分配效率:栈是机器系统提供的数据结构,计算机会在底层对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高。堆则是C/C++函数库提供的,它的机制是很复杂的。
59、什么是键-值,键路径是什么 ?
模型的性质是通过一个简单的键(通常是个字符串)来指定的。视图和控制器通过键来查找相应的属性值。在一个给定的实体中,同一个属性的所有值具有相同的数据类型。键-值编码技术用于进行这样的查找—它是一种间接访问对象属性的机制。
键路径是一个由用点作分隔符的键组成的字符串,用于指定一个连接在一起的对象性质序列。第一个键的
性质是由先前的性质决定的,接下来每个键的值也是相对于其前面的性质。键路径使您可以以独立于模型
实现的方式指定相关对象的性质。通过键路径,您可以指定对象图中的一个任意深度的路径,使其指向相
关对象的特定属性。
目标是动作消息的接收者。一个控件,或者更为常见的是它的单元,以插座变量(参见"插座变量"部分)
的形式保有其动作消息的目标。
动作是控件发送给目标的消息,或者从目标的角度看,它是目标为了响应动作而实现的方法。
程序需要某些机制来进行事件和指令的翻译。这个机制就是目标-动作机制。
61、objc的内存管理
如果您通过分配和初始化(比如[[MyClass alloc] init])的方式来创建对象,您就拥有这个对象,需要负责该对象的释放。这个规则在使用NSObject的便利方法new 时也同样适用。
如果您拷贝一个对象,您也拥有拷贝得到的对象,需要负责该对象的释放。
如果您保持一个对象,您就部分拥有这个对象,需要在不再使用时释放该对象。
反过来,
如果您从其它对象那里接收到一个对象,则您不拥有该对象,也不应该释放它(这个规则有少数
的例外,在参考文档中有显式的说明)。
62、自动释放池是什么,如何工作 ?
当您向一个对象发送一个autorelease消息时,Cocoa就会将该对象的一个引用放入到最新的自动释放池。它仍然是个正当的对象,因此自动释放池定义的作用域内的其它对象可以向它发送消息。当程序执行到作用域结束的位置时,自动释放池就会被释放,池中的所有对象也就被释放。
1. ojc-c 是通过一种"referring counting"(引用计数)的方式来管理内存的, 对象在开始分配内存(alloc)的时候引用计数为一,以后每当碰到有copy,retain的时候引用计数都会加一, 每当碰到release和autorelease的时候引用计数就会减一,如果此对象的计数变为了0, 就会被系统销毁.
2. NSAutoreleasePool 就是用来做引用计数的管理工作的,这个东西一般不用你管的.
3. autorelease和release没什么区别,只是引用计数减一的时机不同而已,autorelease会在对象的使用真正结束的时候才做引用计数减一.
类工厂方法的实现是为了向客户提供方便,它们将分配和初始化合在一个步骤中,返回被创建的对象,并
进行自动释放处理。这些方法的形式是+ (type)className...(其中 className不包括任何前缀)。
工厂方法可能不仅仅为了方便使用。它们不但可以将分配和初始化合在一起,还可以为初始化过程提供对
象的分配信息。
类工厂方法的另一个目的是使类(比如NSWorkspace)提供单件实例。虽然init...方法可以确认一
个类在每次程序运行过程只存在一个实例,但它需要首先分配一个“生的”实例,然后还必须释放该实例。
工厂方法则可以避免为可能没有用的对象盲目分配内存。
64、单件实例是什么?
Foundation 和 Application Kit 框架中的一些类只允许创建单件对象,即这些类在当前进程中的唯一实例。举例来说,NSFileManager 和NSWorkspace 类在使用时都是基于进程进行单件对象的实例化。当向这些类请求实例的时候,它们会向您传递单一实例的一个引用,如果该实例还不存在,则首先进行实例的分配和初始化。单件对象充当控制中心的角色,负责指引或协调类的各种服务。如果类在概念上只有一个实例(比如
NSWorkspace),就应该产生一个单件实例,而不是多个实例;如果将来某一天可能有多个实例,您可
以使用单件实例机制,而不是工厂方法或函数。