iOS面试iOS面试

转载:来来来!关于iOS基础总结咱俩好好唠唠

2018-03-16  本文已影响196人  yahoouchen

尘封已久的学习基础总结,最近公司项目不是很忙,终于抽空整理出来,现分享出来。

1.1 谈一谈GCD和NSOperation的区别?

1.2 谈谈多线程的应用

通常耗时的操作都放在子线程处理,然后到主线程更新UI,如

2. 线程之间是如何通信的?

3. 网络图片处理问题怎么解决图片重复下载问题?(SDWebImage大概实现原理)

4. 多线程安全的几种解决方法?

5. 原子属性

6. 代理的作用、block

7. 谈谈你对runTime运行时机制的了解(注意哦,这个很重要的)

8. 谈谈你对Run Loop的理解

如何处理事件

应用

9. SQLite常用的SQL语句

10. 关于Socket,谈谈TCP/IP 和 UDP的理解

11. 谈一谈内存管理

12. 常见的数据持久化有哪些

//1.获得NSUserDefaults文件
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
//2.向文件中写入内容
[userDefaults setObject:@"AAA" forKey:@"a"];
[userDefaults setBool:YES forKey:@"sex"];
[userDefaults setInteger:21 forKey:@"age"];
//2.1立即同步
[userDefaults synchronize];
//3.读取文件
NSString *name = [userDefaults objectForKey:@"a"];
BOOL sex = [userDefaults boolForKey:@"sex"];
NSInteger age = [userDefaults integerForKey:@"age"];
NSLog(@"%@, %d, %ld", name, sex, age);

// 反归档
  - (id)initWithCoder:(NSCoder *)aDecoder {
      if ([super init]) {
          self.avatar = [aDecoder decodeObjectForKey:@"avatar"];
          self.name = [aDecoder decodeObjectForKey:@"name"];
          self.age = [aDecoder decodeIntegerForKey:@"age"];
      }
      return self;
  }
  // 归档
  - (void)encodeWithCoder:(NSCoder *)aCoder {
      [aCoder encodeObject:self.avatar forKey:@"avatar"];
      [aCoder encodeObject:self.name forKey:@"name"];
      [aCoder encodeInteger:self.age forKey:@"age"];
  }

* 归档,把对象归档时需要调用NSKeyedArchiver的工厂方法archiveRootObject: toFile: 方法

NSString *file = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject stringByAppendingPathComponent:@"person.data"];
  Person *person = [[Person alloc] init];
  person.avatar = self.avatarView.image;
  person.name = self.nameField.text;
  person.age = [self.ageField.text integerValue];
  [NSKeyedArchiver archiveRootObject:person toFile:file];

* 反归档

NSString *file = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject stringByAppendingPathComponent:@"person.data"];
  Person *person = [NSKeyedUnarchiver unarchiveObjectWithFile:file];
  if (person) {
     self.avatarView.image = person.avatar;
     self.nameField.text = person.name;
     self.ageField.text = [NSString stringWithFormat:@"%ld", person.age];
  }

这五种持久化操作不同点

13. KVC 和 KVO

[self.person addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];

* 当person的name的值发生改变时,就会执行该方法

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context
{
  do something....
}

14. @synthesize和@dynamic区别是什么

15. 谈谈时间响应链的一般顺序

16.1 post和get方式的区别

16.2 POST和PUT区别

17. 深复制和浅复制

18. 关于项目中动画的使用

19. 谈谈你对MVVM的认识

其实MVVM这货有点被神化了,好吧,其实我项目中也没用到过,只是写过稍大点的demo

struct AccountViewModel {
    let dispalyBalance: String

    init(mode: cardAccount) {
        let formattedBalance = model.balance.currencyValue;
        displayBalance = "Your balance is \(formatterBalance)"
    }
}

* 通过这种方式,视图模型实际上会读取数据模型,然后将其中的信息进行格式化,从而准备展现在视图当中,很容易测试,直接把带有账户信息的模型放进去,然后测试显示就可以了,在之前是特别复杂的

var viewModel = ViewModel(model: Account)

20.0 关于Swift与OC的不同

其实是个面试官八个不懂Swift,而且一般不懂得就问个Swift与OC的不同。。题主也只是在自学Swift,等到3.0出了之后再深入研究,而且项目中可能也要开始从混编逐渐向Swift靠拢了。

protocol SwitchWithTextCellProtocol {
    var title: String { get }
    var titleFont: UIFont { get }
    var titleColor: UIColor { get }

    var switchOn: Bool { get }
    var switchColor: UIColor { get }

    func onSwitchTogglenOn(onL Bool)
}

// 这个方法只需要一个参数,相比于之前的多个参数简便了很多
class SwitchWithTextTableViewCell: UITableViewCell {
    func configure(withDelegate delagate: SwitchWithTextCellProtocol) {
        // 在这里配置方法
    }
}

struct MinionModeViewController: SwitchWithTextCellProtocol {
    var title = "excellent!!"
    var switchOn = true

    var switchColor: UIColor {
        return .yellowColor()
    }

    func onSwitchToggleOn(on: Bool) {
        if on {
            print("The Minions are here to stay!")
        } else {
            print("The Minions went out to play!")
        }
    }
}

let cell = tableView.dequeueReuseableCellWithIdentifier("SwitchWithTextTableViewCell", forIndexPath: indexPath) as! SwitchWithTextTableViewCell

cell.configure(withDelegate: MinionModeViewModel())

return cell

再把模型放在视图模型层级,一遍对其进行跟踪,再视图模型中传递这些信息,这样单元格就可以生成了

protocol SwitchWithTextCellDataSource {
    var title: String { get }
    var switchOn: Bool { get }
}

protocol SwitchWithTextCellDelegate {
    func onSwitchTogglenOn(on: Bool)

    var switchColor: UIColor { get }
    var textColor: UIColor { get }
    var font: UIFont { get }
}

// SwitchWithTextTableViewCell
func configure(withDataSource dataSource: SwitchWithTextCellDataSource, delegate: SwitchWithTextCellDelegate?) {
    // 在这里配置视图
}

struct MinionModeViewModel: SwiftWithTextCellDataSource {
    var title = "Minion Mode!!"
    var switchOn = true
}

extension MinionModeViewModel: SwitchWithTextCellDelegate {

    var switchColor: UIColor {
        return .yellowColor()
    }

    func onSwitchToggleOn(on: Bool) {
        if on {
            print("The Minions are here to stay!")
        } else {
            print("The Minions went out to play!")
        }
    }
}

// SettingViewController
let viewModel = MinionModeViewModel()
cell.configure(withDataSource:viewModel, delegate: viewModel)

return cell

仅仅需要创建视图模型,然后将其传递到配置方法当中,最后返回单元格,就可以了

20.1 Swift2.0中的 Minxin 和 Trait

// 一看这个对象的类型,就知道他有哪些功能,而不是一个个去查找她的实现
class ZapMonster: GameObject, GunTraint, HealthTraint, MovementTraint {
    ...
}

protocol TextPresentable {
    var text: String { get }
    var textColor: UIColor { get }
    var font: UIFont { get }
}

protocol SwitchPresentable {
    var switchOn: Bool { get }
    var switchColor: UIColor { get }

    func onSwitchToggleOn(on: Bool)
}

这种情况下,比如需要一个图片框,只要一个iamgeProtocol就可以了,设计师要求改所有标签的颜色的话一行代码就可以搞定

class SwitchWithTextTableViewCell<T where T: TextPresentable, T: SwitchPresentable>: UITableViewCell {
    private var delegate: T?

    // T是视图模型
    func configure(withDelegate delegate: T) {
        // 在这里配置视图
    }
}

在这种情况下,它没有实现这些协议,但是会期待某种实现这些协议的东西传递进去,因此我们使用了泛型,这个单元格期待了一个实现了TextPresentableProtocol 的委托。就我们而言,传递进去的将是一个实现了这些协议的东西就可以了,现在要基于这些信息在单元格当中配置所有的东西了,现在就可以基于浙西而信息在单元格中配置所有的东西了

extension MinionModeViewModel: TextPresentable {
    var text: String { return "Minion Mode" }
    var textColor: UIColor { return .blackColor() }
    var font: UIFont { return .systemFontOfsize(17.0) }
}

20.2 Swift2.2随着iOS9.3一同登场,讲讲什么新调整?

21. 优化tableViewCell高度

22. 列举一下你常用的第三方库

23. 为什么AFN显示图片不如SDWebImage流畅?同样是从网络上下载图片而不是从缓存取图片?

24. 关于新特性

iOS7新特性

iOS8新特性

iOS9新特性

25. 我是怎样用两个imageView实现了无线轮播!

  1. 建立一个scrollView,设置contentsize为3*kWidth,contentOffSet为kWidth
  2. 接下来使用代理方法scrollViewDidScroll来监听scrollview的滚动,定义一个枚举变量来记录滚动的方向
  3. 使用KVO来监听direction属性值的改变-->[self addObserver:self forKeyPath:@"direction" options:NSKeyValueObservingOptionNew context:nil];
  4. 通过observeValueForKeyPath判断滚动的方向,当偏移量大于x,表示左移,则将otherImageView加在右边,偏移量小于x,表示右移,则将otherImageView加在左边。同时判断设置对应的索引,图片
  5. 通过代理方法scrollViewDidEndDecelerating来监听滚动结束,结束后,scrollview的偏移量为0或者2x,我们通过代码再次将scrollview的偏移量设置为x,并将currImageView的图片修改为otherImageView的图片,那么我们看到的还是currImageView,只不过展示的是下一张图片,如图,又变成了最初的效果
  6. ,然后设置自动轮播,添加计时器,利用setContentOffset方法里面setContentOffset:animated:方法执行完毕后不会调用scrollview的scrollViewDidEndDecelerating方法,但是会调用scrollViewDidEndScrollingAnimation方法,因此我们要在该方法中调用pauseScroll(即监听减速结束后由otherImageView切换到currImageView的方法)
  7. 添加计时器:self.timer = [NSTimer timerWithTimeInterval:self.time target:self selector:@selector(nextPage) userInfo:nil repeats:YES];
  8. 在scrollViewWillBeginDragging中停止计时器
  9. 在scrollViewDidEndDragging中开启计时器
  10. 判断外界传入的是图片还是路径,如果是图片,直接加入图片数组中,如果是路径,先添加一个占位图片,然后根据路径去下载图片
  11. 监听图片被点击
*   定义一个block属性暴露给外界void(^imageClickBlock)(NSInteger index) (不会block的可以用代理,或者看这里)
*   设置currImageView的userInteractionEnabled为YES
*   给currImageView添加一个点击的手势
*   在手势方法里调用block,并传入图片索引
  1. NSTimer的两种形式
*   scheduledTimerWithTimeInterval 是创建一个定时器,并加入到当前运行循环[NSRunLoop currentRunLoop]中
*   其他两个([NSTimer timerWithTimeInterval:3 target:self selector:@selector(doSomeThing1) userInfo:nil repeats:YES]; [[NSTimer alloc] initWithFireDate:[NSDate dateWithTimeIntervalSinceNow:5] interval:3 target:self selector:@selector(doSomeThing2) userInfo:nil repeats:YES];)只是创建定时器,并未添加到当前运行循环中,所以如果是其他两种方式创建的定时器则需要手动添加到currentRunLoop中

26. tableView的优化

iOS平台因为UIKit本身的特性,需要将所有的UI操作都放在主线程执行,所以有时候就习惯将一些线程安全性不确定的逻辑,以及它线程结束后的汇总工作等等放到了主线程,所以主线程包含大量计算、IO、绘制都有可能造成卡顿。

  1. 设置正确的 reuseidentifer 以重用 cell

  2. 尽量将 View 设置为不透明,包括 cell 本身(backgroundcolor默认是透明的),图层混合靠GPU去渲染,如果透明度设置为100%,那么GPU就会忽略下面所有的layer,节约了很多不必要的运算。模拟器上点击“Debug”菜单,然后选择“color Blended Layers”,会把所有区域分成绿色和红色,绿色的好,红色的性能差(经过混合渲染的),当然也有一些图片虽然是不透明的,但是也会显示红色,如果检查代码没错的话,一般就是图片自身的性质问题了,直接联系美工或后台解决就好了。除非必须要用GPU加载的,其他最好要用CPU加载,因为CPU一般不会百分百加载,可以通过CoreGraphics画出圆角

  3. 有时候美工失误,图片大小给错了,引起不必要的图片缩放(可以找美工去改,当然也可以异步去裁剪图片然后缓存下来),还是使用Instrument的Color Misaligned Images,黄色表示图片需要缩放,紫色表示没有像素对齐。当然一般情况下图片格式不会给错,有些图片格式是GPU不支持的,就还要劳烦CPU去进行格式转换。还有可以通过Color Offscreen-Rendered Yellow来检测离屏渲染(就是把渲染结果临时保存,等到用的时候再取出,这样相对于普通渲染更消耗内存,使用maskToBounds、设置shadow,重写drawRect方法都会导致离屏渲染) 避免渐变,cornerRadius在默认情况下,这个属性只会影响视图的背景颜色和 border,但是不会离屏绘制,不影响性能。不用clipsToBounds(过多调用GPU去离屏渲染),而是让后台加载图片并处理圆角,并将处理过的图片赋值给UIImageView。UIImageView 的圆角通过直接截取图片实现,圆角路径直接用贝塞尔曲线UIBezierPath绘制(人为指定路径之后就不会触发离屏渲染),UIGraphicsBeginImageContextWithOptions。UIView的圆角可以使用CoreGraphics画出圆角矩形,核心是CGContextAddArcToPoint 函数。它中间的四个参数表示曲线的起点和终点坐标,最后一个参数表示半径。调用了四次函数后,就可以画出圆角矩形。最后再从当前的绘图上下文中获取图片并返回,最后把这个图片插入到视图层级的底部。 “Flash updated Regions”用于标记发生重绘的区域

  4. 如果 row 的高度不相同,那么将其缓存下来

  5. 如果 cell 显示的内容来自网络,那么确保这些内容是通过异步下载

  6. 使用 shadowPath 来设置阴影,图层最好不要使用阴影,阴影会导致离屏渲染(在进入屏幕渲染之前,还看不到的时候会再渲染一次,尽量不要产生离屏渲染)

  7. 减少 subview 的数量,不要去添加或移除view,要就显示,不要就隐藏

  8. 在 cellForRowAtIndexPath 中尽量做更少的操作,最好是在别的地方算好,这个方法里只做数据的显示,如果需要做一些处理,那么最好做一次之后将结果储存起来.

  9. 使用适当的数据结构来保存需要的信息,不同的结构会带来不同的操作代价

  10. 使用,rowHeight , sectionFooterHeight 和 sectionHeaderHeight 来设置一个恒定高度 , 而不是从代理(delegate)中获取

  11. cell做数据绑定的时候,最好在willDisPlayCell里面进行,其他操作在cellForRowAtIndexPath,因为前者是第一页有多少条就执行多少次,后者是第一次加载有多少个cell就执行多少次,而且调用后者的时候cell还没显示

  12. 读取文件,写入文件,最好是放到子线程,或先读取好,在让tableView去显示

  13. tableView滚动的时候,不要去做动画(微信的聊天界面做的就很好,在滚动的时候,动态图就不让他动,滚动停止的时候才动,不然可能会有点影响流畅度)。在滚动的时候加载图片,停止拖拽后在减速过程中不加载图片,减速停止后加载可见范围内图片

27. 谈谈内存的优化和注意事项(使用Instrument工具的CoreAnimation、GPU Driver、I/O操作,检查fps数值)

原文出自转载:https://juejin.im/post/5a31e394f265da4310486479

上一篇下一篇

猜你喜欢

热点阅读