面试的信心来源于过硬的基础iOS开发方向
发布时间:2023-03-31 14:17:13 所属栏目:教程 来源:
导读:在过去的一年很多人不满于公司没有福利、人际关系不好相处、没有发展前途的境遇等等,想着在开年来换一份工作来重新开始自己,那么 你 准备好了吗?
下面是本人整理的一份面试材料,本想自己用的,但是新年第一天
下面是本人整理的一份面试材料,本想自己用的,但是新年第一天
|
在过去的一年很多人不满于公司没有福利、人际关系不好相处、没有发展前途的境遇等等,想着在开年来换一份工作来重新开始自己,那么 你 准备好了吗? 下面是本人整理的一份面试材料,本想自己用的,但是新年第一天 公司突然给了我个惊喜,涨工资了!!! UIView和CALayer是什么关系 UIView继承自UIResponder类,可以响应事件 CALayer直接继承自NSObject类,不可以响应事件 UIView是CALayer的delegate(CALayerDelegate) UIView主要处理事件,CALayer负责绘制 每个UIView内部都有一个CALayer在背后提供内容的绘制和显示,并且UIView的尺寸样式都由内部的Layer所提供。两者都有树状层级结构,Layer内部有SubLayers,View内部有SubViews,但是Layer比View多了个AnchorPoint NSCache和NSMutableDictionary的相同点与区别 相同点: NSCache和NSMutableDictionary功能用法基本是相同的 区别: NSCache是线程安全的,NSMutableDictionary线程不安全,Mutable开发的类一般都是线程不安全的 当内存不足时NSCache会自动释放内存(所以从缓存中取数据的时候总要判断是否为空) NSCache可以指定缓存的限额,当缓存超出限额自动释放内存 NSCache的Key只是对对象进行了Strong引用,而非拷贝,所以不需要实现NScopying协议 atomic的实现机制;为什么不能保证绝对的线程安全(最好可以结合场景来说) atomic会对属性的setter/getter方法进行加锁,这仅仅只能保证在操作setter/getter方法是安全的。不能保证其他线程的安全 例如:线程1调用了某一属性的setter方法并进行到了一半,线程2调用其getter方法,那么会执行完setter操作后,再执行getter操作,线程2会获取到线程1setter后的完整的值;当几个线程同时调用同一属性的setter、getter方法时,会获取到一个完整的值,但获取到的值不可控 iOS 中内省的几个方法 对象在运行时获取其类型的能力称为内省。内省可以有多种方法实现 OC运行时内省的4个方法: 判断对象类型: -(BOOL) isKindOfClass: // 判断是否是这个类或者这个类的子类的实例 -(BOOL) isMemberOfClass: // 判断是否是这个类的实例 判断对象/类是否有这个方法 -(BOOL) respondsToSelector: // 判断实例是否有这样方法 +(BOOL) instancesRespondToSelector: // 判断类是否有这个方法 作为一个开发者,有一个学习的氛围跟一个交流圈子特别重要,这是一个我的点击加入群聊iOS交流群:642363427,不管你是小白还是大牛欢迎入驻 ,分享BAT,阿里面试题、面试经验,讨论技术, 大家一起交流学习成长! objc在向一个对象发送消息时,发生了什么 根据对象的isa指针找到该对象所属的类,去objc的对应的类中找方法 1.首先,在相应操作的对象中的缓存方法列表中找调用的方法,如果找到,转向相应实现并执行 2.如果没找到,在相应操作的对象中的方法列表中找调用的方法,如果找到,转向相应实现执行 3.如果没找到,去父类指针所指向的对象中执行1,2. 4.以此类推,如果一直到根类还没找到,转向拦截调用,走消息转发机制 5.如果没有重写拦截调用的方法,程序报错 你是否接触过OC中的反射机制?简单聊一下概念和使用 class反射 通过类名的字符串形式实例化对象 Class class = NSClassFromString(@"student"); Student *stu = [[class alloc] init]; 将类名变为字符串 Class class = [Student class]; Nsstring *className = NsstringFromClass(class); SEL的反射 通过方法的字符串形式实例化方法 SEL selector = NSSelectorFromString(@"setName"); [stu performSelector:selector withObject:@"Mike"]; 将方法变成字符串 NsstringFromSelector(@selector(setName:)); 这个写法会出什么问题@property (nonatomic, copy) NSMutableArray *arr; 添加,删除,修改数组内元素的时候,程序会因为找不到对应的方法而崩溃。原因:是因为copy就是复制一个不可变NSArray的对象,不能对NSArray对象进行添加/修改 如何让自己的类用copy修饰符 若想令自己所写的对象具有拷贝功能,则需实现NScopying协议。如果自定义的对象分为可变版本与不可变版本,那么就要同时实现NScopying与NSMutablecopying协议。 具体步骤: 1.需声明该类遵从NScopying协议 2.实现NScopying协议的方法,具体区别戳这里 NScopying协议方法为: - (id)copyWithZone:(NSZone *)zone { MyObject *copy = [[[self class] allocWithZone: zone] init]; copy.username = self.username; return copy; } 为什么assign不能用于修饰对象 首先我们需要明确,对象的内存一般被分配到堆上,基本数据类型和oc数据类型的内存一般被分配在栈上 如果用assign修饰对象,当对象被释放后,指针的地址还是存在的,也就是说指针并没有被置为nil,从而造成了野指针。因为对象是分配在堆上的,堆上的内存由程序员分配释放。而因为指针没有被置为nil,如果后续的内存分配中,刚好分配到了这块内存,就会造成崩溃 而assign修饰基本数据类型或oc数据类型,因为基本数据类型是分配在栈上的,由系统分配和释放,所以不会造成野指针 请写出以下代码输出 int a[5] = {1, 2, 3, 4, 5}; int *ptr = (int *)(&a + 1); printf("%d, %d", *(a + 1), *(ptr + 1)); 参考答案:2,随机值 分析: a代表有5个元素的数组的首地址,a[5]的元素分别是1,2,3,4,5。接下来,a + 1表示数据首地址加1,那么就是a[1],也就是对应于值为2,但是,这里是&a + 1,因为a代表的是整个数组,它的空间大小为5 * sizeof(int),因此&a + 1就是a + 5。a是个常量指针,指向当前数组的首地址,指针+1就是移动sizeof(int)个字节 因此,ptr是指向int *类型的指针,而ptr指向的就是a + 5,那么ptr + 1也相当于a + 6,所以最后的*(ptr + 1)就是一个随机值了。而*(ptr – 1)就相当于a + 4,对应的值就是5 一个view已经初始化完毕,view上面添加了n个button(可能使用循环创建),除用view的tag之外,还可以采用什么办法来找到自己想要的button来修改Button的值 > 第一种:如果是点击某个按钮后,才会刷新它的值,其它不用修改,那么不用引用任何按钮,直接在回调时,就已经将接收响应的按钮给传过来了,直接通过它修改即可 > 第二种:点击某个按钮后,所有与之同类型的按钮都要修改值,那么可以通过在创建按钮时将按钮存入到数组中,在需要的时候遍历查找 UIViewController的viewDidUnload、viewDidLoad和loadView分别什么时候调用?UIView的drawRect和layoutSubviews分别起什么作用 > 第一个问题: > 在控制器被销毁前会调用`viewDidUnload`(`MRC`下才会调用) > 在控制器没有任何`view`时,会调用`loadView` > 在`view`加载完成时,会调用`viewDidLoad` > 第二个问题: > 在调用`setNeedsdisplay`后,会调用`drawRect`方法,我们通过在此方法中可以获取到`context`(设置上下文),就可以实现绘图 > 在调用`setNeedsLayout`后,会调用`layoutSubviews`方法,我们可以通过在此方法去调整UI。当然能引起`layoutSubviews`调用的方式有很多种的,比如添加子视图、滚动`scrollview`、修改视图的`frame`等 自动释放池工作原理 > 自动释放池是`NSAutorelease`类的一个实例,当向一个对象发送`autorelease`消息时,该对象会自动入池,待池销毁时,将会向池中所有对象发送一条`release`消息,释放对象 > `[pool release]、[pool drain]`表示的是池本身不会销毁,而是池子中的临时对象都被发送`release`,从而将对象销毁 苹果是如何实现autoreleasepool的 > `autoreleasepool`是由`AutoreleasePoolPage`以双向链表的方式实现的,主要通过下列三个函数完成: > > * 由`objc_autoreleasePoolPush`作为自动释放池作用域的第一个函数 > * 使用`objc_autorelease`将对象加入自动释放池 > * 由`objc_autoreleasePoolPop`作为自动释放池作用域的最后一个函数 autorelease的对象何时被释放 RunLoop在每个事件循环结束后会去自动释放池将所有自动释放对象的引用计数减一,若引用计数变成了0,则会将对象真正销毁掉,回收内存。 在没有手动添加Autorelease Pool的情况下,autorelease的对象是在每个事件循环结束后,自动释放池才会对所有自动释放的对象的引用计数减一,若引用计数变成了0,则释放对象,回收内存。因此,若想要早一点释放掉autorelease对象,那么我们可以在对象外加一个自动释放池。比如,在循环处理数据时,临时变量要快速释放,就应该采用这种方式: // 通过alloc创建的对象,直接加入@autoreleasepool没有作用,需在创建对象后面显式添加autorelease // 通过类方法创建的对象不需要显式添加autorelease,原因是类方法创建的对象系统会自动添加autorelease for (int i = 0; i < 1000000; i++) { @autoreleasepool { Nsstring *str = @"Abc"; str = [str lowercaseString]; str = [str stringByAppendingString:@"xyz"]; NSLog(@"%@", str); } // 出了这里,就会去遍历该自动释放池了 } 简述内存管理基本原则 > OC内存管理遵循`谁创建,谁释放,谁引用,谁管理`的机制,当使用`alloc、copy(mutablecopy)或者retian`一个对象时,你就有义务向它发送一条`release或者autorelease`消息释放该对象,其他方法创建的对象,不需要由你来管理内存,当对象引用计数为0时,系统将释放该对象,这是OC的手动管理机制(`MRC`) > 向一个对象发送一条`autorelease`消息,这个对象并不会立即销毁,而是将这个对象放入了自动释放池,待池子释放时,它会向池中每一个对象发送一条`release`消息,以此来释放对象 > 向一个对象发送`release`消息,并不意味着这个对象被销毁了,而是当这个对象的引用计数为0时,系统才会调用`dealloc`方法释放该对象和对象本身所拥有的实例 sizeof关键字 > `sizeof`是在编译阶段处理,且不能被编译为机器码。`sizeof`的结果等于对象或类型所占的内存字节数。`sizeof`的返回值类型为`size_t` > 变量:`int a; sizeof(a)`为4; > 指针:`int *p; sizeof(p)`为4; > 数组:`int b[10]; sizeof(b)`为数组的大小4*10;`int c[0]; sizeof(c)`等于0 > `sizeof(void)`等于1 > `sizeof(void *)`等于4 (编辑:汽车网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
推荐文章
站长推荐
