iOS_面试题
来源:互联网 发布:mac安装win10启动黑屏 编辑:程序博客网 时间:2024/06/05 09:04
1.父类实现深拷贝时,子类如何实现深度拷贝。父类没有实现深拷贝时,子类如何实现深度拷贝。
深拷贝同浅拷贝的区别:浅拷贝是指针拷贝,对一个对象进行浅拷贝,相当于对指向对象的指针进行复制,产生一个新的指向这个对象的指针,那么就是有两个指针指向同一个对象,这个对象销毁后两个指针都应该置空。深拷贝是对一个对象进行拷贝,相当于对对象进行复制,产生一个新的对象,那么就有两个指针分别指向两个对象。当一个对象改变或者被销毁后拷贝出来的新的对象不受影响。
实现深拷贝需要实现NSCoying协议,实现- (id)copyWithZone:(NSZone *)zone 方法。当对一个property属性含有copy修饰符的时候,在进行赋值操作的时候实际上就是调用这个方法。
父类实现深拷贝之后,子类只要重写copyWithZone方法,在方法内部调用父类的copyWithZone方法,之后实现自己的属性的处理
父类没有实现深拷贝,子类除了需要对自己的属性进行处理,还要对父类的属性进行处理。
2.KVO,NSNotification,delegate及block区别
- KVO就是cocoa框架实现的观察者模式,一般同KVC搭配使用,通过KVO可以监测一个值的变化,比如View的高度变化。是一对多的关系,一个值的变化会通知所有的观察者。
- NSNotification是通知,也是一对多的使用场景。在某些情况下,KVO和NSNotification是一样的,都是状态变化之后告知对方。
NSNotification的特点,就是需要被观察者先主动发出通知,然后观察者注册监听后再来进行响应,比KVO多了发送通知的一步,但是其优点是监听不局限于属性的变化,还可以对多种多样的状态变化进行监听,监听范围广,使用也更灵活。
delegate 是代理,就是我不想做的事情交给别人做。比如狗需要吃饭,就通过delegate通知主人,主人就会给他做饭、盛饭、倒水,这些操作,这些狗都不需要关心,只需要调用delegate(代理人)就可以了,由其他类完成所需要的操作。所以delegate是一对一关系。
block是delegate的另一种形式,是函数式编程的一种形式。使用场景跟delegate一样,相比delegate更灵活,而且代理的实现更直观。
KVO一般的使用场景是数据,需求是数据变化,比如股票价格变化,我们一般使用KVO(观察者模式)。delegate一般的使用场景是行为,需求是需要别人帮我做一件事情,比如买卖股票,我们一般使用delegate。
- Notification一般是进行全局通知,比如利好消息一出,通知大家去买入。delegate是强关联,就是委托和代理双方互相知道,你委托别人买股票你就需要知道经纪人,经纪人也不要知道自己的顾客。
- Notification是弱关联,利好消息发出,你不需要知道是谁发的也可以做出相应的反应,同理发消息的人也不需要知道接收的人也可以正常发出消息。
3.KVC如果实现,如何进行键值查找。KVO如何实现
setValue:forKey:
- 首先搜索setKey:方法。(key指成员变量名,首字母大写)
- 上面setter方法没找到,如果累方法accessInstanceVariablesDirectly返回YES。那么按_key , _isKey,key,iskey的顺序搜索成员名。(NSKeyValueCodingCatogery中实现的类方法,默认实现为返回YES)
- 如果没有找到成员变量,调用setValue:forUnderfineKey:
valueForkey:
- 首先getKey,key,iskey的循序查找getter方法,找到直接调用。如果是BOOL,int 等内建值类型,会做NSNumber的转换。
- 上面的getter没有找到,查找countOfkey,objectInKeyAtindex,KeyAtindexes格式的方法。如果countOfKey和另外两个方法中的一个找到,那么就会返回一个可以享用NSArray所以方法的代理集合的NSArray消息方法。
- 还没找到,查找countOfkey,enumeratorOfKey,memberOfKey格式的方法,如果这三个方法到找到,那么就返回一个可以享用NSSet所以方法的代理集合。
- 还是没找到,如果累方法accessInstanceVariablesDirectly返回YES,那么按_key,_iskey,key,iskey的顺序搜索成员名。
- 再没有找到,调用valueForUndefineKey。
- KVC实现分析
- KVC运用了isa-swizzing技术。isa-swizzing就是类型混合指针机制。KVC通过isa-swizzing实现其内部查找定位。isa指针(is kind of 的意思)指向维护分发表的对象的类,该分发表实际上包含了指向实现类中的方法的指针和其他数据。
KVO,KVC详细
4.将一个函数在主线程执行的4种方法
GCD
dispatch_async(dispatch_get_main_queue(),^{ //需要执行的代码});
NSOperation
NSOperationQueue *mainQueue=[NSOperationQueue mainQueue];//主队列NSBlockOperation *operation=[NSBlockOperation blockOperationWithblock:^{//需要执行的代码}];[mainQueue addOperation:operation];
NSThread方法
[self performSelector:@selector(method) onThread:[NSThread mainThread] withObject:nil waitUntilDone:YES modes:nil];[self performSelectorOnMainThread:@selector(method) withObject:nil waitUntilDone:YES];[[NSThread mainThread] performSelector:@selector(method) withObject:nil];
RunLoop方法
[[NSRunLoop mainRunLoop] performSelector:@selector(method) withObject:nil];
5.如何让计时器调用一个类方法
[NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timerMethod) userInfo:nil repeats:YES];-(void)timerMethod{//调用类方法 [[self class] staticMethod];}-(void)invalid{ [timer invalid]; timer = nil;}
6.如何重写类方法
- 在子类中实现一个同基类名字一样的静态方法
- 在调用的时候不要使用类名调用,而是使用[self class]的方式调用。原理,用类名调用是早绑定,在编译期绑定,用[self class]是晚绑定,在运行时决定调用哪个方法。
7.NSTimer创建后,会在哪个线程运行
- 用scheduledTimerWithTimeInterval创建的,在哪个线程创建就会被加入哪个线程的RunLoop中就运行在哪个线程
- 自己创建的Timer,加入到哪个线程的RunLoop中就运行在哪个线程。
8.id和NSObject*的区别
- id是一个 objc_object 结构体指针
typedef struct objc_object *idid可以理解为指向对象的指针。所有oc的对象 id都可以指向,编译器不会做类型检查,id调用任何存在的方法都不会在编译阶段报错,当然如果这个id指向的对象没有这个方法,该崩溃还是会崩溃的。
NSObject *指向的必须是NSObject的子类,调用的也只能是NSObjec里面的方法否则就要做强制类型转换。
不是所有的OC对象都是NSObject的子类,还有一些继承自NSProxy。NSObject *可指向的类型是id的子集。
9.Obkective-c堆和栈的区别
- 对于栈来讲,是由编译器自动管理,无需我们手工控制;对于堆来说,释放工作由程序员控制,容易产生memory leak。
栈:在Windows下,栈是向低地址扩展的数据结构,是一块连续的内存的区域
堆:堆是向高地址扩展的数据结构,是不连续的内存区域。- 碎片问题:对于堆来讲,频繁的new/delete势必会造成内存空间的不连续,从而造成大量的碎片,使程序效率降低。对于栈来讲,则不会存在这个问题,因为栈是先进后出的队列,他们是如此的一一对应,以至于永远都不可能有一个内存块从栈中间弹出
- 分配效率:栈是机器系统提供的数据结构,计算机会在底层对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高。堆则是C/C++函数库提供的,它的机制是很复杂的。
10.除了MVC,单例和工厂之外说出你知道的其他任意5个设计模式
- 代理模式
- MVVM模式
- 观察者模式
- 策略模式
- 目标-动作模式
11.多线程间通信怎么实现?
@interface BTThreadViewController (){ UIImageView *imagev;}@end- (void)viewDidLoad{ [super viewDidLoad]; imagev = [[UIImageView alloc] initWithFrame:CGRectMake(100, 100, 100, 100)]; [self.view addSubview:imagev]; //子线程里面调用downImage方法下载图片 [self performSelectorInBackground:@selector(downImage) withObject:nil];}-(void)downImage{ //从网络中下载图片 NSURL *url = [NSURL URLWithString:@"http://i8.topit.me/8/c1/31/1142319854bdc31c18o.jpg"]; //将图片转换为二进制数据 NSData *imgData = [NSData dataWithContentsOfURL:url]; //数据转换成图片 UIImage *img = [UIImage imageWithData:imgData]; //回到主线程设置图片 [self performSelectorOnMainThread:@selector(senderImage:) withObject:img waitUntilDone:NO];}-(void)senderImage:(UIImage *)image{ imagev.image = image;}
- iOS_面试题
- iOS_使用CALayer实现镜面效果
- 面试题....
- 面试题
- 面试题
- 面试题
- 面试题
- 面试题
- 面试题
- 面试题
- 面试题
- 面试题
- 面试题
- 面试题
- 面试题
- 面试题
- 面试题
- 面试题
- CSS -Counter
- Spring-EhCache配置实例
- PHP知识体系思维导图
- C和指针—结构体和联合
- HDU 1170
- iOS_面试题
- IT运维流程 — ITIL
- const理解之二
- 堆栈堆栈
- Glib学习(5) 字符串 Strings
- mysql监控器
- 今天犯了一个非常low的错误❌。关于UINavigationController 和UITabBarController
- Linux内核将要支持最新龙芯3A2000/3B2000
- [未完整]谈js中的作用域链和闭包