美团iOS面试败北感悟

移动开发
本次美团面试, 我准备了所有我能够准备的面试题内容,底层原理,逆向安全,多线程与锁,内存布局,UI性能优化等, 果不其然, 足足1个小时的电话面试, 我轻松通过, 问的就是些我准备好的底层知识, 让我觉得机会终于来了, 可是.... 当我现场面试后... 题目全部是上机题...

日常扯淡

从去年开始, 我就一直有尝试的面试些大公司, 因为对于一个半路出家(非计算机专业), 靠着MJ视频入门的iOS菜鸡玩家, 经过了3年的摸爬滚打, 终于也渐渐的可以做一些简单的前端,后端,移动端的交互, 但想要继续深入就感觉瓶颈越发的明显,基础的薄弱导致很难上升, 所以能够进入一家大型成熟互联网公司就成为了我最近的目标, 原因很简单, 这是最为有效的学习成长的方式.

去年7月, 第一次面试大公司:饿了么, 收到大公司的召唤非常的兴奋, 觉得自己翻身的机会终于要来了, 兴冲冲的跑去面试, 以为会和一般初级iOS面试的题目相同, 没有做任何的准备, 其实也不知道准备什么, 记得那时候聊的是:

  1. UI方面:如何避免卡顿掉帧,异步渲染.
  2. 性能方面:性能优化,Vsync,CPU / GPU
  3. 网络方面: 如何进行请求缓存策略.
  4. 安全方面:lild重签名,Mach-O.
  5. 前端方面: 如何避免DOM重绘.
  6. 后端方面: 如何进行负载均衡的处理.

还有一些极端的情况, 由于时间久远已经记不太清了, 反正这次面试给我的感觉就是, 靠... 我简直就是个垃圾啊~ 当时记得内推我的架构师建议我扎实一下iOS的基本功, 然后就推荐了基本书:计算机网络,操作系统原理,HTTP权威指南,TCP/IP权威指南,深入解析Max OS X & iOS 操作系统... 这些书, 除了HTTP权威指南我咬着牙看完了, 其他的对于我来说简直就是天书, 根本消化不良啊.

去年12月, 第二次面试大公司:京东, 由于有了上一次的经验, 我变得非常的淡定, 知道自己肯定会被大公司所淘汰, 和优等专业生有着不可逾越的天堑, 比较吃惊的是, 进入京东的大楼需要用身份证换取临时门禁... 那时候的面试题就比饿了么的柔和的多了, 虽然当时还是回答不出.

  1. Runtime:isa,消息转发,弱引用表.
  2. Runloop:mode,timer.
  3. Block:__block,__forwording.
  4. Property:assign,weak,copy.
  5. Category:assoc,load

现在想想, 这TM才是面试iOS啊, 只可惜, 那时候并不具备这些知识, 可惜了了. 之后我就对C++,ASM,Linux, 这三方面进行了学习, 也学习了些MACH-O,逆向的相关的知识, 以备后面的面试机会.

第三次就是这周三面试美团了, 我准备了所有我能够准备的面试题内容,底层原理,逆向安全,多线程与锁,内存布局,UI性能优化等, 果不其然, 足足1个小时的电话面试, 我轻松通过, 问的就是些我准备好的底层知识, 让我觉得机会终于来了, 可是.... 当我现场面试后... 题目全部是上机题...

  1. 设计一个网络框架, 如何进行不同数据解析的设计(header, body), 并能够进行自定义, 重连机制如何处理, 状态码错误转发机制的处理, 如何避免回调地狱, 实现Promise的自实现.
  2. 根据UIControl实现UIButton....
  3. 找到两个排序数组的中位数...
  4. pow(double, double)函数的自实现....

果然,网络,UI,算法... 好吧, 第一次做上机题, 瞬间就蒙了... 然后就是面试官在旁边不停的笑... 不停的笑... 可能是他对我友好的一种方式吧... 最后的面试结论是, 我的知识面还是比较广的,做过的东西也是挺多的, 但是在知识深度方面还是比较欠缺.

后来得知, 他们招聘的是技术专家的职级, 觉得我的技术水平达不到要求, 不能给与录取, 当然被拒我是当场就知道了, 也觉得美团和饿了么的两次面试经历都和我的水平相差甚远... 可是, 我只是想进入大公司学习, 就一定要成为专家才行么? 现在初中高级,资深都不需要了, 直接专家么..., 我的猎头朋友和我说,3-1的级别就是对标阿里P6/P7, 我选择去死啊.....

有了这次的面试经验后, 我的策略也发生了改变, 不再追求大公司的光环了, 做人开心一点不好么, 非要像机器一样思考?活的像个算法一样是不是感觉缺少了些重要的东西? 和朋友们吹吹牛逼的日子不快活么, 偏要用功学习? 这里想到了最近听到的两句话,最好的产品体验就是要让用户不用思考,认知即痛苦, 无知即极乐, 人真是矛盾, 价值观的一念之差, 差之毫厘失之千里啊....

美团面试题1 自实现pow(double, double)

这道题目上机的时候非常的蒙, 因为幂是double, 完全不知道如何下手, 面试官就降低难度使用整型.

解法1

  1. func _pow_1(_ base: Int, _ exponent: Int) -> Int { if exponent < 0 { return 0 } if exponent == 0 { return 0 } if exponent == 1 { return base 
  2.     } var result = base for _ in 1.. 

然后, 第一次做算法题的我, 只能想到通过最为粗糙的办法解答, 就是一个循环, 我也知道这不是面试官所期许的答案, 但这有什么办法呢...

解法2

  1. func _pow_2(_ base: Double, _ exponent: Int) -> Double { if exponent < 0 { return 0 } if exponent == 0 { return 0 } var ans:Double = 1, last_pow = base, exp = exponent while exp > 0 { if (exp & 1) != 0 { 
  2.             ans = ans * last_pow 
  3.         } 
  4.         exp = exp >> 1 last_pow = last_pow * last_pow 
  5.     } return ans 

这个是我在网上翻阅资料后的另一种看似比较好的解答方式.

解法3

  1. func _pow_3(_ base: Double, _ exponent: Int) -> Double { var isNegative = false var exp = exponent if exp < 0 { 
  2.         isNegative = true exp = -exp 
  3.     } let result = _pow_2(base, exp) return isNegative ? 1 / result : result 

这个仅仅是加了一个负值判断.... 但是幂是double的仍然是毫无头绪, 需要请大佬和大神不吝赐教.

美团面试题2 findMedianSortedArrays

这是一道LeetCode的原题, 但是我至今还没有刷过算法题库... 也是平生第一次面试的时候遇到算法题. 题目的意思是找到两个排序数组的中位数.

解法1

  1. func findMedianSortedArrays_1(_ array1: [Int], _ array2: [Int]) -> Double { var array = [Int]() 
  2.     array.append(contentsOf: array1) 
  3.     array.append(contentsOf: array2) quickSort(list: &array) let b = array.count % 2 let c = array.count var result = 0.0; if b == 1 { 
  4.         result = Double(array[c / 2]) 
  5.     } else { let n1 = array[c / 2 - 1] let n2 = array[c / 2] 
  6.         result = Double((n1 + n2)) / 2.0 } return result 

第一次做算法题, 只能无视算法复杂度, 能够完成就算是不错了, 要什么自行车...

解法2

  1. func findMedianSortedArrays_2(_ array1: [Int], _ array2: [Int]) -> Double { let c1 = array1.count, c2 = array2.count var a1 = array1, a2 = array2 if c1  nums2.count - j { return findKth(&nums2, i: j, &nums1, j: i, k: k) 
  2.         } if nums1.count == i { return Double(nums2[j + k - 1]) 
  3.         } if k == 1 { return Double(min(nums1[i], nums2[j])) 
  4.         } let pa = min(i + k / 2, nums1.count), pb = j + k - pa + i if nums1[pa - 1] < nums2[pb - 1] { return findKth(&nums1, i: pa, &nums2, j: j, k: k - pa + i) 
  5.         } else if nums1[pa - 1] > nums2[pb - 1] { return findKth(&nums1, i: i, &nums2, j: pb, k: k - pb + j) 
  6.         } else { return Double(nums1[pa - 1]) 
  7.         } 
  8.     } let total = c1 + c2 if total % 2 == 1 { return findKth(&a1, i: 0, &a2, j: 0, k: total / 2 + 1) 
  9.     } else { return (findKth(&a1, i: 0, &a2, j: 0, k: total / 2) + findKth(&a1, i: 0, &a2, j: 0, k: total / 2 + 1)) / 2.0 } 

这个是我在网上查资料的时候的答案... 还没理清是个什么思路, 反正面试官提示分而治之, 掐头去尾... 也不知道是不是最优算法.

解法3

  1. func findMedianSortedArrays_3(_ array1: [Int], _ array2: [Int]) -> Double { let total = array1.count + array2.count let index = total / 2 let count = array1.count < array2.count ? array2.count : array1.count var array = [Int]() var i = 0, j = 0; for _ in 0...count { if array.count >= index + 1 { break } if array1[i] < array2[j] { 
  2.             array.append(array1[i]) 
  3.             i += 1 } else { 
  4.             array.append(array2[j]) 
  5.             j += 1 } 
  6.     } return total % 2 == 1 ? Double(array[index]) : Double(array[index] + array[index - 1]) * 0.5 } 

这个是请教霜神(@halfrost-一缕殇流化隐半边冰霜)后给的思路, 的确很好实现. 但霜神谦虚的说不是最优解....

奇数测试

  1. var array1 = randomList(1000001) var array2 = randomList(1000000) quickSort(list: &array1) quickSort(list: &array2) print(findMedianSortedArrays_1(array1, array2)) print(findMedianSortedArrays_2(array1, array2)) print(findMedianSortedArrays_3(array1, array2)) 

--- scope of: findMedianSortedArrays --- 500045.0 500045.0 500045.0

偶数测试

  1. var array1 = randomList(1000001) var array2 = randomList(1000000) quickSort(list: &array1) quickSort(list: &array2) print(findMedianSortedArrays_1(array1, array2)) print(findMedianSortedArrays_2(array1, array2)) print(findMedianSortedArrays_3(array1, array2)) 

--- scope of: findMedianSortedArrays --- 499665.5 499665.5 499665.5

耗时比较

--- scope of: findMedianSortedArrays_1 ---

timing: 2.50845623016357 --- scope of: findMedianSortedArrays_2 ---

timing: 1.28746032714844e-05 --- scope of: findMedianSortedArrays_3 ---

timing: 0.0358490943908691

可以看出网上查资料的答案是三种解法里性能最高的算法, 霜神的思路和网上的答案差了三个数量级, 而我写的差了五个数量级.... 果然我写的果然是最为垃圾的算法....

解法4

  1. @discardableResult func findMedianSortedArrays_4(_ array1: [Int], _ array2: [Int]) -> Double { if array1.count == 0 { if array2.count % 2 == 1 { return Double(array2[array2.count / 2]) 
  2.         } else { return Double(array2[array2.count / 2] + array2[array2.count / 2 - 1]) * 0.5 } 
  3.     } else if array2.count == 0 { if array1.count % 2 == 1 { return Double(array1[array1.count / 2]) 
  4.         } else { return Double(array1[array1.count / 2] + array1[array1.count / 2 - 1]) * 0.5 } 
  5.     } let total = array1.count + array2.count let count = array1.count < array2.count ? array1.count : array2.count let odd = total % 2 == 1 var i = 0, j = 0, f = 1, m1 = 0.0, m2 = 0.0, result = 0.0; for _ in 0...count { if odd { array1[i] < array2[j] ? (i += 1) : (j += 1) } if f >= total / 2 { if odd { 
  6.                 result = array1[i] < array2[j] ? Double(array1[i]) : Double(array2[j]) 
  7.             } else { if array1[i] < array2[j] { 
  8.                     m1 = Double(array1[i]) if (i + 1) < array1.count && array1[i + 1] < array2[j] { 
  9.                         m2 = Double(array1[i + 1]) 
  10.                     } else { 
  11.                         m2 = Double(array2[j]) 
  12.                     } 
  13.                 } else { 
  14.                     m1 = Double(array2[j]) if (j + 1) < array2.count && array2[j + 1] < array1[i] { 
  15.                         m2 = Double(array2[j + 1]) 
  16.                     } else { 
  17.                         m2 = Double(array1[i]) 
  18.                     } 
  19.                 } 
  20.                 result = (m1 + m2) * 0.5 } break } if !odd { array1[i] < array2[j] ? (i += 1) : (j += 1) } 
  21.         f += 1 } return result 

--- scope of: findMedianSortedArrays_3 ---

timing: 0.0358932018280029 --- scope of:

findMedianSortedArrays_4 ---

timing: 0.0241639614105225

沿着霜神的思路和面试官给的提示, 给出了上面的算法, 但是解法3的数量级是相同的

美团面试题3 UIContorl -> UIButton

  1. protocol ButtonInterface { func setTitle(_ title: String); func setTitleColor(_ titleColor: UIColor); func setTitleEdgeInsets(_ edgeInsets: UIEdgeInsets); func setImage(_ image: UIImage); func setBackgroundImage(_ image: UIImage); func setImageEdgeInsets(_ edgeInsets: UIEdgeInsets); 
  2. } class Button: UIControl, ButtonInterface {  

以上就是面试时候的原题, 一开始根本不知道是要让我做些什么, 说是只要让我把上面的方法全部实现就好了, 就像实现一个自己的UIButton... 一开始, 我以为是要我用CALayer来实现, 吓的我瑟瑟发抖... 还好不是... 然后, 我就按照自己平时自定义控件的写法, 写了一个UIImageView, 一个UILabel, 然后布局赋值... 就看到面试官对着我笑着说, 你以为这道题这么简单么... 这么简单么...

然后说, 你知道UIButton setTitle的时候才会创建UILabel,setImage的时候才会创建UIImageView, 你为什么吧frame给写死... 不知道UIView有sizeToFit么, 你怎么不实现sizeThatFits, 你是完全不会用吧... 你知道UIButton用AutoLayout布局的时候只要设置origin坐标, 宽高就可以自适应了, 你自定义的时候怎么不实现呢?setBackgroundImage和setImageEdgeInsets你就不要做了吧, 反正你也不会...

我想说的是,谁没事放着UIButton不用, 用UIContorl这种东西... 就为了一个target-action的设计模式么... 我每次在想思路的时候一直打断我, 可能这是面试官的一种策略吧... 算了不吐槽了, 还是尽力实现吧.

  1. import UIKit protocol ButtonInterface { func setTitle(_ title: String); func setTitleColor(_ titleColor: UIColor); func setTitleEdgeInsets(_ edgeInsets: UIEdgeInsets); func setImage(_ image: UIImage); func setBackgroundImage(_ image: UIImage); func setImageEdgeInsets(_ edgeInsets: UIEdgeInsets); 
  2. } class Button: UIControl, ButtonInterface { lazy var titleLabel: UILabel = UILabel() lazy var imageView: UIImageView = UIImageView() lazy var backgroundImageView: UIImageView = UIImageView() var titleLabelIsCreated = false var imageViewIsCreated = false var backgroundImageViewCreated = false internal func setTitle(_ text: String) { if !titleLabelIsCreated { 
  3.             addSubview(titleLabel) 
  4.             titleLabelIsCreated = true } 
  5.         titleLabel.text = text 
  6.     } internal func setTitleColor(_ textColor: UIColor) { if !titleLabelIsCreated { return } 
  7.         titleLabel.textColor = textColor 
  8.     } internal func setTitleEdgeInsets(_ edgeInsets: UIEdgeInsets) { if !titleLabelIsCreated { return } 
  9.     } internal func setImage(_ image: UIImage) { if !imageViewIsCreated { 
  10.             addSubview(imageView) 
  11.             imageViewIsCreated = true } 
  12.         imageView.image = image 
  13.     } internal func setBackgroundImage(_ image: UIImage) { if !backgroundImageViewCreated { 
  14.             addSubview(backgroundImageView) 
  15.             insertSubview(backgroundImageView, at: 0) 
  16.             backgroundImageViewCreated = true } 
  17.         backgroundImageView.image = image 
  18.     } internal func setImageEdgeInsets(_ edgeInsets: UIEdgeInsets) { if !imageViewIsCreated { return } 
  19.     } override func sizeThatFits(_ size: CGSize) -> CGSize { if titleLabelIsCreated && !imageViewIsCreated && !backgroundImageViewCreated { let text: NSString? = titleLabel.text as NSString? let titleLabelW: CGFloat = text?.boundingRect(with: CGSize(width: CGFloat(MAXFLOAT), height: bounds.height), options: NSStringDrawingOptions.usesLineFragmentOrigin, attributes: [NSAttributedStringKey.font : titleLabel.font], context: nil).size.width ?? 0.0 let titleLabelH: CGFloat = text?.boundingRect(with: CGSize(width: titleLabelW, height: CGFloat(MAXFLOAT)), options: NSStringDrawingOptions.usesLineFragmentOrigin, attributes: [NSAttributedStringKey.font : titleLabel.font], context: nil).size.height ?? 0.0 return CGSize(width: titleLabelW, height: titleLabelH + 10) 
  20.         } else if !titleLabelIsCreated && imageViewIsCreated { return imageView.image?.size ?? CGSize.zero 
  21.         } else if titleLabelIsCreated && imageViewIsCreated { let text: NSString? = titleLabel.text as NSString? let titleLabelW: CGFloat = text?.boundingRect(with: CGSize(width: CGFloat(MAXFLOAT), height: bounds.height), options: NSStringDrawingOptions.usesLineFragmentOrigin, attributes: [NSAttributedStringKey.font : titleLabel.font], context: nil).size.width ?? 0.0 let titleLabelH: CGFloat = text?.boundingRect(with: CGSize(width: titleLabelW, height: CGFloat(MAXFLOAT)), options: NSStringDrawingOptions.usesLineFragmentOrigin, attributes: [NSAttributedStringKey.font : titleLabel.font], context: nil).size.height ?? 0.0 let imageViewW: CGFloat = imageView.image?.size.width ?? 0.0 let imageViewH: CGFloat = imageView.image?.size.height ?? 0.0 return CGSize(width: titleLabelW + imageViewW, height: imageViewH > titleLabelH ? imageViewH : titleLabelH) 
  22.         } else { return backgroundImageView.image?.size ?? CGSize.zero 
  23.         } 
  24.     } override func layoutSubviews() { super.layoutSubviews() if titleLabelIsCreated && !imageViewIsCreated { 
  25.             titleLabel.frame = bounds 
  26.             titleLabel.textAlignment = .center 
  27.         } else if !titleLabelIsCreated && imageViewIsCreated { let y: CGFloat = 0; let width: CGFloat = imageView.image?.size.width ?? 0; let x: CGFloat = (bounds.width - width) * 0.5; let height: CGFloat = bounds.height; 
  28.             imageView.frame = CGRect(x: x, y: y, width: width, height: height) 
  29.         } else if titleLabelIsCreated && imageViewIsCreated { let imageViewY: CGFloat = 0; let imageViewW: CGFloat = imageView.image?.size.width ?? 0; let imageViewH: CGFloat = bounds.height; let text: NSString? = titleLabel.text as NSString? let titleLabelW: CGFloat = text?.boundingRect(with: CGSize(width: CGFloat(MAXFLOAT), height: bounds.height), options: NSStringDrawingOptions.usesLineFragmentOrigin, attributes: [NSAttributedStringKey.font : titleLabel.font], context: nil).size.width ?? 0.0 let titleLabelH: CGFloat = text?.boundingRect(with: CGSize(width: titleLabelW, height: CGFloat(MAXFLOAT)), options: NSStringDrawingOptions.usesLineFragmentOrigin, attributes: [NSAttributedStringKey.font : titleLabel.font], context: nil).size.height ?? 0.0 let imageViewX: CGFloat = (bounds.width - imageViewW - titleLabelW) * 0.5; let titleLabelX: CGFloat = imageViewX + imageViewW let titleLabelY = (bounds.height - titleLabelH) * 0.5 titleLabel.frame = CGRect(x: titleLabelX, y: titleLabelY, width: titleLabelW, height: titleLabelH) 
  30.             imageView.frame = CGRect(x: imageViewX, y: imageViewY, width: imageViewW, height: imageViewH) 
  31.         } if backgroundImageViewCreated { 
  32.             backgroundImageView.frame = bounds 
  33.         } 
  34.     } 

虽然实现了部分的功能, 但是AutoLayout和EdgeInsets的功能还是没有思路, 还请各位大佬解惑.

测试对比

我们用自己自实现的Button和UIButton进行对比.

  1. class ViewController: UIViewController { override func loadView() { super.loadView(); let uibutton = UIButton() 
  2.         uibutton.layer.borderWidth = 1 uibutton.layer.borderColor = UIColor.black.cgColor 
  3.         uibutton.frame = CGRect(x: 0, y: 100, width: view.bounds.width, height: 40) 
  4.         uibutton.setTitle("github.com/coderZsq"for: .normal) 
  5.         uibutton.setTitleColor(.red, for: .normal) 
  6.         uibutton.titleEdgeInsets = UIEdgeInsetsMake(0, 0, 0, 0) 
  7.         uibutton.setImage(UIImage(named: "avatar"), for: .normal) 
  8.         uibutton.setBackgroundImage(UIImage(named: "avatar"), for: .normal) 
  9.         uibutton.imageEdgeInsets = UIEdgeInsetsMake(-10, -10, -10, -10) 
  10.         view.addSubview(uibutton) 
  11.         uibutton.sizeToFit() let button = Button() 
  12.         button.layer.borderWidth = 1 button.layer.borderColor = UIColor.black.cgColor 
  13.         button.frame = CGRect(x: 0, y: 350, width: view.bounds.width, height: 40) 
  14.         button.setTitle("github.com/coderZsq"
  15.         button.setTitleColor(.red) 
  16.         button.setTitleEdgeInsets(UIEdgeInsetsMake(0, 0, 0, 0)) 
  17.         button.setImage(UIImage(named: "avatar") ?? UIImage()); 
  18.         button.setBackgroundImage(UIImage(named: "avatar") ?? UIImage()) 
  19.         button.setImageEdgeInsets(UIEdgeInsetsMake(0, 0, 0, 0)) 
  20.         view.addSubview(button) 
  21.         button.sizeToFit() 
  22.     } 

zero impl

  1. let uibutton = UIButton() 
  2.         uibutton.layer.borderWidth = 1 uibutton.layer.borderColor = UIColor.black.cgColor 
  3.         uibutton.frame = CGRect(x: 0, y: 100, width: view.bounds.width, height: 40) //        uibutton.setTitle("github.com/coderZsq"for: .normal) //        uibutton.setTitleColor(.red, for: .normal) //        uibutton.titleEdgeInsets = UIEdgeInsetsMake(0, 0, 0, 0) //        uibutton.setImage(UIImage(named: "avatar"), for: .normal) //        uibutton.setBackgroundImage(UIImage(named: "avatar"), for: .normal) //        uibutton.imageEdgeInsets = UIEdgeInsetsMake(-10, -10, -10, -10) view.addSubview(uibutton) //        uibutton.sizeToFit() let button = Button() 
  4.         button.layer.borderWidth = 1 button.layer.borderColor = UIColor.black.cgColor 
  5.         button.frame = CGRect(x: 0, y: 350, width: view.bounds.width, height: 40) //        button.setTitle("github.com/coderZsq") //        button.setTitleColor(.red) //        button.setTitleEdgeInsets(UIEdgeInsetsMake(0, 0, 0, 0)) //        button.setImage(UIImage(named: "avatar") ?? UIImage()); //        button.setBackgroundImage(UIImage(named: "avatar") ?? UIImage()) //        button.setImageEdgeInsets(UIEdgeInsetsMake(0, 0, 0, 0)) view.addSubview(button) //        button.sizeToFit() 

 

美团iOS面试败北感悟


美团iOS面试败北感悟

 

 

setTitle && setTitleColor

  1. let uibutton = UIButton() 
  2.         uibutton.layer.borderWidth = 1 uibutton.layer.borderColor = UIColor.black.cgColor 
  3.         uibutton.frame = CGRect(x: 0, y: 100, width: view.bounds.width, height: 40) 
  4.         uibutton.setTitle("github.com/coderZsq"for: .normal) 
  5.         uibutton.setTitleColor(.red, for: .normal) //        uibutton.titleEdgeInsets = UIEdgeInsetsMake(0, 0, 0, 0) //        uibutton.setImage(UIImage(named: "avatar"), for: .normal) //        uibutton.setBackgroundImage(UIImage(named: "avatar"), for: .normal) //        uibutton.imageEdgeInsets = UIEdgeInsetsMake(-10, -10, -10, -10) view.addSubview(uibutton) //        uibutton.sizeToFit() let button = Button() 
  6.         button.layer.borderWidth = 1 button.layer.borderColor = UIColor.black.cgColor 
  7.         button.frame = CGRect(x: 0, y: 350, width: view.bounds.width, height: 40) 
  8.         button.setTitle("github.com/coderZsq"
  9.         button.setTitleColor(.red) //        button.setTitleEdgeInsets(UIEdgeInsetsMake(0, 0, 0, 0)) //        button.setImage(UIImage(named: "avatar") ?? UIImage()); //        button.setBackgroundImage(UIImage(named: "avatar") ?? UIImage()) //        button.setImageEdgeInsets(UIEdgeInsetsMake(0, 0, 0, 0)) view.addSubview(button) //        button.sizeToFit() } 

 

美团iOS面试败北感悟

setTitle && setTitleColor && sizeToFit

  1. let uibutton = UIButton() 
  2.         uibutton.layer.borderWidth = 1 uibutton.layer.borderColor = UIColor.black.cgColor 
  3.         uibutton.frame = CGRect(x: 0, y: 100, width: view.bounds.width, height: 40) 
  4.         uibutton.setTitle("github.com/coderZsq"for: .normal) 
  5.         uibutton.setTitleColor(.red, for: .normal) //        uibutton.titleEdgeInsets = UIEdgeInsetsMake(0, 0, 0, 0) //        uibutton.setImage(UIImage(named: "avatar"), for: .normal) //        uibutton.setBackgroundImage(UIImage(named: "avatar"), for: .normal) //        uibutton.imageEdgeInsets = UIEdgeInsetsMake(-10, -10, -10, -10) view.addSubview(uibutton) 
  6.         uibutton.sizeToFit() let button = Button() 
  7.         button.layer.borderWidth = 1 button.layer.borderColor = UIColor.black.cgColor 
  8.         button.frame = CGRect(x: 0, y: 350, width: view.bounds.width, height: 40) 
  9.         button.setTitle("github.com/coderZsq"
  10.         button.setTitleColor(.red) //        button.setTitleEdgeInsets(UIEdgeInsetsMake(0, 0, 0, 0)) //        button.setImage(UIImage(named: "avatar") ?? UIImage()); //        button.setBackgroundImage(UIImage(named: "avatar") ?? UIImage()) //        button.setImageEdgeInsets(UIEdgeInsetsMake(0, 0, 0, 0)) view.addSubview(button) 
  11.         button.sizeToFit() 

 

美团iOS面试败北感悟

setImage

  1. let uibutton = UIButton() 
  2.         uibutton.layer.borderWidth = 1 uibutton.layer.borderColor = UIColor.black.cgColor 
  3.         uibutton.frame = CGRect(x: 0, y: 100, width: view.bounds.width, height: 40) //        uibutton.setTitle("github.com/coderZsq"for: .normal) //        uibutton.setTitleColor(.red, for: .normal) //        uibutton.titleEdgeInsets = UIEdgeInsetsMake(0, 0, 0, 0) uibutton.setImage(UIImage(named: "avatar"), for: .normal) //        uibutton.setBackgroundImage(UIImage(named: "avatar"), for: .normal) //        uibutton.imageEdgeInsets = UIEdgeInsetsMake(-10, -10, -10, -10) view.addSubview(uibutton) //        uibutton.sizeToFit() let button = Button() 
  4.         button.layer.borderWidth = 1 button.layer.borderColor = UIColor.black.cgColor 
  5.         button.frame = CGRect(x: 0, y: 350, width: view.bounds.width, height: 40) //        button.setTitle("github.com/coderZsq") //        button.setTitleColor(.red) //        button.setTitleEdgeInsets(UIEdgeInsetsMake(0, 0, 0, 0)) button.setImage(UIImage(named: "avatar") ?? UIImage()); //        button.setBackgroundImage(UIImage(named: "avatar") ?? UIImage()) //        button.setImageEdgeInsets(UIEdgeInsetsMake(0, 0, 0, 0)) view.addSubview(button) //        button.sizeToFit() 

 

美团iOS面试败北感悟

美团iOS面试败北感悟

setImage && sizeToFit

  1. let uibutton = UIButton() 
  2.         uibutton.layer.borderWidth = 1 uibutton.layer.borderColor = UIColor.black.cgColor 
  3.         uibutton.frame = CGRect(x: 0, y: 100, width: view.bounds.width, height: 40) //        uibutton.setTitle("github.com/coderZsq"for: .normal) //        uibutton.setTitleColor(.red, for: .normal) //        uibutton.titleEdgeInsets = UIEdgeInsetsMake(0, 0, 0, 0) uibutton.setImage(UIImage(named: "avatar"), for: .normal) //        uibutton.setBackgroundImage(UIImage(named: "avatar"), for: .normal) //        uibutton.imageEdgeInsets = UIEdgeInsetsMake(-10, -10, -10, -10) view.addSubview(uibutton) 
  4.         uibutton.sizeToFit() let button = Button() 
  5.         button.layer.borderWidth = 1 button.layer.borderColor = UIColor.black.cgColor 
  6.         button.frame = CGRect(x: 0, y: 350, width: view.bounds.width, height: 40) //        button.setTitle("github.com/coderZsq") //        button.setTitleColor(.red) //        button.setTitleEdgeInsets(UIEdgeInsetsMake(0, 0, 0, 0)) button.setImage(UIImage(named: "avatar") ?? UIImage()); //        button.setBackgroundImage(UIImage(named: "avatar") ?? UIImage()) //        button.setImageEdgeInsets(UIEdgeInsetsMake(0, 0, 0, 0)) view.addSubview(button) 
  7.         button.sizeToFit()

 

美团iOS面试败北感悟

美团iOS面试败北感悟

setBackgroundImage

  1. let uibutton = UIButton() 
  2.         uibutton.layer.borderWidth = 1 uibutton.layer.borderColor = UIColor.black.cgColor 
  3.         uibutton.frame = CGRect(x: 0, y: 100, width: view.bounds.width, height: 40) //        uibutton.setTitle("github.com/coderZsq"for: .normal) //        uibutton.setTitleColor(.red, for: .normal) //        uibutton.titleEdgeInsets = UIEdgeInsetsMake(0, 0, 0, 0) //        uibutton.setImage(UIImage(named: "avatar"), for: .normal) uibutton.setBackgroundImage(UIImage(named: "avatar"), for: .normal) //        uibutton.imageEdgeInsets = UIEdgeInsetsMake(-10, -10, -10, -10) view.addSubview(uibutton) //        uibutton.sizeToFit() let button = Button() 
  4.         button.layer.borderWidth = 1 button.layer.borderColor = UIColor.black.cgColor 
  5.         button.frame = CGRect(x: 0, y: 350, width: view.bounds.width, height: 40) //        button.setTitle("github.com/coderZsq") //        button.setTitleColor(.red) //        button.setTitleEdgeInsets(UIEdgeInsetsMake(0, 0, 0, 0)) //        button.setImage(UIImage(named: "avatar") ?? UIImage()); button.setBackgroundImage(UIImage(named: "avatar") ?? UIImage()) //        button.setImageEdgeInsets(UIEdgeInsetsMake(0, 0, 0, 0)) view.addSubview(button) //        button.sizeToFit()

 

美团iOS面试败北感悟

美团iOS面试败北感悟

这里, 我们看到和系统的实现不一样, 因为我直接在渲染(display)设置了bitmap, 而不是像系统添加了一个新的view. 这样的性能消耗会少些... (以修改 为了下面的问题)

setBackgroundImage && sizeToFit

  1. let uibutton = UIButton() 
  2.         uibutton.layer.borderWidth = 1 uibutton.layer.borderColor = UIColor.black.cgColor 
  3.         uibutton.frame = CGRect(x: 0, y: 100, width: view.bounds.width, height: 40) //        uibutton.setTitle("github.com/coderZsq"for: .normal) //        uibutton.setTitleColor(.red, for: .normal) //        uibutton.titleEdgeInsets = UIEdgeInsetsMake(0, 0, 0, 0) //        uibutton.setImage(UIImage(named: "avatar"), for: .normal) uibutton.setBackgroundImage(UIImage(named: "avatar"), for: .normal) //        uibutton.imageEdgeInsets = UIEdgeInsetsMake(-10, -10, -10, -10) view.addSubview(uibutton) 
  4.         uibutton.sizeToFit() let button = Button() 
  5.         button.layer.borderWidth = 1 button.layer.borderColor = UIColor.black.cgColor 
  6.         button.frame = CGRect(x: 0, y: 350, width: view.bounds.width, height: 40) //        button.setTitle("github.com/coderZsq") //        button.setTitleColor(.red) //        button.setTitleEdgeInsets(UIEdgeInsetsMake(0, 0, 0, 0)) //        button.setImage(UIImage(named: "avatar") ?? UIImage()); button.setBackgroundImage(UIImage(named: "avatar") ?? UIImage()) //        button.setImageEdgeInsets(UIEdgeInsetsMake(0, 0, 0, 0)) view.addSubview(button) 
  7.         button.sizeToFit()

 

美团iOS面试败北感悟

美团iOS面试败北感悟

setTitle && setTitleColor && setImage

  1. let uibutton = UIButton() 
  2.         uibutton.layer.borderWidth = 1 uibutton.layer.borderColor = UIColor.black.cgColor 
  3.         uibutton.frame = CGRect(x: 0, y: 100, width: view.bounds.width, height: 40) 
  4.         uibutton.setTitle("github.com/coderZsq"for: .normal) 
  5.         uibutton.setTitleColor(.red, for: .normal) //        uibutton.titleEdgeInsets = UIEdgeInsetsMake(0, 0, 0, 0) uibutton.setImage(UIImage(named: "avatar"), for: .normal) //        uibutton.setBackgroundImage(UIImage(named: "avatar"), for: .normal) //        uibutton.imageEdgeInsets = UIEdgeInsetsMake(-10, -10, -10, -10) view.addSubview(uibutton) //        uibutton.sizeToFit() let button = Button() 
  6.         button.layer.borderWidth = 1 button.layer.borderColor = UIColor.black.cgColor 
  7.         button.frame = CGRect(x: 0, y: 350, width: view.bounds.width, height: 40) 
  8.         button.setTitle("github.com/coderZsq"
  9.         button.setTitleColor(.red) //        button.setTitleEdgeInsets(UIEdgeInsetsMake(0, 0, 0, 0)) button.setImage(UIImage(named: "avatar") ?? UIImage()); //        button.setBackgroundImage(UIImage(named: "avatar") ?? UIImage()) //        button.setImageEdgeInsets(UIEdgeInsetsMake(0, 0, 0, 0)) view.addSubview(button) //        button.sizeToFit()

 

美团iOS面试败北感悟

美团iOS面试败北感悟

setTitle && setTitleColor && setImage && sizeToFit

  1. let uibutton = UIButton() 
  2.         uibutton.layer.borderWidth = 1 uibutton.layer.borderColor = UIColor.black.cgColor 
  3.         uibutton.frame = CGRect(x: 0, y: 100, width: view.bounds.width, height: 40) 
  4.         uibutton.setTitle("github.com/coderZsq"for: .normal) 
  5.         uibutton.setTitleColor(.red, for: .normal) //        uibutton.titleEdgeInsets = UIEdgeInsetsMake(0, 0, 0, 0) uibutton.setImage(UIImage(named: "avatar"), for: .normal) //        uibutton.setBackgroundImage(UIImage(named: "avatar"), for: .normal) //        uibutton.imageEdgeInsets = UIEdgeInsetsMake(-10, -10, -10, -10) view.addSubview(uibutton) 
  6.         uibutton.sizeToFit() let button = Button() 
  7.         button.layer.borderWidth = 1 button.layer.borderColor = UIColor.black.cgColor 
  8.         button.frame = CGRect(x: 0, y: 350, width: view.bounds.width, height: 40) 
  9.         button.setTitle("github.com/coderZsq"
  10.         button.setTitleColor(.red) //        button.setTitleEdgeInsets(UIEdgeInsetsMake(0, 0, 0, 0)) button.setImage(UIImage(named: "avatar") ?? UIImage()); //        button.setBackgroundImage(UIImage(named: "avatar") ?? UIImage()) //        button.setImageEdgeInsets(UIEdgeInsetsMake(0, 0, 0, 0)) view.addSubview(button) 
  11.         button.sizeToFit()

 

美团iOS面试败北感悟

美团iOS面试败北感悟

setTitle && setTitleColor && setBackgroundImage

  1. let uibutton = UIButton() 
  2.         uibutton.layer.borderWidth = 1 uibutton.layer.borderColor = UIColor.black.cgColor 
  3.         uibutton.frame = CGRect(x: 0, y: 100, width: view.bounds.width, height: 40) 
  4.         uibutton.setTitle("github.com/coderZsq"for: .normal) 
  5.         uibutton.setTitleColor(.red, for: .normal) //        uibutton.titleEdgeInsets = UIEdgeInsetsMake(0, 0, 0, 0) //        uibutton.setImage(UIImage(named: "avatar"), for: .normal) uibutton.setBackgroundImage(UIImage(named: "avatar"), for: .normal) //        uibutton.imageEdgeInsets = UIEdgeInsetsMake(-10, -10, -10, -10) view.addSubview(uibutton) //        uibutton.sizeToFit() let button = Button() 
  6.         button.layer.borderWidth = 1 button.layer.borderColor = UIColor.black.cgColor 
  7.         button.frame = CGRect(x: 0, y: 350, width: view.bounds.width, height: 40) 
  8.         button.setTitle("github.com/coderZsq"
  9.         button.setTitleColor(.red) //        button.setTitleEdgeInsets(UIEdgeInsetsMake(0, 0, 0, 0)) //        button.setImage(UIImage(named: "avatar") ?? UIImage()); button.setBackgroundImage(UIImage(named: "avatar") ?? UIImage()) //        button.setImageEdgeInsets(UIEdgeInsetsMake(0, 0, 0, 0)) view.addSubview(button) //        button.sizeToFit()

 

美团iOS面试败北感悟

美团iOS面试败北感悟

setTitle && setTitleColor && setBackgroundImage && sizeToFit

  1. let uibutton = UIButton() 
  2.         uibutton.layer.borderWidth = 1 uibutton.layer.borderColor = UIColor.black.cgColor 
  3.         uibutton.frame = CGRect(x: 0, y: 100, width: view.bounds.width, height: 40) 
  4.         uibutton.setTitle("github.com/coderZsq"for: .normal) 
  5.         uibutton.setTitleColor(.red, for: .normal) //        uibutton.titleEdgeInsets = UIEdgeInsetsMake(0, 0, 0, 0) //        uibutton.setImage(UIImage(named: "avatar"), for: .normal) uibutton.setBackgroundImage(UIImage(named: "avatar"), for: .normal) //        uibutton.imageEdgeInsets = UIEdgeInsetsMake(-10, -10, -10, -10) view.addSubview(uibutton) 
  6.         uibutton.sizeToFit() let button = Button() 
  7.         button.layer.borderWidth = 1 button.layer.borderColor = UIColor.black.cgColor 
  8.         button.frame = CGRect(x: 0, y: 350, width: view.bounds.width, height: 40) 
  9.         button.setTitle("github.com/coderZsq"
  10.         button.setTitleColor(.red) //        button.setTitleEdgeInsets(UIEdgeInsetsMake(0, 0, 0, 0)) //        button.setImage(UIImage(named: "avatar") ?? UIImage()); button.setBackgroundImage(UIImage(named: "avatar") ?? UIImage()) //        button.setImageEdgeInsets(UIEdgeInsetsMake(0, 0, 0, 0)) view.addSubview(button) 
  11.         button.sizeToFit() 

 

美团iOS面试败北感悟

美团iOS面试败北感悟

setTitle && setTitleColor && setImage && setBackgroundImage

  1. let uibutton = UIButton() 
  2.         uibutton.layer.borderWidth = 1 uibutton.layer.borderColor = UIColor.black.cgColor 
  3.         uibutton.frame = CGRect(x: 0, y: 100, width: view.bounds.width, height: 40) 
  4.         uibutton.setTitle("github.com/coderZsq"for: .normal) 
  5.         uibutton.setTitleColor(.red, for: .normal) //        uibutton.titleEdgeInsets = UIEdgeInsetsMake(0, 0, 0, 0) uibutton.setImage(UIImage(named: "avatar"), for: .normal) 
  6.         uibutton.setBackgroundImage(UIImage(named: "avatar"), for: .normal) //        uibutton.imageEdgeInsets = UIEdgeInsetsMake(-10, -10, -10, -10) view.addSubview(uibutton) //        uibutton.sizeToFit() let button = Button() 
  7.         button.layer.borderWidth = 1 button.layer.borderColor = UIColor.black.cgColor 
  8.         button.frame = CGRect(x: 0, y: 350, width: view.bounds.width, height: 40) 
  9.         button.setTitle("github.com/coderZsq"
  10.         button.setTitleColor(.red) //        button.setTitleEdgeInsets(UIEdgeInsetsMake(0, 0, 0, 0)) button.setImage(UIImage(named: "avatar") ?? UIImage()); 
  11.         button.setBackgroundImage(UIImage(named: "avatar") ?? UIImage()) //        button.setImageEdgeInsets(UIEdgeInsetsMake(0, 0, 0, 0)) view.addSubview(button) //        button.sizeToFit() 

 

美团iOS面试败北感悟美团iOS面试败北感悟

setTitle && setTitleColor && setImage && setBackgroundImage && sizeToFit

  1. let uibutton = UIButton() 
  2.         uibutton.layer.borderWidth = 1 uibutton.layer.borderColor = UIColor.black.cgColor 
  3.         uibutton.frame = CGRect(x: 0, y: 100, width: view.bounds.width, height: 40) 
  4.         uibutton.setTitle("github.com/coderZsq"for: .normal) 
  5.         uibutton.setTitleColor(.red, for: .normal) //        uibutton.titleEdgeInsets = UIEdgeInsetsMake(0, 0, 0, 0) uibutton.setImage(UIImage(named: "avatar"), for: .normal) 
  6.         uibutton.setBackgroundImage(UIImage(named: "avatar"), for: .normal) //        uibutton.imageEdgeInsets = UIEdgeInsetsMake(-10, -10, -10, -10) view.addSubview(uibutton) 
  7.         uibutton.sizeToFit() let button = Button() 
  8.         button.layer.borderWidth = 1 button.layer.borderColor = UIColor.black.cgColor 
  9.         button.frame = CGRect(x: 0, y: 350, width: view.bounds.width, height: 40) 
  10.         button.setTitle("github.com/coderZsq"
  11.         button.setTitleColor(.red) //        button.setTitleEdgeInsets(UIEdgeInsetsMake(0, 0, 0, 0)) button.setImage(UIImage(named: "avatar") ?? UIImage()); 
  12.         button.setBackgroundImage(UIImage(named: "avatar") ?? UIImage()) //        button.setImageEdgeInsets(UIEdgeInsetsMake(0, 0, 0, 0)) view.addSubview(button) 
  13.         button.sizeToFit() 

美团iOS面试败北感悟

美团iOS面试败北感悟

这道题还没有实现的就是AutoLayout和EdgeInsets, 还有就是在sizeToFit算的最佳尺寸和系统的最佳尺寸有细微出入, 还有就是UIImageView和UILabel的先后加载的问题.

update

  1. lazy var titleLabel: UILabel =  { let titleLabel = UILabel() 
  2.         titleLabel.font = UIFont.systemFont(ofSize: 18) 
  3.         titleLabel.textAlignment = .center return titleLabel 
  4.     }() 
  5. 对于在sizeToFit算的最佳尺寸和系统的最佳尺寸有细微出入这个问题是UILabel的默认系统字体大小是17, 而UIButton中的titleLabel的字体大小是18. 
  6. internal func setImage(_ image: UIImage) { if !imageViewIsCreated { 
  7.             addSubview(imageView) if titleLabelIsCreated { 
  8.                 insertSubview(imageView, belowSubview: titleLabel) 
  9.             } 
  10.             imageViewIsCreated = true } 
  11.         imageView.image = image 
  12.     } 

对于UIImageView和UILabel的先后加载的问题, 需要在setImage时判断titleLabel是否存在即可

美团iOS面试败北感悟

美团iOS面试败北感悟

现已达到完全相同, 接下来就是要解决AutoLayout和EdgeInsets的问题.

美团面试题4 网络架构实现

这道题真是戳中我的软肋, 网络与多线程是我最为薄弱的地方, 现在对线程的理解应该已经不错了, 但是网络还是有所欠缺的, 所以, 我会在今后学习Linux和精读AFNetWorking&&SDWebImage后, 自己写一个网络架构来进行自我提升.

美团面试总结

对于两道算法题, 我没有什么太多想讲的,技不如人吧, 可是算法题这种东西在iOS上用处其实不是很大, 我就不信那些没有刷过算法题的同学, 面对一道从没有见过的算法题能够一下子从容的写出最优解的. 还有就是UI的那道题目, 坑吧, 谁会去放着好好的现成的不用, 去恶心自己, 还一定要一样... 我都问过面试官好几遍, 到底想要做什么功能... 回答只有, 我不在乎你怎么写, 只要和系统的一样就好了.... 产品附体了么....

好吧... 技不如人, 被挂了也是理所当然... 不会找什么借口... 听美团的朋友说, 现在只招技术专家, 其他低职级的名额紧缩都不招了... 诶... 随缘吧...

最后 本文中所有的源码都可以在github上找到:

  • GitHub Repo:https://github.com/coderZsq/coderZsq.target.swift
  • Follow: https://github.com/coderZsq
  • Resume: https://coderzsq.github.io/coderZsq.webpack.js/#/
责任编辑:未丽燕 来源: iOS开发整理发布
相关推荐

2023-03-28 21:33:53

面试隔离MVCC

2023-05-22 08:17:04

2024-05-16 17:58:30

线程任务线程通讯线程池

2018-12-07 12:54:22

App美团外卖iOS客户端

2024-06-07 08:10:14

Netty操作系统零拷贝

2021-08-29 18:36:17

MySQL技术面试题

2016-11-27 20:43:26

云计算迭代

2020-12-30 10:04:46

userMapper接口

2013-08-20 13:11:58

技术美团

2023-01-31 08:44:50

SQL语句查询

2017-06-01 10:52:35

互联网

2023-11-26 17:48:00

营销策略

2021-08-31 15:19:16

美团面试快排

2022-03-03 16:45:02

美团述职反馈

2023-06-30 07:58:07

Spring数据源事务

2021-08-26 13:22:09

JVM调优参数

2021-09-09 19:08:49

JDK版本Java

2017-09-18 01:21:05

美团IDC集群锐捷网络

2021-08-04 20:36:12

MySQL结构体系

2020-03-23 12:58:34

美团公有云互联网
点赞
收藏

51CTO技术栈公众号