关键词/关键类
1.#import跟#include有什么区别,@class呢,#import<>跟#import<>有什么区别?
#include c语言中引入一个头文件,但是可能出现交叉编译
#import在OC中引入自己创建的头文件#import””或者系统框架#import<>。
#import不会出现交叉编译,@class对一个类进行声明,告诉编译器有这个类,但是类的定义什么的都不知道
2描述一下KVO和KVC?
Key-Value Observing (简写为KVO):当指定的对象的属性被修改了,允许对象接受到通知的机制。每次指定的被观察对象的属性被修改的时候,KVO都会自动的去通知相应的观察者。
KVC是KeyValue Coding的简称,它是一种可以直接通过字符串的名字(key)来访问类属性的机制。而不是通过调用Setter、Getter方法访问。
3.类目和继承地区别
1.类别是对方法的扩展,不能添加成员变量。继承可以在原来父类的成员变量的基础上,添加新的成员变量
2.类别只能添加新的方法,不能修改和删除原来的方法。继承可以增加、修改和删除方法。
3.类别不提倡对原有的方法进行重载。继承可以通过使用super对原来方法进行重载。
4.类别可以被继承,如果一个父类中定义了类别,那么其子类中也会继承此类别。
5.什么是懒加载?在使用懒加载时的注意事项是什么?
答:所谓的懒加载指的是延迟创建对象,只有当需要的时候才创建对象。在真正开发的过程中其实懒加载就是重写getter方法。在getter方法的内部,实现对象的创建,如果对象为nil才创建,如果不为nil,直接返回对象。在真正使用懒加载时需要注意的是当第一次使用对象时,需要调用self.因为只有这样才能调用对应的getter方法,对象才会被创建。
6.简述你对UIView、UIWindow、CALayer的理解。
答:CALayer是图层类,本身可以显示的,但是不能响应事件。
UIView是iOS系统中界面元素的基础,所有的界面元素都继承自它。事件的处理由它来执行,但是显示其实是由其对应的layer层来操作的,UIView内嵌了一个layer,layer显示内容,UIView本身增加了事件处理的功能。
UIWindow继承自UIView,主要的作用是作为窗口呈现其他的视图。而且一个应用程序一般情况下只有一个窗口。
7. id声明的对象有什么特性?
答:id是任意对象类型的,不能表示基本类型。id类型是通用指针类型,因为通过指针,也就是内存地址来引用对象,所以可以将任意对象赋值给id类型的对象。返回id类型值的方法是返回指向内存中某对象的指针。然后可以将该值赋给任何对象变量(强制类型转换即可)。因为无论在哪里,对象总是携带它的isa成员。所以即使将它存储在id类型的通用对象变量中,也总是可以确定它的真实类型,id是多态的一种体现
7.@synthesize和@dynamic有什么区别?
(1)@property有两个对应的词,一个是@synthesize,一个是@dynamic。如果@synthesize和@dynamic都没写,那么默认的就是@syntheszie var = _var;
(2)@synthesize的语义是如果你没有手动实现setter方法和getter方法,那么编译器会自动为你加上这两个方法。
(3)@dynamic告诉编译器:属性的setter与getter方法由用户自己实现,不自动生成。(当然对于readonly的属性只需提供getter即可)。假如一个属性被声明为@dynamic var,然后你没有提供@setter方法和@getter方法,编译的时候没问题,但是当程序运行到instance.var = someVar,由于缺setter方法会导致程序崩溃;或者当运行到someVar = instance.var时,由于缺getter方法同样会导致崩溃。编译时没问题,运行时才执行相应的方法,这就是所谓的动态绑定。@dynamic可用于在分类中添加属性(需要用到objc_getAssociatedObject和objc_setAssociatedObject函数)。
3.在Category中本身不允许为已有的类添加新的属性或者成员变量,你有没有其他的方法可以在category中添加属性或者是成员变量?
答:一种方法就是使用runtime.h中的objc_getAssociatedObject和objc_setAssociatedObject来访问和生成关联对象。例如为NSObject添加一个类目,分类中添加一个属性。代码如下所示:
NSObject+Test.h文件
#import
@interface NSObject (Test)
@property (nonatomic, strong) NSString *test;
@end
NSObject+Test.m文件
#import “NSObject+Test.h"
#import
static const void *instanceNameKey = &instanceNameKey;
@implementation NSObject (Test)
@dynamic test;
- (NSString *)test
{
return objc_getAssociatedObject(self, instanceNameKey);
}
- (void)setTest:(NSString *)test
{
objc_setAssociatedObject(self, instanceNameKey, test, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
@end
15.在oc中引入头文件使用的关键字是哪一个?能在c语言文件中使用吗?
答:#import关键字可以在OC中使用,不能在C文件中使用,#include可以在C和OC中使用。
16.#import与#include相比,好处是什么?
答:#import确定一个文件只能被导入一次,避免的重复导入的问题,使用#include一定要注意重复导入的问题。所以在OC中都使用#import来引用头文件。
17.#import<>和#import””的区别是什么?
答:#import<>用于对系统文件的引用,编译器会在系统文件目录中去查找文件
#import””用于对自定义的文件的引用,编译器首先回去用户目录下查找,然后去安装目录,最后去系统目录中查找文件。
18.@class的作用是什么?
答:@class的作用是告诉编译器有@class后面的内容是一个类名。只是告诉编译器存在这么一个类,类具体包含哪些方法,属性和变量的并没有告诉编译器。一般在类的头文件中使用@class来引入其他类。
55.简述你对UIView、UIWindow、CALayer的理解。
答:CALayer是图层类,本身可以显示的,但是不能响应事件。
UIView是iOS系统中界面元素的基础,所有的界面元素都继承自它。事件的处理由它来执行,但是显示其实是由其对应的layer层来操作的,UIView内嵌了一个layer,layer显示内容,UIView本身增加了事件处理的功能。
UIWindow继承自UIView,主要的作用是作为窗口呈现其他的视图。而且一个应用程序一般情况下只有一个窗口。
2.Sizeof和strlen的区别和联系?
sizeof(...)是运算符,在头文件中typedef为unsigned int,其值在编译时即计算好了,参数可以是数组、指针、类型、对象、函数等。
它的功能是:获得保证能容纳实现所建立的最大对象的字节大小。
由于在编译时计算,因此sizeof不能用来返回动态分配的内存空间的大小。实际上,用sizeof来返回类型以及静态分配的对象、结构或数组所占的空间,返回值跟对象、结构、数组所存储的内容没有关系。
strlen(...)是函数,要在运行时才能计算。参数必须是字符型指针(char*)。当数组名作为参数传入时,实际上数组就退化成指针了。
它的功能是:返回字符串的长度。该字符串可能是自己定义的,也可能是内存中随机的,该函数实际完成的功能是从代表该字符串的第一个地址开始遍历,直到遇到结束符NULL。返回的长度大小不包括NULL。
区别和联系:
1.sizeof操作符的结果类型是size_t,它在头文件中typedef为unsigned int类型。
该类型保证能容纳实现所建立的最大对象的字节大小。
2.sizeof是运算符,strlen是函数。
3.sizeof可以用类型做参数,strlen只能用char*做参数,且必须是以''\0''结尾的。
sizeof还可以用函数做参数,比如:
short f();
printf("%d\n", sizeof(f()));
输出的结果是sizeof(short),即2。
4.数组做sizeof的参数不退化,传递给strlen就退化为指针了。
5.大部分编译程序 在编译的时候就把sizeof计算过了 是类型或是变量的长度这就是sizeof(x)可以用来定义数组维数的原因
char str[20]="0123456789";
int a=strlen(str); //a=10;
int b=sizeof(str); //而b=20;
6.strlen的结果要在运行的时候才能计算出来,时用来计算字符串的长度,不是类型占内存的大小。
7.sizeof后如果是类型必须加括弧,如果是变量名可以不加括弧。这是因为sizeof是个操作符不是个函数。
8.当适用了于一个结构类型时或变量,sizeof返回实际的大小,
当适用一静态地空间数组,sizeof归还全部数组的尺寸。
sizeof操作符不能返回动态地被分派了的数组或外部的数组的尺寸
3.do while和while do的区别?
while语句是先测试条件再执行语句,条件不符后终止
do while语句是先执行语句再测试条件,条件不符后终止,所以do while循环至少执行一次
15、const意味着”只读”,关键字const什么含义?下面的声明都是什么意思?
const int a;
int const a;
const int *a;
int * const a;
int const * a const;
前两个的作⽤用是⼀一样,a是⼀一个常整型数。第三个意味着a是⼀一个指向常整型数的指针(也就是,整型数是不可修改的,但指针可以)。第四个意思a是⼀一个指向整型数的常指针(也就是说,指针指向的整型数是可以修改的,但指针是不可修改的)。最后⼀一个意味着a是⼀一个指向常整型数的常指针(也就是说,指针指向的整型数是不可修改的,同时
指针也是不可修改的)。
欲阻⽌止⼀一个变量被改变,可以使⽤用const关键字。在定义该const变量时,通常需要对它进⾏行初
始化,因为以后就没有机会再去改变它了;
(2)对指针来说,可以指定指针本⾝身为const,也可以指定指针所指的数据为const,或⼆二者同时指
定为const;
(3)在⼀一个函数声明中,const可以修饰形参,表明它是⼀一个输⼊入参数,在函数内部不
能改变其值;
(4)对于类的成员函数,若指定其为const类型,则表明其是⼀一个常函数,不能修改类的成员变量;
(5)对于类的成员函数,有时候必须指定其返回值为const类型,以使得其返回值不 为“左值”。
4.关键字volatile有什么含义?
一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。精确地说就是,优化器在用到
这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。下面是volatile变量的几个例子:
• 并行设备的硬件寄存器(如:状态寄存器)
• 一个中断服务子程序中会访问到的非自动变量(Non-automatic variables)
• 多线程应用中被几个任务共享的变量
• 一个参数既可以是const还可以是volatile吗?解释为什么。
• 一个指针可以是volatile吗?解释为什么。
下面是答案:
• 是的。一个例子是只读的状态寄存器。它是volatile因为它可能被意想不到地改变。它是const因为程序不应该试图去修改它。
• 是的。尽管这并不很常见。一个例子是当一个中服务子程序修该一个指向一个buffer的指针时。
6、nil,NSNULL,NULL区别
nil定义一个实例为空,指向oc中对象的空指针.是对objective c id对象赋空值,对于objective c集合类对象 比如数组对象,字典对象,当我们不需要再使用他们的时候,对他们release的同时最好也把他们赋值为nil,这样确保安全性,如果不赋值nil,可能导致程序崩溃
NSNull类定义了一个单例对象用于表示集合对象的空值
集合对象无法包含nil作为其具体值,如NSArray、NSSet和NSDictionary。相应地,nil值用一个特定的对象NSNull来表示。NSNull提供了一个单一实例用于表示对象属性中的的nil值。默认的实现方法中,dictionaryWithValuesForKeys:和setValuesForKeysWithDictionary:自动地将NSNull和nil相互转换,因此您的对象不需要进行NSNull的测试操作。
NULL可以用在C语言的各种指针上,在Objective-C里,nil对象被设计来跟NULL空指针关联的。他们的区别就是nil是一个对象,而NULL只是一个值。而且我们对于nil调用方法,不会产生crash或者抛出异常。
8、NSDictionary和NSMutableDictionary的区别,是有序还是无序(追问:可以排序吗?如何排序,最好代码实现)
NSDictionary是不可变的对象,NSMutableDictionary是可变对象,可以进行添加和删除操作。
是无序的
排序的话可以这样做:
1.获取所有的key
NSArray *myKeys = [myDictionary allKeys];
2.对key进行排序
NSArray *sortedKeys = [myKeys sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
3.按照key获取对象
id firstObject = [myDictionary objectForKey: [sortedKeys objectAtIndex:0]];
keysSortedByValueUsingSelector/keysSortedByValueUsingComparator通过使用指定SEL或NSComarator来对allKeys进行排序,然后通过objectsForKeys取出排序后的键-值对。
5、内存中的栈和堆的区别是什么?哪些数据在栈上哪些数据在堆上?
(1)管理方式:对于栈来讲,是由编译器自动管理,无需我们手工控制;对于堆来说,释放工作由程序员控制,容易产生memory leak。
(2)申请大小:能从栈获得的空间较小,堆是向高地址扩展的数据结构,是不连续的内存区域。堆的大小受限于计算机系统中 有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。
(3)碎片问题:对于堆来讲,频繁的new/delete势必会造成内存空间的不连续,从而造成大量的碎片,使程序效率降低。 对于栈来讲,则不会存在这个问题,因为栈是先进后出的队列,他们是如此的一一对应,以至于永远都不可能有一个内存块 从栈中间弹出
(4)分配方式:堆都是动态分配的,没有静态分配的堆。栈有2种分配方式:静态分配和动态分配。静态分配是编译器完成 的,比如局部变量的分配。动态分配由alloca函数进行分配,但是栈的动态分配和堆是不同的,他的动态分配是由编译器 进行释放,无需我们手工实现。
(5)分配效率:栈是机器系统提供的数据结构,计算机会在底层对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈 都有专门的指令执行,这就决定了栈的效率比较高。堆则是C/C++函数库提供的,它的机制是很复杂的。
在函数体中定义的变量通常是在栈上,用malloc, calloc, realloc等分配内存的函数分配得到的就是在堆上。
8)浅复制和深复制的区别
浅层复制:只复制指向对象的指针,而不复制引用对象本身。
深层复制:复制引用对象本身。
意思就是说我有个A对象,复制一份后得到A_copy对象后,对于浅复制来说,A和A_copy指向的是同一 个内存资源,复制的只不过是是一个指针,对象本身资源 还是只有一份,那如果我们对A_copy执行了修改操作,那么发现A引用的对象同样被修改,这其实违背 了我们复制拷贝的一个思想。深复制就好理解了,内存中存在了
两份独立对象本身。
用网上一哥们通俗的话将就是:
浅复制好比你和你的影子,你完蛋,你的影子也完蛋
深复制好比你和你的克隆人,你完蛋,你的克隆人还活着。
深浅拷贝前提是:是实现NSCopying或者NSMutableCopying协议。
浅拷贝只是复制对象本身,对象的属性和包含的对象不做复制。
深拷贝则对对象本身复制,同时对对象的属性也进行复制。
深浅拷贝的本质区别是对象或者对象属性的内存地址是否一样,一样则为浅拷贝,不一样则为深拷贝。
Foundation框架支持复制的类,默认是浅拷贝。其中对Foundation中不可变的对象进行copy时作用相当于retain。
而如果是mutablecopy时,无论对象是否可变,副本是可变的,并且实现了真正意义上的copy。如果对可变对象进行copy,
副本对象是不可变的,同样是真正意义上的copy。
12readwrite,readonly,assign,retain,copy,nonatomic属性的作⽤
@property是⼀一个属性访问声明,扩号内⽀支持以下⼏几个属性: 1,getter=getterName,setter=setterName,设置setter与getter的⽅方法名2,readwrite,readonly,设置可供访问级别2,assign,setter⽅方法直接赋值,不进⾏行任何retain操作,为了解决原类型与环循引⽤用问题3,retain,setter⽅方法对参数进⾏行release旧值再retain新值,所有实现都是这个顺序(CC上有相关资料) 4,copy,setter⽅方法进⾏行Copy操作,与retain处理流程⼀一样,先旧值release,再Copy出新的对象, retainCount为1。这是为了减少对上下⽂文的依赖⽽而引⼊入的机制。copy是在你不希望a和b共享⼀一块内存时会使⽤用到。a和b各⾃自有⾃自⼰己的内存。5,nonatomic,⾮非原⼦子性访问,不加同步,多线程并发访问会提⾼高性能。注意,如果不加此属性,则 默认是两个访问⽅方法都为原⼦子型事务访问。锁被加到所属对象实例级(我是这么理解的...)。atomic和nonatomic⽤用来决定编译器⽣生成的getter和setter是否为原⼦子操作。在多线程环境下,原⼦子操作 是必要的,否则有可能引起错 误的结果。
property中属性retain,copy,assgin的含义分别是什么?有什么区别?将其转换成get/set方法怎么做?有什么注意事项?
assign: 简单赋值,不更改索引计数(Reference Counting)。
copy: 建立一个索引计数为1的对象,然后释放旧对象
retain:释放旧的对象,将旧对象的值赋予输入对象,再提高输入对象的索引计数为1
使用assign:对基础数据类型 (NSInteger,CGFloat)和C数据类型(int, float, double, char,等等)
使用copy: 对NSString
使用retain: 对其他NSObject和其子类
retain表示持有特性,setter方法将传入参数先保留,再赋值,传入参数的retaincount会+1;
- (void)setInstance:(id)instance{
if (_instance != instance) {
[_instance release];
_instance = [instance retain];
}
}
copy表示赋值特性,setter方法将传入对象复制一份;需要完全一份新的变量时。
- (void)setInstance:(id)instance{
if (_instance != instance) {
[_instance release];
_instance = [instance copy];
}
}
assign是赋值特性,setter方法将传入参数赋值给实例变量;仅设置变量时;
- (void)setInstance:(id)instance{
if (_instance != instance) {
_instance = instance;
}
}
7、setValue和setObject区别
在使用NSMutableDictionary的时候经常会使用setValue forKey与setObject forKey,他们经常是可以交互使用的,代码中经常每一种的使用都有。
他们2者的区别就是:
1、setObject:forkey:中value是不能够为nil的,不然会报错。
setValue:forKey:中value能够为nil,但是当value为nil的时候,会自动调用removeObject:forKey方法
2、setValue:forKey:中key的参数只能够是NSString类型,而setObject:forKey:的可以是任何类型
3、setObject:forKey:方法NSMutabledictionary特有的,而
setValue:forKey:方法是KVC(键-值编码)的主要方法。
、类别和扩展
8、声明并实现一个cotegory为UIView添加addNewView方法
.h
@interface UIView (AddNewView)
- (void)addNewView:(UIView *)view;
@end
.m
#import "UIView+AddNewView.h"
@implementation UIView (AddNewView)
- (void)addNewView:(UIView *)view
{
[self addSubview:view];
}
@end
9)类别和类扩展的区别
category和extensions的不同在于后者可以添加属性。另外后者添加的⽅方法是必须要实现的。extensions可以认为是⼀一个私有的Category。
9.原子(atomic)跟非原子(non-atomic)属性有什么区别?
①. atomic提供多线程安全。是防止在写未完成的时候被另外一个线程读取,造成数据错误
②. non-atomic:在自己管理内存的环境中,解析的访问器保留并自动释放返回的值,如果指定了nonatomic,那么访问器只是简单地返回这个值。
12.类别的作用?继承和类别在实现中有何区别?
category可以在不获悉,不改变原来代码的情况下往里面添加新的方法,只能添加,不能删除修改。
并且如果类别和原来类中的方法产生名称冲突,则类别将覆盖原来的方法,因为类别具有更高的优先级。
类别主要有3个作用:
(1)将类的实现分散到多个不同文件或多个不同框架中。
(2)创建对私有方法的前向引用。
(3)向对象添加非正式协议。
继承可以增加,修改或者删除方法,并且可以增加属性。
14.什么是KVO和KVC?
kvc:键 – 值编码是一种间接访问对象的属性使用字符串来标识属性,而不是通过调用存取方法,直接或通过实例变量访问的机制。
很多情况下可以简化程序代码。apple文档其实给了一个很好的例子。
kvo:键值观察机制,他提供了观察某一属性变化的方法,极大的简化了代码。
具体用看到嗯哼用到过的一个地方是对于按钮点击变化状态的的监控。
比如我自定义的一个button
[self addObserver:self forKeyPath:@"highlighted" options:0 context:nil];
#pragma mark KVO
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if ([keyPath isEqualToString:@"highlighted"] ) {
[self setNeedsDisplay];
}
}
对于系统是根据keypath去取的到相应的值发生改变,理论上来说是和kvc机制的道理是一样的。
对于kvc机制如何通过key寻找到value:
“当通过KVC调用对象时,比如:[self valueForKey:@”someKey”]时,程序会自动试图通过几种不同的方式解析这个调用。首先查找对象是否带有someKey这个方法,如果没找到,会继续查找对象是否带有someKey这个实例变量(iVar),如果还没有找到,程序会继续试图调用-(id) valueForUndefinedKey:这个方法。如果这个方法还是没有被实现的话,程序会抛出一个NSUndefinedKeyException异常错误。(cocoachina.com注:Key-Value Coding查找方法的时候,不仅仅会查找someKey这个方法,还会查找getsomeKey这个方法,前面加一个get,或者_someKey以及_getsomeKey这几种形式。同时,查找实例变量的时候也会不仅仅查找someKey这个变量,也会查找_someKey这个变量是否存在。)设计valueForUndefinedKey:方法的主要目的是当你使用-(id)valueForKey方法从对象中请求值时,对象能够在错误发生前,有最后的机会响应这个请求。这样做有很多好处,下面的两个例子说明了这样做的好处。“来至cocoa,这个说法应该挺有道理。因为我们知道button却是存在一个highlighted实例变量.因此为何上面我们只是add一个相关的keypath就行了,可以按照kvc查找的逻辑理解,就说的过去了。
15.我们说的OC是动态运行时语言是什么意思?
多态。 主要是将数据类型的确定由编译时,推迟到了运行时。
这个问题其实浅涉及到两个概念,运行时和多态。
简单来说,运行时机制使我们直到运行时才去决定一个对象的类别,以及调用该类别对象指定方法。
多态:不同对象以自己的方式响应相同的消息的能力叫做多态。意思就是假设生物类(life)都用有一个相同的方法-eat;
那人类属于生物,猪也属于生物,都继承了life后,实现各自的eat,但是调用是我们只需调用各自的eat方法。
也就是不同的对象以自己的方式响应了相同的消息(响应了eat这个选择器)。因此也可以说,运行时机制是多态的基础。
18.类变量的@protected ,@private,@public,@package,声明各有什么含义?(OC第二讲 实例变量可见度与方法)
上面的几个声明表明的时类成员的作用域,@private作用范围只能在自身类(外界既不可访问,又不能继承);@protected作用范围在自身类和子类,如果什么都不加修饰,默认是@protected(外界不可访问,但是可以继承);@public作用范围最大,可以在任何地方被访问(外界即可访问,又可以继承);@package作用范围在某个框架内
线程是什么?进程是什么?二者有什么区别和联系? (UI第二十二讲 多线程编程)
线程是CPU独立运行和独立调度的基本单位(可以理解为一个进程中执行的代码片段),进程是资源分配的基本单位(进程是一块包含了某些资源的内存区域)。进程是线程的容器,真正完成代码执行的是线程,而进程则作为线程的执行环境。一个程序至少包含一个进程,一个进程至少包含一个线程,一个进程中的多个线程共享当前进程所拥有的资源。
32. What is lazy loading?
在使用的时候才去初始化,比如UITableViewCell的imageView属性,懒加载对象的创建是在getter方法里面进行创建的。
34. isKindOfClass、isMemberOfClass作用分别是什么?
-(BOOL) isKindOfClass: classObj判断是否是这个类或者是这个类子类的实例
-(BOOL) isMemberOfClass: classObj判断是否是这个类的实例
OC里怎么实现多继承
OC没有多继承。用协议实现多继承,把协议中的方法在实现的类 中重写C++有多继承,多继承其实用好了很方便。C++多继承很容易出现 二一性比如:
类A { int a;}
类B:类A,类C:类A
类D : B, C那么int a到底是继承自谁的单继承
60.使用圆角效果时为什么会出现卡顿效果,如何解决这个问题?
不要在滚动视图使用cornerRadius或者mask,添加self.layer.shouldRasterize = YES; self.layer.rasterizationScale = [UIScreen mainScreen].scale;
采取预先生成圆角图片,并缓存起来这个方法才是比较好的手段。预处理圆角图片可以在后台处理,处理完毕后缓存起来,再在主线程显示,这就避免了不必要的离屏渲染了。
在网络请求中如何提高性能
在网络请求中如何保证安全性
iOS在数据传输过程中有数据泄露的可能,客户端在进行网络请求时一般都采用加密的方式来保证数据的安全性,在iOS9以后,苹果为了保护数据的安全性,使用了Https协议。
86.#define和const定义的变量,有什么区别什么情况下会出现内存的循环引用block中的weak self,是任何时候都需要加的么?
答案:
1.宏:只是在预处理器里进行文本替换,没有类型,不做任何类型检查,编译器可以对相同的字符串进行优化。只保存一份到.rodata段。甚至有相同后缀的字符串也可以优化,你可以用GCC编译测试,"Hello world"与"world"两个字符串,只存储前面一个。取的时候只需要给前面和中间的地址,如果是整形、浮点型会有多份拷贝,但这些数写在指令中。占的只是代码段而已,大量用宏会导致二进制文件变大.常量:共享一块内存空间,就算项目中N处用到,也不会分配N块内存空间,可以根据const修饰的位置设定能否修改,在编译阶段会执行类型检查
2.(1)计时器NSTimer
一方面,NSTimer经常会被作为某个类的成员变量,而NSTimer初始化时要指定self为target,容易造成循环引用。 另一方面,若timer一直处于validate的状态,则其引用计数将始终大于0.
(2)block
block在copy时都会对block内部用到的对象进行强引用(ARC)或者retainCount增1(非ARC)。在ARC与非ARC环境下对block使用不当都会引起循环引用问题,一般表现为,某个类将block作为自己的属性变量,然后该类在block的方法体里面又使用了该类本身,简单说就是self.someBlock = ^(Type var){[self dosomething];或者self.otherVar = XXX;或者_otherVar = ...};block的这种循环引用会被编译器捕捉到并及时提醒。
(3)委托delegate
在委托问题上出现循环引用问题已经是老生常谈了,本文也不再细讲,规避该问题的杀手锏也是简单到哭,一字诀:声明delegate时请用assign(MRC)或者weak(ARC),千万别手贱玩一下retain或者strong,毕竟这基本逃不掉循环引用了!
3.使用方将self或成员变量加入block之前要先将self变为__weak
Configuration中,debug和release的区别是什么?
Release是发行版本,比Debug版本有一些优化,文件比Debug文件小Debug是调试版本,Debug和Release调用两个不同的底层库。
一、"Debug是调试版本,包括的程序信息更多"
二、只有DEBUG版的程序才能设置断点、单步执行、使用TRACE/ASSERT等调试输出语句。
三、REALEASE不包含任何调试信息,所以体积小、运行速度快。
、Initilize和load的区别
http://www.cnblogs.com/ider/archive/2012/09/29/objective_c_load_vs_initialize.html
1.怎么修改只读(readonly)属性的变量
使用KVC可以修改,kvc就是键值编码(key-value),可以通过指定的key获得想要的值value。而不是通过调用Setter、Getter方法访问。
什么情况使⽤用weak关键字,相⽐比assign有什么不同?在ARC中,防⽌止在有可能出现循环引⽤用的时候使⽤用weak关键字,⽐比如:block。assign可以修饰基本数据类型和C数据类型,也就是简单的赋值,⽽而weak只能修饰OC对象类型。
1)在ARC中,在有可能出现循环引⽤用的时候,往往要通过让其中⼀一端使⽤用weak来解决,⽐比如:delegate代理属性
2)自身已经对它进⾏行⼀一次强引⽤用,没有必要再强引⽤用⼀一次,此时也会使⽤用weak,⾃自定义IBOutlet控件属性⼀一般也使⽤用weak;当然,也可以使⽤用strong。在下文也有论述:《IBOutlet连出来的视图属性为什么可以被设置成weak?》不同点:
1)weak此特质表明该属性定义了⼀一种“⾮非拥有关系”(nonowning relationship)。为这种属性设置新值时,设置⽅方法既不保留新值,也不释放旧值。此特质同assign类似,然⽽而在属性所指的对象遭到摧毁时,属性值也会清空(nil out)。⽽而assign的“设置⽅方法”只会执⾏行针对“纯量类型”(scalar type,例如CGFloat或NSlnteger等)的简单赋值操作。
2) assign可以用非OC对象,而weak必须用于OC对象
3、copy和mutablecopy的区别copy返回⼀一个不可变对象,mutableCopy是创建⼀一个新的可变对象,并初始化源
对象的值,引⽤用计数为1。
1. mutableCopy创建⼀一个新的可变对象,并初始化为原对象的值,新对象的引用计数为1;
2. copy返回⼀一个不可变对象。分两种情况:(1)若原对象是不可变对象,那么返回原对象,并将其引用计数加1 ;(2)若原对象是可变对象,那么创建⼀一个新的不可变对象,并初始化为原对象的值,新对象的引用计数为1。
@synthesize和@dynamic的区别?
@synthesize就是⾃自动⽣生成属性的setter和getter⽅方法。
@dynamic就是要告诉编译器,⾃自⼰己实现⽅方法。
object-c为了让java的开发者习惯使⽤用.的操作,所以可以将接⼜⼝口类中的变量使⽤用@property来声明属性。但是在.h中声明的属性,必须在.m中使⽤用@synthesize或者@dynamic来实现(传⾔言,在最近出的ios6中这步已经省了),否则属性不可⽤用。熟悉object-c语法的都知道@synthesize实际的意义就是⾃自动⽣生成属性的setter和getter⽅方法。
@dynamic就是要告诉编译器,代码中⽤用@dynamic修饰的属性,其getter和setter⽅方法会在程序运⾏行的时候或者⽤用其他⽅方式动态绑定,以便让编译器通过编译。其主要的作⽤用就是⽤用在NSManagerObject对象的属性声明上,由于此类对象的属性⼀一般是从Core Data的属性中⽣生成的,core data框架会在程序运⾏行的时候为此类属性⽣生成getter和setter⽅方法,但是如果不是NSManagerObject的⼦子类,就必须⼿手动实现setter和getter⽅方法,否则将出现野指针;
5、__block和__weak修饰符的区别
1.__block不管是ARC还是MRC模式下都可以使用,可以修饰对象,还可以修饰基本数据类型。
2.__weak只能在ARC模式下使用,也只能修饰对象(NSString),不能修饰基本数据类型(int)。
3.__block对象可以在block中被重新赋值,__weak不可以。
PS:__unsafe_unretained修饰符可以被视为iOS SDK 4.3以前版本的__weak的替代品,不过不会被自动置空为nil。所以尽可能不要使用这个修饰符。
6.在什么情况下会用到weak这个关键字,作用是什么?
适用于OC对象,作用和非ARC中的assign作用相同,修饰的成员变量为弱指针类型
IBOutlet的属性一般可以设为weak是因为它已经被view引用了,除非view被释放,否则IBOutlet的属性也不会被释放,另外IBOutlet属性的生命周期和view应该是一致的,所以IBOutlet属性一般设为weak。
4、队列和栈的区别是什么?
1.队列先进先出,栈先进后出。
2.对插入和删除操作的"限定"。 栈是限定只能在表的一端进行插入和删除操作的线性表。 队列是限定只能在表的一端进行插入和在另一端进行删除操作的线性表。 从"数据结构"的角度看,它们都是线性结构,即数据元素之间的关系相同。但它们是完全不同的数据类型。除了它们各自的基本操作集不同外,主要区别是对插入和删除操作的"限定"。 栈和队列是在程序设计中被广泛使用的两种线性数据结构,它们的特点在于基本操作的特殊性,栈必须按"后进先出"的规则进行操作,而队列必须按"先进先出"的规则进行操作。和线性表相比,它们的插入和删除操作受更多的约束和限定,故又称为限定性的线性表结构。
3.遍历数据速度不同。栈只能从头部取数据 也就最先放入的需要遍历整个栈最后才能取出来,而且在遍历数据的时候还得为数据开辟临时空间,保持数据在遍历前的一致性队列怎不同,他基于地址指针进行遍历,而且可以从头或尾部开始遍历,但不能同时遍历,无需开辟临时空间,因为在遍历的过程中不影像数据结构,速度要快的多。
8、NSDictionary和NSMutableDictionary的区别,是有序还是无序(追问:可以排序吗?如何排序,最好代码实现)
NSDictionary是不可变的对象,NSMutableDictionary是可变对象,可以进行添加和删除操作。
是无序的
排序的话可以这样做:
1.获取所有的key
NSArray *myKeys = [myDictionary allKeys];
2.对key进行排序
NSArray *sortedKeys = [myKeys sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
3.按照key获取对象
id firstObject = [myDictionary objectForKey: [sortedKeys objectAtIndex:0]];
keysSortedByValueUsingSelector/keysSortedByValueUsingComparator通过使用指定SEL或NSComarator来对allKeys进行排序,然后通过objectsForKeys取出排序后的键-值对。
9、推送通知和本地通知的区别
本地推送和远程推送的区别是本地推送一般是用来实现闹钟或者生日提醒的功能.远程推送是为了实现服务器想要把及时的消息在某个特定的时间发送给用户的手段.
本地推送不需要申请推送证书,远程推送需要先申请证书然后再去实现证书.
13.AVPlayer AVAudioPlayer MediaPlayer的不同
AVAudioPlayer:使用简单方便,但只能播放本地音频,不支持流媒体播放
AVPlayer: iOS4.0以后,可以使用AVPlayer播放本地音频和支持流媒体播放,但是提供接口较少,处理音频不够灵活
MediaPlayer :是用来处理网络上的视频文件的播放的系统类.
24XML、JSON解析;
(1)区别:
(1)可读性方面:基本相同,xml的可读性比较好
(2)可扩展性方面:都具有很好的扩展性
(3)编码难度方面:相对而言:JSON的编码比较容易
(4)解码难度:json的解码难度基本为零,xml需要考虑子节点和父节点
(5)数据体积方面:json相对于xml来讲,数据体积小,传递的速度跟快些
(6)数据交互方面:json与JavaScript的交互更加方面,更容易解析处理,更好的数据交互
(7)数据描述方面:xml对数据描述性比较好
(8)传输速度方面:json的速度远远快于xml
(2)
1)JSON底层原理:
遍历字符串中的字符,最终根据格式规定的特殊字符,比如{}号,[]号, :号等进行区分,{}号是一个字典的开始,[]号是一个数组的开始, :号是字典的键和值的分水岭,最终乃是将json数据转化为字典,字典中值可能是字典,数
组,或字符串而已。
2)XML底层原理:XML解析常用的解析方法有两种:DOM解析和SAX解析。DOM采用建立树形结构的方式访问XML文档,而
SAX采用的事件模型。
DOM解析把XML文档转化为一个包含其内容的树,并可以对树进行遍历。使用DOM解析器的时候需要处理整个XML文档,所以对性能和内存的要求比较高。SAX在解析XML文档的时候可以触发一系列的事件,当发现给定的tag的时候,它可以激活一个回调方法,告诉该方法制定的标签已经找到。SAX对内存的要求通常会比较低,因为它让开发人员自己来决定所要处理的tag。特别是当开发人员只需要处理文档中所包含的部分数据时,SAX这种扩展能力得到了更好的体现。
3)SAX与DOM的区别:
1、SAX处理的优点非常类似于流媒体的优点。分析能够立即开始,而不是等待所有的数据被处理。而且由于应用程序只是在读取数据时检查数据,因此不需要将数据存储在内存中。这对于大型文档来说是个巨大的优点。事实上,应用程序甚至不必解析整个文档;它可以在某个条件得到满足时停止解析。一般来说,SAX还比它的替代者DOM快许多。另一方面,由于应用程序没有以任何方式存储数据,使用SAX来更改数据或在数据流中往后移是不可能的。
2、DOM以及广义的基于树的处理具有几个优点。首先,由于树在内存中是持久的,因此可以修改它以便应用程序能对数据和结构作出更改。它还可以在任何时候在树中上下导航,而不是像SAX那样是一次性的处理。DOM使用起来也要简单得多。另一方面,在内存中构造这样的树涉及大量的开销。大型文件完全占用系统内存容量的情况并不鲜见。此外,创建一棵DOM树可能是一个缓慢的过程。
11.方法(method)和选择器有何不同?
NSDictionary是不可变的对象,NSMutableDictionary是可变对象,可以进行添加和删除操作。
是无序的
排序的话可以这样做:
1.获取所有的key
NSArray *myKeys = [myDictionary allKeys];
2.对key进行排序
NSArray *sortedKeys = [myKeys sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
3.按照key获取对象
id firstObject = [myDictionary objectForKey: [sortedKeys objectAtIndex:0]];
keysSortedByValueUsingSelector/keysSortedByValueUsingComparator通过使用指定SEL或NSComarator来对allKeys进行排序,然后通过objectsForKeys取出排序后的键-值对。
1.bounds和frame的区别?bound的大小改变frame改变吗?
bounds相当于是一个视图的坐标,一个视图的frame是相对于父视图的bounds,改变bounds并不会影响本视图的frame,但是会对子视图的布局造成影响
24.说说响应链
当事件发生的时候,响应链首先被发送给第一个响应者(往往是事件发生的视图,也就是用户触摸屏幕的地方)。事件将沿着响应者链一直向下传递,直到被接受并作出处理。一般来说,第一响应这是个视图对象或者其子类,当其被触摸后事件就交由它处理,如果他不处理,时间就会被传递给视图控制器对象UIViewController(如果存在),然后是它的父视图对象(superview),以此类推直到顶层视图。接下来会沿着顶层视图(topview)到窗口(UIwindow对象)再到程序的(UIApplication对象),如果整个过程都没有响应这个事件,则该事件被丢弃,一般情况下,在响应链中只要有对象处理事件,事件就会被传递典型的响应路线图如:First Responser -> The Window ->The Applicationn -> App Delegate
4、drawInRect
在运行到drawInRect:withFont: lineBreakMode:alignment:,出现提示iOS7弃用这个方法,使用drawInRect:withAttributes:的方法的提示。但是这个方法在说明的时候,写的很简单,第二个参数是一个字典,根本就搞不明白是什么东西。我在查了不少资料后,才翻到字典里面能存放的东西:NSAttributedString,里面竟然可以使用21组键值对,功能强大了不少。NSParagraphStyleAttributeName这个key就能代替iOS6上的那个弃用方法,不过值必须得是NSMutableParagraphStyle,不然不能自定义
5、NSAttributedString属性字符串
NSAttributedString管理一个字符串,以及与该字符串中的单个字符或某些范围的字符串相关的属性。比如这个字符串“我爱北京天安门”,“我”跟其他字符的颜色不一样,而“北京”与其他的字体和大小不一样,等等。NSAttributedString就是用来存储这些信息的,具体实现时,NSAttributedString维护了一个NSString,用来保存最原始的字符串,另有一个NSDictionary用来保存各个子串/字符的属性。
学习链接:http://blog.csdn.net/zhangao0086/article/details/7616385
UIScrollview重用机制
事件处理看过了,就要考虑scrollView如何重用内存的,下面写了一个例子模仿UITableView的重用的思想,这里只是模仿,至于苹果公司怎么实现这种重用的,他们应该有更好的方法。
这里的例子是在scrollView上放置4个2排2列的视图,但是内存中只占用6个视图的内存空间。当scrollView滚动的时候,通过不停的重用之前视图的内存空间,从而达到节省内存的效果。重用的方法如下:
1.如果scrollView向下面滚动,一旦一排视图滚出了可视范围,就改变滚动出去的那个view在scrollView中的frame,也就是改变位置到达末尾,达到重用的效果。
2.如果scrollView向上面滚动,一旦最末排的视图view滚出了可视范围,就改变滚动出去的那个view在scrollView中的frame,移动到最前面。
8、描述什么是面向对象?
面向对象:
把数据及对数据的操作方法放在一起,作为一个相互依存的整体——对象。对同类对象抽象出其共性,形成类。类中的大多数数据,只能用本类的方法进行处理。类通过一个简单的外部接口与外界发生关系,对象与对象之间通过消息进行通信。程序流程由用户在使用中决定。
1、UITableView的执行流程是怎么样的?
第一轮:
1、numberOfSectionsInTableView:假如section=2,此函数只执行一次,假如section=0,下面函数不执行,默认为1
2、heightForHeaderInSection,执行两次,此函数执行次数为section数目
3、heightForFooterInSection,函数属性同上,执行两次
4、numberOfRowsInSection,此方法执行一次
5、heightForHeaderInSection,此方法执行了两次,我其实有点困惑为什么这里还要调用这个方法
6、heightForFooterInSection,此方法执行两次,
7、numberOfRowsInSection,执行一次
8、heightForRowAtIndexPath,行高,先执行section=0,对应的row次数
第二轮:
1、numberOfSectionsInTableView,一次
2、heightForHeaderInSection,section次数
3、heightForFooterInSection,section次数
4、numberOfRowsInSection,一次
5、heightForHeaderInSection,执行section次数
6、heightForFooterInSection,执行section次数
7、numberOfRowsInSection,执行一次
8、heightForRowAtIndexPath,行高,先执行一次
9、cellForRowAtIndexPath
10、willDisplayCell
然后8、9、10依次执行直到所有的cell被描画完毕
网友评论