文章目录

2020年IOS面试题总结(二)

1.统计一个字符数组中每个字符出现的次数?

2.实现一个反转二叉树;

3.如何获取VC上所有的Button?

4.排序算法有哪些?(答案待完善)

5.self和super区别;

6.UIViewController的生命周期;

7.UIButton的继承链,如何改变它的点击区域;

8.Category

9.实现setter方法

10.iOS判断一个字符串中是否都是数字

11.如何合并两个有序数组?

12.GET和POST区别

13.面向对象编程的六大原则

14.ios Animation

15.为什么必须在主线程中操作UI

16.显式和隐式动画的区别

17.OC内联函数 inline

原文地址:2020年iOS大厂面试题总结(一)

原文链接:https://www.jianshu.com/p/89978870f49f

1.统计一个字符数组中每个字符出现的次数?

  1. void main()
  2. {
  3. char str[20];
  4. int i,num[256]={0};
  5. printf("please input string:");
  6. scanf("%s",str);
  7. for(i=0;i<strlen(str);i++)
  8. num[(int)str[i]]++;
  9. for(i=0;i<256;i++)
  10. if(num[i]!=0)
  11. printf("字符%c出现%d次\n",(char)i,num[i]);
  12. }

2.实现一个反转二叉树;
  1. @interface TreeNode : NSObject
  2. @property (nonatomic, assign) NSInteger val;
  3. @property (nonatomic, strong) TreeNode *left;
  4. @property (nonatomic, strong) TreeNode *right;
  5. @end
  6. - (void)exchangeNode:(TreeNode *)node {
  7. //判断是否存在node节点
  8. if(node) {
  9. //交换左右节点
  10. TreeNode *temp = node.left;
  11. node.left = node.right;
  12. node.right = temp;
  13. }
  14. }
  15. - (TreeNode *)invertTree:(TreeNode *)root
  16. {
  17. //边界条件 递归结束或输入为空情况
  18. if(!root) {
  19. return root;
  20. }
  21. //递归左右子树
  22. [self invertTree:root.left];
  23. [self invertTree:root.right];
  24. //交换左右子节点
  25. [self exchangeNode:root];
  26. return root;
  27. }

3.如何获取VC上所有的Button?

递归

4.排序算法有哪些?(答案待完善)

冒泡、快速、插入、选择、希尔、堆等等

5.self和super区别;

self调用自己方法,super调用父类方法 self是类,super是预编译指令 【self class】和【super class】输出是一样的

1.当使用 self 调用方法时,会从当前类的方法列表中开始找,如果没有,就从父类中再找;而当使用 super 时,则从父类的方法列表中开始找,然后调用父类的这个方法。
2.当使用 self 调用时,会使用 objc_msgSend 函数: id objc_msgSend(id theReceiver, SEL theSelector, …)。第 一个参数是消息接收者,第二个参数是调用的具体类方法的 selector,后面是 selector 方法的可变参数。以 [self setName:] 为例,编译器会替换成调用 objc_msgSend 的函数调用,其中 theReceiver 是 self,theSelector 是 @selector(setName:),这个 selector 是从当前 self 的 class 的方法列表开始找的 setName,当找到后把对应的 selector 传递过去。
3.当使用 super 调用时,会使用 objc_msgSendSuper 函数:id objc_msgSendSuper(struct objc_super

  1. struct objc_super {
  2. id receiver;
  3. Class superClass;
  4. };

当编译器遇到 [super setName:] 时,开始做这几个事: 1)构 建 objc_super 的结构体,此时这个结构体的第一个成员变量 receiver 就是 子类,和 self 相同。而第二个成员变量 superClass 就是指父类 调用 objc_msgSendSuper 的方法,将这个结构体和 setName 的 sel 传递过去。 2)函数里面在做的事情类似这样:从 objc_super 结构体指向的 superClass 的方法列表开始找 setName 的 selector,找到后再以 objc_super->receiver 去调用这个 selector **

作为一个开发者,有一个学习的氛围跟一个交流圈子特别重要,这是一个我的点击加入群聊iOS交流群:789143298 ,不管你是小白还是大牛欢迎入驻 ,分享BAT,阿里面试题、面试经验,讨论技术,大家一起交流
学习成长!

2020年iOS大厂面试题总结(二) - 图1

6.UIViewController的生命周期;

initWithCoder; awakeFromNib; loadView; viewDidLoad; viewWillAppear; viewWillLayoutSubviews; viewDidLayoutSubviews; viewDidAppear; viewWillDisappear; viewDidDisappear; dealloc; didReceiveMemoryWarning

7.UIButton的继承链,如何改变它的点击区域;

UIButton > UIControl > UIView > UIResponder > NSObject

  1. - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent*)event
  2. {
  3. CGRect bounds = self.bounds;
  4. CGFloat width = MAX(100 - bounds.size.width, 0);
  5. CGFloat height = MAX(100 - bounds.size.height, 0);
  6. bounds = CGRectInset(bounds, -width/2, -height/2);
  7. return CGRectContainsPoint(bounds, point);
  8. }

8.Category

Build Phases ->Complie Source 中的编译顺序 1.属性。Property 2.实例变量。Ivar(属性是给成员变量默认添加了setter和getter方法。tips:如果不用@dynamic修饰的话。) 3.isa指针。在Objective-C中,任何类的定义都是对象。类和类的实例(对象)没有任何本质上的区别。任何对象都有isa指针。但是分类没有。 category 它是在运行期决议的。 因为在运行期即编译完成后,对象的内存布局已经确定,如果添加实例变量就会破坏类的内部布局,这对编译型语言来说是灾难性的。 使用Runtime技术中的关联对象可以为类别添加属性。 其原因是:关联对象都由AssociationsManager管理,AssociationsManager里面是由一个静态AssociationsHashMap来存储所有的关联对象的。这相当于把所有对象的关联对象都存在一个全局map里面。而map的的key是这个对象的指针地址(任意两个不同对象的指针地址一定是不同的),而这个map的value又是另外一个AssociationsHashMap,里面保存了关联对象的kv对。 如合清理关联对象? runtime的销毁对象函数objc_destructInstance里面会判断这个对象有没有关联对象,如果有,会调用_object_remove_assocations做关联对象的清理工作。(详见Runtime的源码) extension在编译期决议;extension可以添加实例变量,而category是无法添加实例变量的(因为在运行期,对象的内存布局已经确定,如果添加实例变量就会破坏类的内部布局,这对编译型语言来说是灾难性的)

9.实现setter方法

  1. -(void)setName:(NSString *)name{
  2. if (_name != name) {
  3. [_name release];
  4. _name = [name copy];
  5. }
  6. }

10.iOS判断一个字符串中是否都是数字

  1. 第一种方式是使用NSScanner
  2. 1. 整形判断
  3. - (BOOL)isPureInt:(NSString *)string{
  4. NSScanner* scan = [NSScanner scannerWithString:string];
  5. int val;
  6. return [scan scanInt:&val] && [scan isAtEnd];
  7. }
  8. 2.浮点形判断:
  9. - (BOOL)isPureFloat:(NSString *)string{
  10. NSScanner* scan = [NSScanner scannerWithString:string];
  11. float val;
  12. return [scan scanFloat:&val] && [scan isAtEnd];
  13. }
  14. 第二种方式是使用循环判断
  15. - (BOOL)isPureNumandCharacters:(NSString *)text
  16. {
  17. for(int i = 0; i < [text length]; ++i) {
  18. int a = [text characterAtIndex:i];
  19. if ([self isNum:a]){
  20. continue;
  21. } else {
  22. return NO;
  23. }
  24. }
  25. return YES;
  26. }
  27. 或者 C语言中常用的方式.
  28. - (BOOL)isAllNum:(NSString *)string{
  29. unichar c;
  30. for (int i=0; i<string.length; i++) {
  31. c=[string characterAtIndex:i];
  32. if (!isdigit(c)) {
  33. return NO;
  34. }
  35. }
  36. return YES;
  37. }
  38. 第三种方式则是使用NSStringtrimming方法
  39. - (BOOL)isPureNumandCharacters:(NSString *)string
  40. {
  41. string = [string stringByTrimmingCharactersInSet;[NSCharacterSet decimalDigitCharacterSet]];
  42. if(string.length > 0)
  43. {
  44. return NO;
  45. }
  46. return YES;
  47. }

11.如何合并两个有序数组?

比较相邻的两个元素,类似冒泡排序;

  1. NSMutableArray *A = [NSMutableArray arrayWithObjects:@4,@5,@8,@10,@15, nil];
  2. NSMutableArray *B = [NSMutableArray arrayWithObjects:@2,@6,@7,@9,@11,@12,@13, nil];
  3. NSMutableArray *C = [NSMutableArray array];
  4. int count = (int)A.count+(int)B.count;
  5. int index = 0;
  6. for (int i = 0; i < count; i++) {
  7. if (A[0]<B[0]) {
  8. [C addObject:A[0]];
  9. [A removeObject:A[0]];
  10. }
  11. else if (B[0]<A[0]) {
  12. [C addObject:B[0]];
  13. [B removeObject:B[0]];
  14. }
  15. if (A.count==0) {
  16. [C addObjectsFromArray:B];
  17. index = i+1;
  18. return;
  19. }
  20. else if (B.count==0) {
  21. [C addObjectsFromArray:A];
  22. index = i+1;
  23. return;
  24. }
  25. }
  26. //(2).
  27. //时间复杂度
  28. //T(n) = O(f(n)):用"T(n)"表示,"O"为数学符号,f(n)为同数量级,一般是算法中频度最大的语句频度。
  29. //时间复杂度:T(n) = O(index);

12.GET和POST区别

tcp在传输层,IP在网络层,http在应用层。。。。 GET产生一个TCP数据包;POST产生两个TCP数据包(对于GET方式的请求,浏览器会把http header和data一并发送出去,服务器响应200(返回数据); 而对于POST,浏览器先发送header,服务器响应100 continue,浏览器再发送data,服务器响应200 ok(返回数据),)。。。 GET请求在URL中传送的参数是有长度限制的,而POST没有。 GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息。 GET参数通过URL传递,POST放在Request body中。 GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留。 GET请求只能进行url编码,而POST支持多种编码方式。 GET请求会被浏览器主动cache,而POST不会,除非手动设置。 GET产生的URL地址可以被Bookmark,而POST不可以。 GET在浏览器回退时是无害的,而POST会再次提交请求。

13.面向对象编程的六大原则

1.单一职责:

不要存在多于一个导致类变更的原因。通俗的说,即一个类只负责一项职责。

2.里氏替换原则:

所有引用基类的地方必须能透明地使用其子类的对象,也就是说子类可以扩展父类的功能,但不能改变父类原有的功能

3.依赖倒置:

高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。简单的说就是尽量面向接口编程.

4.接口隔离:

客户端不应该依赖它不需要的接口;一个类对另一个类的依赖应该建立在最小的接口上。接口最小化,过于臃肿的接口依据功能,可以将其拆分为多个接口.

5.迪米特法则:

一个对象应该对其他对象保持最少的了解,简单的理解就是高内聚,低耦合,一个类尽量减少对其他对象的依赖,并且这个类的方法和属性能用私有的就尽量私有化.

6.开闭原则:

一个软件实体如类、模块和函数应该对扩展开放,对修改关闭.当软件需求变化时,尽量通过扩展软件实体的行为来实现变化,而不是通过修改已有的代码来实现变化.

14.ios Animation

Core Animation

CAAnimation作为虚基类实现了CAMediaTiming协议(其实还实现了CAAction协议)。CAAnimation有三个子类CAAnimationGroup(组动画)、CAPropertyAnimation(属性动画)、CATrasition(渐变动画)。CAAnimation不能直接使用,应该使用它的子类。作为CAPropertyAnimation也有两个子类CABasicAnimation(基础动画)、CAKeyFrameAnimation(关键帧动画)。CAPropertyAnimation也不能直接使用,应该使用两个子类。综上所诉要使用核心动画,可以使用的就是以下四个类(CAAnimationGroup、CATrasition、CABasicAnimation、CAKeyFrameAnimation)。

  1. 1.CABasicAnimation简单使用
  2. - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
  3. {
  4. UITouch *touch = [touches anyObject];
  5. CGPoint point = [touch locationInView:self.view];
  6. CABasicAnimation *positionAnimation = [CABasicAnimation animationWithKeyPath:@"position"];
  7. positionAnimation.fromValue = [NSValue valueWithCGPoint:self.testLayer.presentationLayer.position];
  8. positionAnimation.toValue = [NSValue valueWithCGPoint:point];
  9. positionAnimation.duration = 1.f;//动画时长
  10. positionAnimation.removedOnCompletion = NO;//是否在完成时移除
  11. positionAnimation.fillMode = kCAFillModeForwards;//动画结束后是否保持状态
  12. [self.testLayer addAnimation:positionAnimation forKey:@"positionAnimation"];
  13. }
  14. 2. CATransition(过渡动画)
  15. CATransition *transition = [CATransition animation];
  16. transition.startProgress = 0;//开始进度
  17. transition.endProgress = 1;//结束进度
  18. transition.type = kCATransitionReveal;//过渡类型
  19. transition.subtype = kCATransitionFromLeft;//过渡方向
  20. transition.duration = 1.f;
  21. UIColor *color = [UIColor colorWithRed:arc4random_uniform(255) / 255.0 green:arc4random_uniform(255) / 255.0 blue:arc4random_uniform(255) / 255.0 alpha:1.f];
  22. self.testLayer.backgroundColor = color.CGColor;
  23. [self.testLayer addAnimation:transition forKey:@"transition"];
  24. 3.CAKeyFrameAnimation关键帧动画
  25. CAKeyframeAnimation *moveAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
  26. moveAnimation.path = bezirePath;
  27. moveAnimation.fillMode = kCAFillModeForwards;
  28. moveAnimation.removedOnCompletion = NO;
  29. moveAnimation.duration = 3.f;
  30. 4.AnimationGroup(组动画)
  31. CAAnimationGroup *groupAnimation = [[CAAnimationGroup alloc] init];
  32. groupAnimation.animations = @[xScaleAnimation, yScaleAnimation];//将所有动画添加到动画组

15.为什么必须在主线程中操作UI

因为UIKit不是线程安全的。试想下面这几种情况: 两个线程同时设置同一个背景图片,那么很有可能因为当前图片被释放了两次而导致应用崩溃。 两个线程同时设置同一个UIView的背景颜色,那么很有可能渲染显示的是颜色A,而此时在UIView逻辑树上的背景颜色属性为B。 两个线程同时操作view的树形结构:在线程A中for循环遍历并操作当前View的所有subView,然后此时线程B中将某个subView直接删除,这就导致了错乱还可能导致应用崩溃。iOS4之后苹果将大部分绘图的方法和诸如 UIColor 和 UIFont 这样的类改写为了线程安全可用,但是仍然强烈建议讲UI操作保证在主线程中执行。

16.显式和隐式动画的区别

1、隐式动画一直存在 如需关闭需设置;显式动画是不存在,如需显式 要开启(创建)。 2、显式动画是指用户自己通过beginAnimations:context:和commitAnimations创建的动画。 隐式动画是指通过UIView的animateWithDuration:animations:方法创建的动画。 3.一种为UIView动画,又称隐式动画,动画后frame的数值发生了变化.另一种是CALayer动画,又称显示动画,UIView(隐式动画)可以相应用户交互。

17.OC内联函数 inline

优点相比于函数: 1.inline函数避免了普通函数的,在汇编时必须调用call的缺点:取消了函数的参数压栈,减少了调用的开销,提高效率.所以执行速度确比一般函数的执行速度要快. 2)集成了宏的优点,使用时直接用代码替换(像宏一样); 优点相比于宏: 1.避免了宏的缺点:需要预编译.因为inline内联函数也是函数,不需要预编译. 2)编译器在调用一个内联函数时,会首先检查它的参数的类型,保证调用正确。然后进行一系列的相关检查,就像对待任何一个真正的函数一样。这样就消除了它的隐患和局限性。 3)可以使用所在类的保护成员及私有成员。 inline内联函数的说明 1.内联函数只是我们向编译器提供的申请,编译器不一定采取inline形式调用函数. 2.内联函数不能承载大量的代码.如果内联函数的函数体过大,编译器会自动放弃内联. 3.内联函数内不允许使用循环语句或开关语句. 4.内联函数的定义须在调用之前.

  1. //数组添加非空对象
  2. static inline void photoComponentSafeAddObject(NSMutableArray *array, id object) {
  3. if (array && object) {
  4. [array addObject:object];
  5. }
  6. }
  7. static inline CGSize liteVideoImageSizeScaleWithSize(CGSize scaleSize, CGSize pixelSize) {
  8. CGFloat width = pixelSize.width;
  9. CGFloat height = pixelSize.height;
  10. float verticalRadio = scaleSize.height*1.0/height;
  11. float horizontalRadio = scaleSize.width*1.0/width;
  12. float radio = 1;
  13. if (verticalRadio < 1 || horizontalRadio < 1) {
  14. radio = verticalRadio < horizontalRadio ? verticalRadio : horizontalRadio;
  15. }
  16. width = width*radio;
  17. height = height*radio;
  18. // 返回新的改变大小后的size
  19. return CGSizeMake(width, height);
  20. }

👇推荐👇:

大家可以加入iOS技术交流群,群号:789143298 群内提供数据结构与算法、底层进阶、swift、逆向、底层面试题整合文档等免费资料!!!

2020年iOS大厂面试题总结(二) - 图2

版权声明:本文为「波波9005」的原创文章,

原文链接:https://blog.csdn.net/weixin_43547696/article/details/87284256