iOS面试题整理001

iOS面试题整理001

Object-c的类可以多重继承么?可以实现多个接口么?Category是什么?重写一个类的方式用继承好还是分类好?为什么?

Object-c的类不可以多重继承;可以实现多个接口,通过实现多个接口可以完成C++的多重继承;Category是类别,一般情况用分类好,用Category去重写类的方法,仅对本Category有效,不会影响到其他类与原有类的关系。

#import 跟#include 又什么区别,@class呢, #import<> 跟#import””又什么区别?
  • import是Objective-C导入头文件的关键字,

  • include是C/C++导入头文件的关键字,使用#import头文件会自动只导入一次,不会重复导入,相当于#include和#pragma once;

  • @class告诉编译器某个类的声明,当执行时,才去查看类的实现文件,可以解决头文件的相互包含;
  • import<>用来包含系统的头文件,#import””用来包含用户头文件。

属性readwrite,readonly,assign,retain,copy,nonatomic 各是什么作用,在那种情况下用?
  • readwrite 是可读可写特性;需要生成getter方法和setter方法时
  • readonly 是只读特性 只会生成getter方法 不会生成setter方法 ;不希望属性在类外改变
  • assign 是赋值特性,setter方法将传入参数赋值给实例变量;仅设置变量时;
  • retain 表示持有特性,setter方法将传入参数先保留,再赋值,传入参数的retaincount会+1;
  • copy 表示赋值特性,setter方法将传入对象复制一份;需要完全一份新的变量时。
  • nonatomic 非原子操作,决定编译器生成的setter getter是否是原子操作,atomic表示多线程安全,一般使用nonatomic
对于语句NSString*obj = [[NSData alloc] init]; obj在编译时和运行时分别时什么类型的对象?
编译时是NSString的类型;运行时是NSData类型的对象
常见的object-c的数据类型有那些, 和C的基本数据类型有什么区别?如:NSInteger和int

object-c的数据类型有NSString,NSNumber,NSArray,NSMutableArray,NSData等等,这些都是class,创建后便是对象,而C语言的基本数据类型int,只是一定字节的内存空间,用于存放数值;NSInteger是基本数据类型,并不是NSNumber的子类,当然也不是NSObject的子类。NSInteger是基本数据类型Int或者Long的别名(NSInteger的定义typedef long NSInteger),它的区别在于,NSInteger会根据系统是32位还是64位来决定是本身是int还是Long。

id 声明的对象有什么特性?

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

原子(atomic)跟非原子(non-atomic)属性有什么区别?

atomic提供多线程安全。是防止在写未完成的时候被另外一个线程读取,造成数据错误
non-atomic:在自己管理内存的环境中,解析的访问器保留并自动释放返回的值,如果指定了 nonatomic ,那么访问器只是简单地返回这个值。

Object C中创建线程的方法是什么?如果在主线程中执行代码,方法是什么?如果想延时执行代码、方法又是什么?

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

类别的作用?继承和类别在实现中有何区别?

category 可以在不获悉,不改变原来代码的情况下往里面添加新的方法,只能添加,不能删除修改,并且如果类别和原来类中的方法产生名称冲突,则类别将覆盖原来的方法,因为类别具有更高的优先级。
类别主要有3个作用:
1).将类的实现分散到多个不同文件或多个不同框架中。
2).创建对私有方法的前向引用。
3).向对象添加非正式协议。
继承可以增加,修改或者删除方法,并且可以增加属性。

类别和类扩展的区别。

category和extensions的不同在于后者可以添加属性。另外后者添加的方法是必须要实现的。
extensions可以认为是一个私有的Category。

oc中的协议和java中的接口概念有何不同?

网上大家都将oc中的interface理解为“非正式协议(或说接口)”,protocol理解为“正式协议(或说接口)”,我觉得那样理解起来虽然不困难,但是很变扭,于是我做一点自己的理解:
1、protocol就相当于java中的interface;
2、而interface和implementation共同代表一个类,两者的组合相当于java中的class,即oc中的类必须包括两部分,interface部分和implementation部分,这才是oc中的一个类的完整声明;然后OC中将成员变量和成员方法的声明部分放置在interface部分中,包括继承关系,protocol实现关系,都在interface里面的头部进行声明,然后将实现部分放置在implementation部分中,相当于是将类拆分成声明和实现两部分,这两部分缺一不可,所以在OC中,不妨不要将interface叫做接口,直接叫做类声明部分来得容易理解多了,简而言之,oc中interface是类的一个部分,和implementation共同组成一个完整的类。

iOS开发在@interface,@implementation和@property中变量的定义
//ViewController.h
@interface ViewController : UIViewController { 
    NSInteger a; 
} 
@property (nonatomic,assign) NSInteger b; 
@end
//ViewController.m 
@interface ViewController () { 
    NSInteger c; 
} 
@property (nonatomic,assign) NSInteger d; 
@end

a,b,c,d这四个变量有什么不同?
a是成员变量,相当于java中的protected,可以被子类继承。
b相当于java中的public,既可以被子类继承,也可以被外部访问。
c和d个人理解都是私有变量,相当于java中的private,不可以被子类调用,也不可以外部访问。
b 和 d 可以用 self.来访问, a和c不能。
a和c基本上很少用,一般都用b和d,如果需要对外开放的属性的就放在b,不需要的话直接在d位置定义。
a和c我觉的应该是为了兼容早期版本的写法,为了让你自己定义属性对应的内部变量,但是在arc之后的版本中,你只要定义一个属相,xcode会自动帮你定义一个以下划线打头的和属性同名的内部变量,所以你不需要另外再定义了

我们说的oc是动态运行时语言是什么意思?

多态。 主要是将数据类型的确定由编译时,推迟到了运行时。
这个问题其实浅涉及到两个概念,运行时和多态。

运行时:简单来说,运行时机制使我们直到运行时才去决定一个对象的类别,以及调用该类别对象指定方法。

多态:不同对象以自己的方式响应相同的消息的能力叫做多态。意思就是假设生物类(life)都用有一个相同的方法-eat;

那人类属于生物,猪也属于生物,都继承了life后,实现各自的eat,但是调用是我们只需调用各自的eat方法。

也就是不同的对象以自己的方式响应了相同的消息(响应了eat这个选择器)。

关于多态性

多态,子类指针可以赋值给父类。
这个题目其实可以出到一切面向对象语言中,
因此关于多态,继承和封装基本最好都有个自我意识的理解,也并非一定要把书上资料上写的能背出来

frame和bounds有什么不同?

frame指的是:该view在父view坐标系统中的位置和大小。(参照点是父亲的坐标系统)
bounds指的是:该view在本身坐标系统中 的位置和大小。(参照点是本身坐标系统)
demo演示:

UIView *view1 = [[UIView alloc] initWithFrame:CGRectMake(20, 20, 280, 250)];  
[view1 setBounds:CGRectMake(-20, -20, 280, 250)];  
view1.backgroundColor = [UIColor redColor];  
[self.view addSubview:view1];//添加到self.view  
NSLog(@"view1 frame:%@========view1 bounds:%@",NSStringFromCGRect(view1.frame),NSStringFromCGRect(view1.bounds));  

UIView *view2 = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];  
view2.backgroundColor = [UIColor yellowColor];  
[view1 addSubview:view2];//添加到view1上,[此时view1坐标系左上角起点为(-20,-20)]  
NSLog(@"view2 frame:%@========view2 bounds:%@",NSStringFromCGRect(view2.frame),NSStringFromCGRect(view2.bounds)); 

注意: //setBounds 强制将自己坐标系的左上角点改为(-20,-20)。那么真正的原点(0,0)自然向右下角偏移(20,20);
运行结果:
图片 1.png

方法和选择器有何不同?

selector是一个方法的名字,method是一个组合体,包含了名字和实现.

OC的垃圾回收机制?

与Java语言相同Objective-c 2.0之后,也提供了垃圾回收机制。但是在iOS移动终端设备中,并不支持垃圾回收机制。因此,iPhone并不能对内存进行自动垃圾回收处理(autorelease)。因此需要注意垃圾回收机制并不是ARC,ARC也是需要管理内存的,只不过是隐式的管理内存,编译器会再适当的地方自动插入retain,release和autorelease消息。ARC是在IOS5之后推出的新技术,它与GC的机制是不同的。

在应用中可以创建多少autorelease对象,是否有限制?

类和结构体区别?

1、结构体只能封装属性,类却不仅可以封装属性也可以封装方法。如果一个封装的数据有属性也有行为,就只能用类了。
2、结构体变量分配在栈,而OC对象分配在堆,栈的空间相对于堆来说是比较小的,但是存储在栈中的数据访问效率相对于堆而言是比较高
3、堆的存储空间比较大,存储在堆中的数据访问效率相对于栈而言是比较低的
4、如果定义一个结构体,这个结构体中有很多属性,那么这个时候结构体变量在栈中会占据很多空间,这样的话就会降低效率
5、我们使用结构体的时候最好是属性比较少的结构体对象如果属性较多的话就要使用类了。
6、结构体赋值的话是直接赋值,对象的指针,赋值的是对象的地址。

类NSObject的那些方法经常被使用?

NSObject是Objetive-C的基类,其由NSObject类及一系列协议构成
其中类方法alloc、class、 description 对象方法init、dealloc、– performSelector:withObject:afterDelay:等经常被使用

什么是简便构造方法?

简便构造方法一般由CocoaTouch框架提供,如NSNumber的 + numberWithBool: + numberWithChar: + numberWithDouble: + numberWithFloat: + numberWithInt:
Foundation下大部分类均有简便构造方法,我们可以通过简便构造方法,获得系统给我们创建好的对象,并且不需要手动释放。

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

Objective-C堆和栈的区别?

管理方式:对于栈来讲,是由编译器自动管理,无需我们手工控制;对于堆来说,释放工作由程序员控制,容易产生memory leak。

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

用预处理指令#define声明一个常数,用以表明1年中有多少秒(忽略闰年问题)

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

我在这想看到几件事情:

define 语法的基本知识(例如:不能以分号结束,括号的使用,等等)

懂得预处理器将为你计算常数表达式的值,因此,直接写出你是如何计算一年中有多少秒而不是计算出实际的值,是更清晰而没有代价的。
意识到这个表达式将使一个16位机的整型数溢出-因此要用到长整型符号L,告诉编译器这个常数是的长整型数。
如果你在你的表达式中用到UL(表示无符号长整型),那么你有了一个好的起点。记住,第一印象很重要。
重要:
上边这种写法其实不正确的!!!
2019182730.png

写一个”标准"宏MIN ,这个宏输入两个参数并返回较小的一个。

答:

define MIN(A,B) ((A) <= (B) ? (A) : (B))

标识#define在宏中应用的基本知识。这是很重要的,因为直到嵌入(inline)操作符变为标准C的一部分,宏是方便产生嵌入代码的唯一方法,对于嵌入式系统来说,为了能达到要求的性能,嵌入代码经常是必须的方法。三重条件操作符的知识。这个操作符存在C语言中的原因是它使得编译器能产生比 if-then-else 更优化的代码,了解这个用法是很重要的。
懂得在宏中小心地把参数用括号括起来
我也用这个问题开始讨论宏的副作用,例如:当你写下面的代码时会发生什么事?
1 least = MIN(p++, b);
结果是:
1 ((
p++) <= (b) ? (p++) : (p++))
这个表达式会产生副作用,指针p会作三次++自增操作。

猜你喜欢

转载自www.cnblogs.com/1-434/p/10478779.html