iOS面试题(一)
第一次电话面试
按照顺序打印 1 到 100 不少于一个线程
//全局变量
var lock = os_unfair_lock()
DispatchQueue.global().async {
self.action()
}
DispatchQueue.global().async {
self.action()
}
//具体打印
func action(){
while true {
os_unfair_lock_lock(&lock)
if num >= 100{
os_unfair_lock_unlock(&lock)
return
}
num += 1
print("\(num)----\(Thread.current)")
os_unfair_lock_unlock(&lock)
}
}
全局并发队列打印1 到 10000 最终结果
- 会少于 10000 因为会同时拿到 num 值 进行加一
MVVM view 和 viewmodel 和 model 的关系
- viewModel持有 model view 持有 viewModel 使 view 和 model 实现双向绑定
不用 RAC 怎么实现 MVVM
- 利用 KVO 实现双向绑定
UIView.animate.during 监听 alpha 0 到 1的变化
let normalView = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
normalView.backgroundColor = UIColor.red
normalView.alpha = 0
view.addSubview(normalView)
let timer = Timer.scheduledTimer(withTimeInterval: 0.01, repeats: true) { (time) in
let layer = normalView.layer.presentation()
print(layer?.opacity)
}
RunLoop.current.add(timer, forMode: RunLoopMode.commonModes)
UIView.animate(withDuration: 2) {
normalView.alpha = 1
}
setNeedlayout layouSubViews等
- layouSubViews的调用时机
- init初始化不会触发layoutSubviews。
- addSubview会触发layoutSubviews(前面 init 如果设置 frame 的话会调用两次,如果没有 设置frame 就调用一次)
- 设置view的Frame会触发layoutSubviews,(当然前提是frame的值设置前后发生了变化。单单设置 x 值的变化是不会调的,但设置 y 值是会变的,奇怪)
- 滚动一个UIScrollView会触发layoutSubviews。
- 旋转屏幕会触发父UIView上的layoutSubviews事件。(这个我们开发中会经常遇到,比如屏幕旋转时,为了界面美观我们需要修改子view的frame,那就会在layoutSubview中做相应的操作)
- 改变一个UIView大小的时候也会触发父UIView上的layoutSubviews事件
- 直接调用setLayoutSubviews。(Apple是不建议这么做的)
- drawRect调用时机
-
如果在UIView初始化时没有设置rect大小,将直接导致drawRect不被自动调用。drawRect 掉用是在Controller->loadView, Controller->viewDidLoad 两方法之后掉用的.所以不用担心在 控制器中,这些View的drawRect就开始画了.这样可以在控制器中设置一些值给View(如果这些View draw的时候需要用到某些变量值).
-
该方法在调用sizeToFit后被调用,所以可以先调用sizeToFit计算出size。然后系统自动调用drawRect:方法。
-
通过设置contentMode属性值为UIViewContentModeRedraw。那么将在每次设置或更改frame的时候自动调用drawRect:。
-
直接调用setNeedsDisplay,或者setNeedsDisplayInRect:触发drawRect:,但是有个前提条件是rect不能为0。
-
组件化间传值 组件化方案优劣
- 传值总的来说 前向传值就是直接传,反向传值用 block 等
- MGJRouter
//MGJRouter //前向 [MGJRouter openURL:@"MGJ://Test2/PushMainVC" withUserInfo:@{@"navigationVC":self.navigationController,@"text":@"前向传值"} completion:nil]; //反向 [MGJRouter openURL:@"MGJ://Test3/PushMainVC" withUserInfo:@{@"navigationVC":self.navigationController, @"block":^(NSString *text){ NSLog(@"%@",text); }} completion:nil];
- CTMediator
@objc public func A_showSwift(param:[AnyHashable:Any], callback:@escaping (String) -> Void) -> UIViewController? { var params = param//前向 params["callback"] = callback//反向 params[kCTMediatorParamsKeySwiftTargetModuleName] = "DYLCWithDrawKit" if let viewController = self.performTarget("DYLCWithDrawKit", action: "Extension_ViewController", params: params, shouldCacheTarget: false) as? UIViewController { return viewController } return nil } @objc func Action_Extension_ViewController(_ params:NSDictionary) -> UIViewController { let num = params["keggg"]//前向 let aViewController = SHWithDrawHomeViewController() aViewController.num = num as! Int//前向 aViewController.callBack = { (str) in if let callback = params["callback"] as? (String) -> Void { callback(str)//反向 } } return aViewController }
- MGJRouter
- 组件化的优劣
下载100张大图进行组合
- 队列组
- NSOperationQueue线程依赖
单例的销毁
- 代码中有一个onceToken变量,在单例生成之前onceToken = 0,在单例生成之后onceToken = -1了,之后一直保持-1这个值,销毁的时候把单例类置为 nil 同时把onceToken置为 0
工厂模式的实际应用
内存泄漏怎么检查
- MFinderLeaks,instrement 动态检查,静态分析
AutoLayout怎么实现界面布局的
-
AutoLayout用到了布局算法Cassowary算法和一整套布局引擎Layout Engine
-
每个视图在得到它的布局之前,Layout Engine会将视图、约束、优先级、固定大小通过计算转换成最终的位置和大小。
-
具体工作流程:
- 当约束变化,添加、删除视图、设置constant和priority会触发约束变化
- Layout Engine碰到约束变化时会重新计算布局
- 获取到新约束后,调用superview.setNeedLayout()
- 然后会进入Deferred Layout Pass,主要是做一些容错处理。比如说有约束缺失或者没有确定,会在这里做容错处理
- 接下来,Layout Engine 会从上到下调用 layoutSubviews() ,通过 Cassowary 算法计算各个子视图的位置,算出来后将子视图的 frame 从 Layout Engine 里拷贝出来
- 最后,当runloop到来的时候,去重新绘制操作(这一步跟手动布局一样)
转载自:https://juejin.cn/post/6904834156740657159