轉載面試筆記

美團iOS面試敗北感悟 | 掘金技術征文

http://www.cocoachina.com/special/20180419/23081.html

GitHub Repo:coderZsq.target.swift
Follow: coderZsq · GitHub
Resume: coderzsq.github.io/coderZsq.we…

日常扯淡

從去年開始, 我就一直有嘗試的面試些大公司, 因為對于一個半路出家(非計算機專業), 靠著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

<pre courier="" new",="" monospace;="" line-height:="" 1.75;="" overflow:="" auto;="" position:="" relative;"="" style="margin: 1.5em 0px; padding: 0px; font-size: 1em; width: 712.797px; overflow: auto; background: rgb(247, 247, 247); font-style: normal; font-variant: normal; font-weight: 400; font-stretch: normal; line-height: 1.5em; font-family: "Andale Mono", "Lucida Console", monospace; white-space: pre; color: rgb(37, 37, 37); letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">func pow_1( base: Int, _ exponent: Int) -> Int { if exponent < 0 { return 0 } if exponent == 0 { return 0 } if exponent == 1 { return base } var result = base for _ in 1.. <exponent?{?????????result?*=?base?????}?????return?result?}< pre="">然后, 第一次做算法題的我, 只能想到通過最為粗糙的辦法解答, 就是一個循環, 我也知道這不是面試官所期許的答案, 但這有什么辦法呢...

解法2

<pre courier="" new",="" monospace;="" line-height:="" 1.75;="" overflow:="" auto;="" position:="" relative;"="" style="margin: 1.5em 0px; padding: 0px; font-size: 1em; width: 705.656px; overflow: auto; background: rgb(247, 247, 247); font-style: normal; font-variant: normal; font-weight: normal; font-stretch: normal; line-height: 1.5em; font-family: "Andale Mono", "Lucida Console", monospace; white-space: pre;">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 { ans = ans * last_pow } exp = exp >> 1 last_pow = last_pow * last_pow } return ans }</pre>

這個是我在網上翻閱資料后的另一種看似比較好的解答方式.

解法3

<pre courier="" new",="" monospace;="" line-height:="" 1.75;="" overflow:="" auto;="" position:="" relative;"="" style="margin: 1.5em 0px; padding: 0px; font-size: 1em; width: 705.656px; overflow: auto; background: rgb(247, 247, 247); font-style: normal; font-variant: normal; font-weight: normal; font-stretch: normal; line-height: 1.5em; font-family: "Andale Mono", "Lucida Console", monospace; white-space: pre;">func pow_3( base: Double, _ exponent: Int) -> Double { var isNegative = false var exp = exponent if exp < 0 { isNegative = true exp = -exp } let result = _pow_2(base, exp) return isNegative ? 1 / result : result }</pre>

這個僅僅是加了一個負值判斷.... 但是冪是double的仍然是毫無頭緒, 需要請大佬和大神不吝賜教.

美團面試題2 findMedianSortedArrays

這是一道LeetCode的原題, 但是我至今還沒有刷過算法題庫... 也是平生第一次面試的時候遇到算法題. 題目的意思是找到兩個排序數組的中位數.

解法1

<pre courier="" new",="" monospace;="" line-height:="" 1.75;="" overflow:="" auto;="" position:="" relative;"="" style="margin: 1.5em 0px; padding: 0px; font-size: 1em; width: 705.656px; overflow: auto; background: rgb(247, 247, 247); font-style: normal; font-variant: normal; font-weight: normal; font-stretch: normal; line-height: 1.5em; font-family: "Andale Mono", "Lucida Console", monospace; white-space: pre;">func findMedianSortedArrays_1(_ array1: [Int], _ array2: [Int]) -> Double { var array = Int array.append(contentsOf: array1) array.append(contentsOf: array2) quickSort(list: &array) let b = array.count % 2 let c = array.count var result = 0.0; if b == 1 { result = Double(array[c / 2]) } else { let n1 = array[c / 2 - 1] let n2 = array[c / 2] result = Double((n1 + n2)) / 2.0 } return result }</pre>

第一次做算法題, 只能無視算法復雜度, 能夠完成就算是不錯了, 要什么自行車...

解法2

<pre courier="" new",="" monospace;="" line-height:="" 1.75;="" overflow:="" auto;="" position:="" relative;"="" style="margin: 1.5em 0px; padding: 0px; font-size: 1em; width: 705.656px; overflow: auto; background: rgb(247, 247, 247); font-style: normal; font-variant: normal; font-weight: normal; font-stretch: normal; line-height: 1.5em; font-family: "Andale Mono", "Lucida Console", monospace; white-space: pre;">func findMedianSortedArrays_2(_ array1: [Int], _ array2: [Int]) -> Double { let c1 = array1.count, c2 = array2.count var a1 = array1, a2 = array2 if c1 <= 0 && c2 <= 0 { return 0.0 } func findKth(_ nums1: inout [Int], i: Int, _ nums2: inout [Int], j: Int, k: Int) -> Double { if nums1.count - i > nums2.count - j { return findKth(&nums2, i: j, &nums1, j: i, k: k) } if nums1.count == i { return Double(nums2[j + k - 1]) } if k == 1 { return Double(min(nums1[i], nums2[j])) } 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) } else if nums1[pa - 1] > nums2[pb - 1] { return findKth(&nums1, i: i, &nums2, j: pb, k: k - pb + j) } else { return Double(nums1[pa - 1]) } } let total = c1 + c2 if total % 2 == 1 { return findKth(&a1, i: 0, &a2, j: 0, k: total / 2 + 1) } 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 } }</pre>

這個是我在網上查資料的時候的答案... 還沒理清是個什么思路, 反正面試官提示分而治之, 掐頭去尾... 也不知道是不是最優算法.

解法3

<pre courier="" new",="" monospace;="" line-height:="" 1.75;="" overflow:="" auto;="" position:="" relative;"="" style="margin: 1.5em 0px; padding: 0px; font-size: 1em; width: 705.656px; overflow: auto; background: rgb(247, 247, 247); font-style: normal; font-variant: normal; font-weight: normal; font-stretch: normal; line-height: 1.5em; font-family: "Andale Mono", "Lucida Console", monospace; white-space: pre;">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] { array.append(array1[i]) i += 1 } else { array.append(array2[j]) j += 1 } } return total % 2 == 1 ? Double(array[index]) : Double(array[index] + array[index - 1]) * 0.5 }</pre>

這個是請教霜神(@halfrost-一縷殤流化隱半邊冰霜)后給的思路, 的確很好實現. 但霜神謙虛的說不是最優解....

奇數測試

<pre courier="" new",="" monospace;="" line-height:="" 1.75;="" overflow:="" auto;="" position:="" relative;"="" style="margin: 1.5em 0px; padding: 0px; font-size: 1em; width: 705.656px; overflow: auto; background: rgb(247, 247, 247); font-style: normal; font-variant: normal; font-weight: normal; font-stretch: normal; line-height: 1.5em; font-family: "Andale Mono", "Lucida Console", monospace; white-space: pre;">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))</pre>

<pre courier="" new",="" monospace;="" line-height:="" 1.75;="" overflow:="" auto;="" position:="" relative;"="" style="margin: 1.5em 0px; padding: 0px; font-size: 1em; width: 705.656px; overflow: auto; background: rgb(247, 247, 247); font-style: normal; font-variant: normal; font-weight: normal; font-stretch: normal; line-height: 1.5em; font-family: "Andale Mono", "Lucida Console", monospace; white-space: pre;">--- scope of: findMedianSortedArrays --- 500045.0 500045.0 500045.0</pre>

偶數測試

<pre courier="" new",="" monospace;="" line-height:="" 1.75;="" overflow:="" auto;="" position:="" relative;"="" style="margin: 1.5em 0px; padding: 0px; font-size: 1em; width: 705.656px; overflow: auto; background: rgb(247, 247, 247); font-style: normal; font-variant: normal; font-weight: normal; font-stretch: normal; line-height: 1.5em; font-family: "Andale Mono", "Lucida Console", monospace; white-space: pre;">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))</pre>

<pre courier="" new",="" monospace;="" line-height:="" 1.75;="" overflow:="" auto;="" position:="" relative;"="" style="margin: 1.5em 0px; padding: 0px; font-size: 1em; width: 705.656px; overflow: auto; background: rgb(247, 247, 247); font-style: normal; font-variant: normal; font-weight: normal; font-stretch: normal; line-height: 1.5em; font-family: "Andale Mono", "Lucida Console", monospace; white-space: pre;">--- scope of: findMedianSortedArrays --- 499665.5 499665.5 499665.5</pre>

耗時比較

<pre courier="" new",="" monospace;="" line-height:="" 1.75;="" overflow:="" auto;="" position:="" relative;"="" style="margin: 1.5em 0px; padding: 0px; font-size: 1em; width: 705.656px; overflow: auto; background: rgb(247, 247, 247); font-style: normal; font-variant: normal; font-weight: normal; font-stretch: normal; line-height: 1.5em; font-family: "Andale Mono", "Lucida Console", monospace; white-space: pre;">--- scope of: findMedianSortedArrays_1 --- timing: 2.50845623016357 --- scope of: findMedianSortedArrays_2 --- timing: 1.28746032714844e-05 --- scope of: findMedianSortedArrays_3 --- timing: 0.0358490943908691</pre>

可以看出網上查資料的答案是三種解法里性能最高的算法, 霜神的思路和網上的答案差了三個數量級, 而我寫的差了五個數量級.... 果然我寫的果然是最為垃圾的算法....

解法4

<pre courier="" new",="" monospace;="" line-height:="" 1.75;="" overflow:="" auto;="" position:="" relative;"="" style="margin: 1.5em 0px; padding: 0px; font-size: 1em; width: 705.656px; overflow: auto; background: rgb(247, 247, 247); font-style: normal; font-variant: normal; font-weight: normal; font-stretch: normal; line-height: 1.5em; font-family: "Andale Mono", "Lucida Console", monospace; white-space: pre;">@discardableResult func findMedianSortedArrays_4(_ array1: [Int], _ array2: [Int]) -> Double { if array1.count == 0 { if array2.count % 2 == 1 { return Double(array2[array2.count / 2]) } else { return Double(array2[array2.count / 2] + array2[array2.count / 2 - 1]) * 0.5 } } else if array2.count == 0 { if array1.count % 2 == 1 { return Double(array1[array1.count / 2]) } else { return Double(array1[array1.count / 2] + array1[array1.count / 2 - 1]) * 0.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 { result = array1[i] < array2[j] ? Double(array1[i]) : Double(array2[j]) } else { if array1[i] < array2[j] { m1 = Double(array1[i]) if (i + 1) < array1.count && array1[i + 1] < array2[j] { m2 = Double(array1[i + 1]) } else { m2 = Double(array2[j]) } } else { m1 = Double(array2[j]) if (j + 1) < array2.count && array2[j + 1] < array1[i] { m2 = Double(array2[j + 1]) } else { m2 = Double(array1[i]) } } result = (m1 + m2) * 0.5 } break } if !odd { array1[i] < array2[j] ? (i += 1) : (j += 1) } f += 1 } return result }</pre>

<pre courier="" new",="" monospace;="" line-height:="" 1.75;="" overflow:="" auto;="" position:="" relative;"="" style="margin: 1.5em 0px; padding: 0px; font-size: 1em; width: 705.656px; overflow: auto; background: rgb(247, 247, 247); font-style: normal; font-variant: normal; font-weight: normal; font-stretch: normal; line-height: 1.5em; font-family: "Andale Mono", "Lucida Console", monospace; white-space: pre;">--- scope of: findMedianSortedArrays_3 --- timing: 0.0358932018280029 --- scope of: findMedianSortedArrays_4 --- timing: 0.0241639614105225</pre>

沿著霜神的思路和面試官給的提示, 給出了上面的算法, 但是解法3的數量級是相同的

美團面試題3 UIContorl -> UIButton

<pre courier="" new",="" monospace;="" line-height:="" 1.75;="" overflow:="" auto;="" position:="" relative;"="" style="margin: 1.5em 0px; padding: 0px; font-size: 1em; width: 705.656px; overflow: auto; background: rgb(247, 247, 247); font-style: normal; font-variant: normal; font-weight: normal; font-stretch: normal; line-height: 1.5em; font-family: "Andale Mono", "Lucida Console", monospace; white-space: pre;">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); } class Button: UIControl, ButtonInterface { }</pre>

以上就是面試時候的原題, 一開始根本不知道是要讓我做些什么, 說是只要讓我把上面的方法全部實現就好了, 就像實現一個自己的UIButton... 一開始, 我以為是要我用CALayer來實現, 嚇的我瑟瑟發抖... 還好不是... 然后, 我就按照自己平時自定義控件的寫法, 寫了一個UIImageView, 一個UILabel, 然后布局賦值... 就看到面試官對著我笑著說, 你以為這道題這么簡單么... 這么簡單么...

然后說, 你知道UIButton setTitle的時候才會創建UILabel, setImage的時候才會創建UIImageView, 你為什么吧frame給寫死... 不知道UIViewsizeToFit么, 你怎么不實現sizeThatFits, 你是完全不會用吧... 你知道UIButtonAutoLayout布局的時候只要設置origin坐標, 寬高就可以自適應了, 你自定義的時候怎么不實現呢? setBackgroundImagesetImageEdgeInsets你就不要做了吧, 反正你也不會...

我想說的是,誰沒事放著UIButton不用, 用UIContorl這種東西... 就為了一個target-action的設計模式么... 我每次在想思路的時候一直打斷我, 可能這是面試官的一種策略吧... 算了不吐槽了, 還是盡力實現吧.

<pre courier="" new",="" monospace;="" line-height:="" 1.75;="" overflow:="" auto;="" position:="" relative;"="" style="margin: 1.5em 0px; padding: 0px; font-size: 1em; width: 705.656px; overflow: auto; background: rgb(247, 247, 247); font-style: normal; font-variant: normal; font-weight: normal; font-stretch: normal; line-height: 1.5em; font-family: "Andale Mono", "Lucida Console", monospace; white-space: pre;">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); } 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 { addSubview(titleLabel) titleLabelIsCreated = true } titleLabel.text = text } internal func setTitleColor(_ textColor: UIColor) { if !titleLabelIsCreated { return } titleLabel.textColor = textColor } internal func setTitleEdgeInsets(_ edgeInsets: UIEdgeInsets) { if !titleLabelIsCreated { return } } internal func setImage(_ image: UIImage) { if !imageViewIsCreated { addSubview(imageView) imageViewIsCreated = true } imageView.image = image } internal func setBackgroundImage(_ image: UIImage) { if !backgroundImageViewCreated { addSubview(backgroundImageView) insertSubview(backgroundImageView, at: 0) backgroundImageViewCreated = true } backgroundImageView.image = image } internal func setImageEdgeInsets(_ edgeInsets: UIEdgeInsets) { if !imageViewIsCreated { return } } 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) } else if !titleLabelIsCreated && imageViewIsCreated { return imageView.image?.size ?? CGSize.zero } 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) } else { return backgroundImageView.image?.size ?? CGSize.zero } } override func layoutSubviews() { super.layoutSubviews() if titleLabelIsCreated && !imageViewIsCreated { titleLabel.frame = bounds titleLabel.textAlignment = .center } 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; imageView.frame = CGRect(x: x, y: y, width: width, height: height) } 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) imageView.frame = CGRect(x: imageViewX, y: imageViewY, width: imageViewW, height: imageViewH) } if backgroundImageViewCreated { backgroundImageView.frame = bounds } } }</pre>

雖然實現了部分的功能, 但是AutoLayoutEdgeInsets的功能還是沒有思路, 還請各位大佬解惑.

測試對比

我們用自己自實現的ButtonUIButton進行對比.

<pre courier="" new",="" monospace;="" line-height:="" 1.75;="" overflow:="" auto;="" position:="" relative;"="" style="margin: 1.5em 0px; padding: 0px; font-size: 1em; width: 705.656px; overflow: auto; background: rgb(247, 247, 247); font-style: normal; font-variant: normal; font-weight: normal; font-stretch: normal; line-height: 1.5em; font-family: "Andale Mono", "Lucida Console", monospace; white-space: pre;">class ViewController: UIViewController { override func loadView() { super.loadView(); let uibutton = UIButton() uibutton.layer.borderWidth = 1 uibutton.layer.borderColor = UIColor.black.cgColor 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() button.layer.borderWidth = 1 button.layer.borderColor = UIColor.black.cgColor 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() } }</pre>

zero impl

<pre courier="" new",="" monospace;="" line-height:="" 1.75;="" overflow:="" auto;="" position:="" relative;"="" style="margin: 1.5em 0px; padding: 0px; font-size: 1em; width: 705.656px; overflow: auto; background: rgb(247, 247, 247); font-style: normal; font-variant: normal; font-weight: normal; font-stretch: normal; line-height: 1.5em; font-family: "Andale Mono", "Lucida Console", monospace; white-space: pre;"> let uibutton = UIButton() uibutton.layer.borderWidth = 1 uibutton.layer.borderColor = UIColor.black.cgColor 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() button.layer.borderWidth = 1 button.layer.borderColor = UIColor.black.cgColor 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()</pre>

[圖片上傳失敗...(image-e8f097-1524188057009)]

[圖片上傳失敗...(image-f99b06-1524188057009)]

setTitle && setTitleColor

<pre courier="" new",="" monospace;="" line-height:="" 1.75;="" overflow:="" auto;="" position:="" relative;"="" style="margin: 1.5em 0px; padding: 0px; font-size: 1em; width: 705.656px; overflow: auto; background: rgb(247, 247, 247); font-style: normal; font-variant: normal; font-weight: normal; font-stretch: normal; line-height: 1.5em; font-family: "Andale Mono", "Lucida Console", monospace; white-space: pre;"> let uibutton = UIButton() uibutton.layer.borderWidth = 1 uibutton.layer.borderColor = UIColor.black.cgColor 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() button.layer.borderWidth = 1 button.layer.borderColor = UIColor.black.cgColor 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() }</pre>

[圖片上傳失敗...(image-6a4dfd-1524188057009)]

[圖片上傳失敗...(image-94a480-1524188057009)]

setTitle && setTitleColor && sizeToFit

<pre courier="" new",="" monospace;="" line-height:="" 1.75;="" overflow:="" auto;="" position:="" relative;"="" style="margin: 1.5em 0px; padding: 0px; font-size: 1em; width: 705.656px; overflow: auto; background: rgb(247, 247, 247); font-style: normal; font-variant: normal; font-weight: normal; font-stretch: normal; line-height: 1.5em; font-family: "Andale Mono", "Lucida Console", monospace; white-space: pre;"> let uibutton = UIButton() uibutton.layer.borderWidth = 1 uibutton.layer.borderColor = UIColor.black.cgColor 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() button.layer.borderWidth = 1 button.layer.borderColor = UIColor.black.cgColor 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()</pre>

[圖片上傳失敗...(image-39c0bf-1524188057009)]

[圖片上傳失敗...(image-86e7f-1524188057009)]

setImage

<pre courier="" new",="" monospace;="" line-height:="" 1.75;="" overflow:="" auto;="" position:="" relative;"="" style="margin: 1.5em 0px; padding: 0px; font-size: 1em; width: 705.656px; overflow: auto; background: rgb(247, 247, 247); font-style: normal; font-variant: normal; font-weight: normal; font-stretch: normal; line-height: 1.5em; font-family: "Andale Mono", "Lucida Console", monospace; white-space: pre;"> let uibutton = UIButton() uibutton.layer.borderWidth = 1 uibutton.layer.borderColor = UIColor.black.cgColor 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() button.layer.borderWidth = 1 button.layer.borderColor = UIColor.black.cgColor 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()</pre>

[圖片上傳失敗...(image-b1dad0-1524188057009)]

[圖片上傳失敗...(image-8c2d31-1524188057009)]

setImage && sizeToFit

<pre courier="" new",="" monospace;="" line-height:="" 1.75;="" overflow:="" auto;="" position:="" relative;"="" style="margin: 1.5em 0px; padding: 0px; font-size: 1em; width: 705.656px; overflow: auto; background: rgb(247, 247, 247); font-style: normal; font-variant: normal; font-weight: normal; font-stretch: normal; line-height: 1.5em; font-family: "Andale Mono", "Lucida Console", monospace; white-space: pre;"> let uibutton = UIButton() uibutton.layer.borderWidth = 1 uibutton.layer.borderColor = UIColor.black.cgColor 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() button.layer.borderWidth = 1 button.layer.borderColor = UIColor.black.cgColor 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()</pre>

[圖片上傳失敗...(image-f0693b-1524188057009)]

[圖片上傳失敗...(image-897b23-1524188057009)]

setBackgroundImage

<pre courier="" new",="" monospace;="" line-height:="" 1.75;="" overflow:="" auto;="" position:="" relative;"="" style="margin: 1.5em 0px; padding: 0px; font-size: 1em; width: 705.656px; overflow: auto; background: rgb(247, 247, 247); font-style: normal; font-variant: normal; font-weight: normal; font-stretch: normal; line-height: 1.5em; font-family: "Andale Mono", "Lucida Console", monospace; white-space: pre;"> let uibutton = UIButton() uibutton.layer.borderWidth = 1 uibutton.layer.borderColor = UIColor.black.cgColor 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() button.layer.borderWidth = 1 button.layer.borderColor = UIColor.black.cgColor 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()</pre>

[圖片上傳失敗...(image-1733d7-1524188057009)]

[圖片上傳失敗...(image-158b83-1524188057009)]

這里, 我們看到和系統的實現不一樣, 因為我直接在渲染(display)設置了bitmap, 而不是像系統添加了一個新的view. 這樣的性能消耗會少些... (以修改 為了下面的問題)

setBackgroundImage && sizeToFit

<pre courier="" new",="" monospace;="" line-height:="" 1.75;="" overflow:="" auto;="" position:="" relative;"="" style="margin: 1.5em 0px; padding: 0px; font-size: 1em; width: 705.656px; overflow: auto; background: rgb(247, 247, 247); font-style: normal; font-variant: normal; font-weight: normal; font-stretch: normal; line-height: 1.5em; font-family: "Andale Mono", "Lucida Console", monospace; white-space: pre;"> let uibutton = UIButton() uibutton.layer.borderWidth = 1 uibutton.layer.borderColor = UIColor.black.cgColor 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() button.layer.borderWidth = 1 button.layer.borderColor = UIColor.black.cgColor 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()</pre>

setTitle && setTitleColor && setImage

<pre courier="" new",="" monospace;="" line-height:="" 1.75;="" overflow:="" auto;="" position:="" relative;"="" style="margin: 1.5em 0px; padding: 0px; font-size: 1em; width: 705.656px; overflow: auto; background: rgb(247, 247, 247); font-style: normal; font-variant: normal; font-weight: normal; font-stretch: normal; line-height: 1.5em; font-family: "Andale Mono", "Lucida Console", monospace; white-space: pre;"> let uibutton = UIButton() uibutton.layer.borderWidth = 1 uibutton.layer.borderColor = UIColor.black.cgColor 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() button.layer.borderWidth = 1 button.layer.borderColor = UIColor.black.cgColor 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()</pre>

setTitle && setTitleColor && setImage && sizeToFit

<pre courier="" new",="" monospace;="" line-height:="" 1.75;="" overflow:="" auto;="" position:="" relative;"="" style="margin: 1.5em 0px; padding: 0px; font-size: 1em; width: 705.656px; overflow: auto; background: rgb(247, 247, 247); font-style: normal; font-variant: normal; font-weight: normal; font-stretch: normal; line-height: 1.5em; font-family: "Andale Mono", "Lucida Console", monospace; white-space: pre;"> let uibutton = UIButton() uibutton.layer.borderWidth = 1 uibutton.layer.borderColor = UIColor.black.cgColor 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() button.layer.borderWidth = 1 button.layer.borderColor = UIColor.black.cgColor 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()</pre>

setTitle && setTitleColor && setBackgroundImage

<pre courier="" new",="" monospace;="" line-height:="" 1.75;="" overflow:="" auto;="" position:="" relative;"="" style="margin: 1.5em 0px; padding: 0px; font-size: 1em; width: 705.656px; overflow: auto; background: rgb(247, 247, 247); font-style: normal; font-variant: normal; font-weight: normal; font-stretch: normal; line-height: 1.5em; font-family: "Andale Mono", "Lucida Console", monospace; white-space: pre;"> let uibutton = UIButton() uibutton.layer.borderWidth = 1 uibutton.layer.borderColor = UIColor.black.cgColor 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() button.layer.borderWidth = 1 button.layer.borderColor = UIColor.black.cgColor 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()</pre>

setTitle && setTitleColor && setBackgroundImage && sizeToFit

<pre courier="" new",="" monospace;="" line-height:="" 1.75;="" overflow:="" auto;="" position:="" relative;"="" style="margin: 1.5em 0px; padding: 0px; font-size: 1em; width: 705.656px; overflow: auto; background: rgb(247, 247, 247); font-style: normal; font-variant: normal; font-weight: normal; font-stretch: normal; line-height: 1.5em; font-family: "Andale Mono", "Lucida Console", monospace; white-space: pre;"> let uibutton = UIButton() uibutton.layer.borderWidth = 1 uibutton.layer.borderColor = UIColor.black.cgColor 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() button.layer.borderWidth = 1 button.layer.borderColor = UIColor.black.cgColor 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()</pre>

setTitle && setTitleColor && setImage && setBackgroundImage

<pre courier="" new",="" monospace;="" line-height:="" 1.75;="" overflow:="" auto;="" position:="" relative;"="" style="margin: 1.5em 0px; padding: 0px; font-size: 1em; width: 705.656px; overflow: auto; background: rgb(247, 247, 247); font-style: normal; font-variant: normal; font-weight: normal; font-stretch: normal; line-height: 1.5em; font-family: "Andale Mono", "Lucida Console", monospace; white-space: pre;"> let uibutton = UIButton() uibutton.layer.borderWidth = 1 uibutton.layer.borderColor = UIColor.black.cgColor 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() button.layer.borderWidth = 1 button.layer.borderColor = UIColor.black.cgColor 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()</pre>

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

<pre courier="" new",="" monospace;="" line-height:="" 1.75;="" overflow:="" auto;="" position:="" relative;"="" style="margin: 1.5em 0px; padding: 0px; font-size: 1em; width: 705.656px; overflow: auto; background: rgb(247, 247, 247); font-style: normal; font-variant: normal; font-weight: normal; font-stretch: normal; line-height: 1.5em; font-family: "Andale Mono", "Lucida Console", monospace; white-space: pre;"> let uibutton = UIButton() uibutton.layer.borderWidth = 1 uibutton.layer.borderColor = UIColor.black.cgColor 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() button.layer.borderWidth = 1 button.layer.borderColor = UIColor.black.cgColor 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()</pre>

這道題還沒有實現的就是AutoLayoutEdgeInsets, 還有就是在sizeToFit算的最佳尺寸和系統的最佳尺寸有細微出入, 還有就是UIImageViewUILabel的先后加載的問題.

update

<pre courier="" new",="" monospace;="" line-height:="" 1.75;="" overflow:="" auto;="" position:="" relative;"="" style="margin: 1.5em 0px; padding: 0px; font-size: 1em; width: 705.656px; overflow: auto; background: rgb(247, 247, 247); font-style: normal; font-variant: normal; font-weight: normal; font-stretch: normal; line-height: 1.5em; font-family: "Andale Mono", "Lucida Console", monospace; white-space: pre;"> lazy var titleLabel: UILabel = { let titleLabel = UILabel() titleLabel.font = UIFont.systemFont(ofSize: 18) titleLabel.textAlignment = .center return titleLabel }()</pre>

對于在sizeToFit算的最佳尺寸和系統的最佳尺寸有細微出入 這個問題是UILabel的默認系統字體大小是17, 而UIButton中的titleLabel的字體大小是18.

<pre courier="" new",="" monospace;="" line-height:="" 1.75;="" overflow:="" auto;="" position:="" relative;"="" style="margin: 1.5em 0px; padding: 0px; font-size: 1em; width: 705.656px; overflow: auto; background: rgb(247, 247, 247); font-style: normal; font-variant: normal; font-weight: normal; font-stretch: normal; line-height: 1.5em; font-family: "Andale Mono", "Lucida Console", monospace; white-space: pre;"> internal func setImage(_ image: UIImage) { if !imageViewIsCreated { addSubview(imageView) if titleLabelIsCreated { insertSubview(imageView, belowSubview: titleLabel) } imageViewIsCreated = true } imageView.image = image }</pre>

對于UIImageView和UILabel的先后加載的問題, 需要在setImage時判斷titleLabel是否存在即可

[圖片上傳失敗...(image-efe766-1524188057009)]

[圖片上傳失敗...(image-b6d511-1524188057009)]

現已達到完全相同, 接下來就是要解決AutoLayoutEdgeInsets的問題.

美團面試題4 網絡架構實現

這道題真是戳中我的軟肋, 網絡與多線程是我最為薄弱的地方, 現在對線程的理解應該已經不錯了, 但是網絡還是有所欠缺的, 所以, 我會在今后學習Linux和精讀AFNetWorking && SDWebImage后, 自己寫一個網絡架構來進行自我提升.

美團面試總結

對于兩道算法題, 我沒有什么太多想講的, 技不如人吧, 可是算法題這種東西在iOS上用處其實不是很大, 我就不信那些沒有刷過算法題的同學, 面對一道從沒有見過的算法題能夠一下子從容的寫出最優解的. 還有就是UI的那道題目, 坑吧, 誰會去放著好好的現成的不用, 去惡心自己, 還一定要一樣... 我都問過面試官好幾遍, 到底想要做什么功能... 回答只有, 我不在乎你怎么寫, 只要和系統的一樣就好了.... 產品附體了么....

好吧... 技不如人, 被掛了也是理所當然... 不會找什么借口... 聽美團的朋友說, 現在只招技術專家, 其他低職級的名額緊縮都不招了... 誒... 隨緣吧...

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

GitHub Repo:coderZsq.target.swift
Follow: coderZsq · GitHub
Resume: coderzsq.github.io/coderZsq.we…</exponent?{?????????result?*=?base?????}?????return?result?}<> </pre>

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,908評論 6 541
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,324評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 178,018評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,675評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,417評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,783評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,779評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,960評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,522評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,267評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,471評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,009評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,698評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,099評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,386評論 1 294
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,204評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,436評論 2 378