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
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
}
複製程式碼
然後, 第一次做演算法題的我, 只能想到通過最為粗糙的辦法解答, 就是一個迴圈, 我也知道這不是面試官所期許的答案, 但這有什麼辦法呢...
解法2
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
}
複製程式碼
這個是我在網上翻閱資料後的另一種看似比較好的解答方式.
解法3
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
}
複製程式碼
這個僅僅是加了一個負值判斷.... 但是冪是double
的仍然是毫無頭緒, 需要請大佬和大神不吝賜教
.
面試題2 findMedianSortedArrays
這是一道LeetCode的原題, 但是我至今還沒有刷過演算法題庫... 也是平生第一次面試的時候遇到演算法題. 題目的意思是找到兩個排序陣列的中位數.
解法1
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
}
複製程式碼
第一次做演算法題, 只能無視演算法複雜度, 能夠完成就算是不錯了, 要什麼自行車...
解法2
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
}
}
複製程式碼
這個是我在網上查資料的時候的答案... 還沒理清是個什麼思路, 反正面試官提示分而治之, 掐頭去尾... 也不知道是不是最優演算法.
解法3
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
}
複製程式碼
這個是請教霜神(@halfrost-一縷殤流化隱半邊冰霜)後給的思路, 的確很好實現. 但霜神謙虛的說不是最優解....
奇數測試
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
複製程式碼
偶數測試
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
@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
}
複製程式碼
--- scope of: findMedianSortedArrays_3 ---
timing: 0.0358932018280029
--- scope of: findMedianSortedArrays_4 ---
timing: 0.0241639614105225
複製程式碼
沿著霜神的思路和麵試官給的提示, 給出了上面的演算法, 但是解法3
的數量級是相同的
面試題3 UIContorl -> UIButton
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 {
}
複製程式碼
以上就是面試時候的原題, 一開始根本不知道是要讓我做些什麼, 說是隻要讓我把上面的方法全部實現就好了, 就像實現一個自己的UIButton... 一開始, 我以為是要我用CALayer
來實現, 嚇的我瑟瑟發抖... 還好不是... 然後, 我就按照自己平時自定義控制元件的寫法, 寫了一個UIImageView
, 一個UILabel
, 然後佈局賦值... 就看到面試官對著我笑著說, 你以為這道題這麼簡單麼... 這麼簡單麼...
然後說, 你知道UIButton setTitle
的時候才會建立UILabel
, setImage
的時候才會建立UIImageView
, 你為什麼吧frame
給寫死... 不知道UIView
有sizeToFit
麼, 你怎麼不實現sizeThatFits
, 你是完全不會用吧... 你知道UIButton
用AutoLayout
佈局的時候只要設定origin
座標, 寬高就可以自適應了, 你自定義的時候怎麼不實現呢? setBackgroundImage
和setImageEdgeInsets
你就不要做了吧, 反正你也不會...
我想說的是,誰沒事放著UIButton
不用, 用UIContorl
這種東西... 就為了一個target-action
的設計模式麼... 我每次在想思路的時候一直打斷我, 可能這是面試官的一種策略吧... 算了不吐槽了, 還是盡力實現吧.
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
}
}
}
複製程式碼
雖然實現了部分的功能, 但是AutoLayout
和EdgeInsets
的功能還是沒有思路, 還請各位大佬解惑.
測試對比
我們用自己自實現的Button
和UIButton
進行對比.
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()
}
}
複製程式碼
zero impl
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()
複製程式碼
setTitle && setTitleColor
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()
}
複製程式碼
setTitle && setTitleColor && sizeToFit
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()
複製程式碼
setImage
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()
複製程式碼
setImage && sizeToFit
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()
複製程式碼
setBackgroundImage
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()
複製程式碼
這裡, 我們看到和系統的實現不一樣, 因為我直接在渲染(display
)設定了bitmap
, 而不是像系統新增了一個新的view
. 這樣的效能消耗會少些... (以修改 為了下面的問題)
setBackgroundImage && sizeToFit
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()
複製程式碼
setTitle && setTitleColor && setImage
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()
複製程式碼
setTitle && setTitleColor && setImage && sizeToFit
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()
複製程式碼
setTitle && setTitleColor && setBackgroundImage
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()
複製程式碼
setTitle && setTitleColor && setBackgroundImage && sizeToFit
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()
複製程式碼
setTitle && setTitleColor && setImage && setBackgroundImage
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()
複製程式碼
setTitle && setTitleColor && setImage && setBackgroundImage && sizeToFit
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()
複製程式碼
這道題還沒有實現的就是AutoLayout
和EdgeInsets
, 還有就是在sizeToFit
算的最佳尺寸和系統的最佳尺寸有細微出入, 還有就是UIImageView
和UILabel
的先後載入的問題.
update
lazy var titleLabel: UILabel = {
let titleLabel = UILabel()
titleLabel.font = UIFont.systemFont(ofSize: 18)
titleLabel.textAlignment = .center
return titleLabel
}()
複製程式碼
對於在sizeToFit算的最佳尺寸和系統的最佳尺寸有細微出入
這個問題是UILabel
的預設系統字型大小是17
, 而UIButton
中的titleLabel
的字型大小是18
.
internal func setImage(_ image: UIImage) {
if !imageViewIsCreated {
addSubview(imageView)
if titleLabelIsCreated {
insertSubview(imageView, belowSubview: titleLabel)
}
imageViewIsCreated = true
}
imageView.image = image
}
複製程式碼
對於UIImageView和UILabel的先後載入的問題
, 需要在setImage
時判斷titleLabel
是否存在即可
現已達到完全相同, 接下來就是要解決AutoLayout
和EdgeInsets
的問題.
update2
通過 nib 進行建立.. 謝謝@夢痕_Lee
提供的思路.
1.判斷是否是從nib中建立
var createdFromNib = false
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
createdFromNib = true
}
複製程式碼
2.重寫系統實現函式intrinsicContentSize
並返回最佳尺寸
override var intrinsicContentSize: CGSize {
return bestSize()
}
func bestSize() -> 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
}
}
複製程式碼
3.佈局時判斷即可
override func layoutSubviews() {
super.layoutSubviews()
if createdFromNib {
frame.size = intrinsicContentSize
}
...
}
複製程式碼
4.測試一下, 不加sizetofit
nib_button.layer.borderWidth = 1
nib_button.layer.borderColor = UIColor.black.cgColor
nib_button.setTitle("github.com/coderZsq")
nib_button.setTitleColor(.red)
// nib_button.setTitleEdgeInsets(.zero)
nib_button.setImage(UIImage(named: "avatar") ?? UIImage())
// nib_button.setBackgroundImage(UIImage(named: "avatar") ?? UIImage())
nib_button.setImageEdgeInsets(.zero)
複製程式碼
一樣的完美, 攻克了AutoLayout
, 接下來就是EdgeInsets
啦~~~
update3
一直理解錯了, intrinsicContentSize
這個方法是在新增約束後生效, 不管是nib
還是手動約束
, 都會生效.
所以update2
中只需實現第二步即可, 並不需要其他的判斷.
面試題4 網路架構實現
這道題真是戳中我的軟肋, 網路與多執行緒是我最為薄弱的地方, 現在對執行緒的理解應該已經不錯了, 但是網路還是有所欠缺的, 所以, 我會在今後學習Linux
和精讀AFNetWorking
&& SDWebImage
後, 自己寫一個網路架構來進行自我提升.
面試總結
對於兩道演算法題, 我沒有什麼太多想講的, 技不如人吧
, 可是演算法題這種東西在iOS
上用處其實不是很大, 我就不信那些沒有刷過演算法題的同學, 面對一道從沒有見過的演算法題能夠一下子從容
的寫出最優解
的. 還有就是UI
的那道題目, 坑吧, 誰會去放著好好的現成的不用, 去噁心自己, 還一定要一樣... 我都問過面試官好幾遍, 到底想要做什麼功能... 回答只有, 我不在乎你怎麼寫, 只要和系統的一樣就好了.... 產品附體了麼....
好吧... 技不如人, 被掛了也是理所當然... 不會找什麼藉口... 聽美團的朋友說, 現在只招技術專家, 其他低職級的名額緊縮都不招了... 誒... 隨緣吧...
最後 本文中所有的原始碼都可以在github上找到:
GitHub Repo:coderZsq.target.swift
Follow: coderZsq · GitHub
Resume: coderzsq.github.io/coderZsq.we…
掘金技術徵文連結? juejin.im/post/5aaf2a…