美團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
面試的題目相同, 沒有做任何的準備, 其實也不知道準備什么, 記得那時候聊的是:
UI方面:
如何避免卡頓掉幀
,異步渲染
.性能方面:
性能優化
,Vsync
,CPU / GPU
網絡方面: 如何進行請求
緩存策略
.安全方面:
lild重簽名
,Mach-O
.前端方面: 如何避免
DOM
重繪.后端方面: 如何進行
負載均衡
的處理.
還有一些極端的情況, 由于時間久遠已經記不太清了, 反正這次面試給我的感覺就是, 靠... 我簡直就是個垃圾啊~ 當時記得內推我的架構師建議我扎實一下iOS的基本功
, 然后就推薦了基本書: 計算機網絡
, 操作系統原理
, HTTP權威指南
, TCP/IP權威指南
, 深入解析Max OS X & iOS 操作系統
... 這些書, 除了HTTP權威指南
我咬著牙看完了, 其他的對于我來說簡直就是天書, 根本消化不良啊.
去年12月
, 第二次面試大公司: 京東
, 由于有了上一次的經驗, 我變得非常的淡定, 知道自己肯定會被大公司所淘汰, 和優等專業生
有著不可逾越
的天塹
, 比較吃驚的是, 進入京東的大樓需要用身份證
換取臨時門禁
... 那時候的面試題就比餓了么的柔和的多了, 雖然當時還是回答不出.
Runtime:
isa
,消息轉發
,弱引用表
.Runloop:
mode
,timer
.Block:
__block
,__forwording
.Property:
assign
,weak
,copy
.Category:
assoc
,load
現在想想, 這TM才是面試iOS
啊, 只可惜, 那時候并不具備這些知識, 可惜了了. 之后我就對C++
, ASM
, Linux
, 這三方面進行了學習, 也學習了些MACH-O
, 逆向
的相關的知識, 以備后面的面試機會.
第三次就是這周三
面試美團
了, 我準備了所有我能夠準備的面試題內容, 底層原理
, 逆向安全
, 多線程與鎖
, 內存布局
, UI性能優化
等, 果不其然, 足足1個小時
的電話面試, 我輕松通過, 問的就是些我準備好的底層知識
, 讓我覺得機會終于來了, 可是.... 當我現場面試后... 題目全部是上機題...
設計一個網絡框架, 如何進行不同數據解析的設計(header, body), 并能夠進行自定義, 重連機制如何處理, 狀態碼錯誤轉發機制的處理, 如何避免回調地獄, 實現
Promise
的自實現.根據
UIControl
實現UIButton
....找到兩個排序數組的中位數...
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
給寫死... 不知道UIView
有sizeToFit
么, 你怎么不實現sizeThatFits
, 你是完全不會用吧... 你知道UIButton
用AutoLayout
布局的時候只要設置origin
坐標, 寬高就可以自適應了, 你自定義的時候怎么不實現呢? setBackgroundImage
和setImageEdgeInsets
你就不要做了吧, 反正你也不會...
我想說的是,誰沒事放著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>
雖然實現了部分的功能, 但是AutoLayout
和EdgeInsets
的功能還是沒有思路, 還請各位大佬解惑.
測試對比
我們用自己自實現的Button
和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;">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>
這道題還沒有實現的就是AutoLayout
和EdgeInsets
, 還有就是在sizeToFit
算的最佳尺寸和系統的最佳尺寸有細微出入, 還有就是UIImageView
和UILabel
的先后加載的問題.
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)]
現已達到完全相同, 接下來就是要解決AutoLayout
和EdgeInsets
的問題.
美團面試題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>