Making Repo: coderZsq. Target. Swift Follow: coderZsq, making Resume: coderZsq. Making. IO/coderZsq. We…

Everyday bullshit

Since last year, I have been trying to interview some big companies, because for a half-way (non-computer major) iOS player who started with MJ video, after three years of experience, I am gradually able to do some simple front-end, back-end and mobile terminal interactions. However, if I want to further my study, I feel that the bottleneck is becoming more and more obvious, and it is difficult to rise due to the weak foundation. Therefore, joining a large mature Internet company has become my recent goal, for the simple reason that it is the most effective way to learn and grow.

Last July, the first interview large companies: hungry, received large companies call very excited, feeling turn chance is coming finally, excitedly went to the interview, expect and general primary iOS interview questions are the same, didn’t do any preparation, in fact also don’t know what to prepare, remember to chat at that time is:

  1. UI:How to avoid frame lag.Asynchronous rendering.
  2. Performance:Performance optimization.Vsync.CPU / GPU
  3. Networking: How to make a requestCaching strategies.
  4. Safety:Lild heavy signature.Mach-O.
  5. The front end: How to avoid itDOMRedraw.
  6. Back-end aspect: HowLoad balancingProcessing.

There are also some extreme cases, due to the long time has not remembered too clear, anyway, this interview to my feeling is, depend on… My architect recommended that I get a solid grasp of the basics of iOS, and then recommended basic books: Computer networking, principles of operating systems, the definitive guide to HTTP, the definitive guide to TCP/IP, in-depth analysis of Max OS X & iOS. These books, with the exception of the HTTP guru’s guide, were so hard for me to read that I got indigestion.

In December last year, I had my second interview with a big company: JINGdong. Due to my previous experience, I became very calm and knew that I would be eliminated by a big company, and there was an insurpassable barrier between me and an excellent major student. To my surprise, I needed to exchange my ID card for temporary access control to enter the building of Jingdong. The interview questions were much softer than the ele. me questions, though they still couldn’t be answered.

  1. Runtime: isa.forward.A weak reference table.
  2. Runloop: mode.timer.
  3. Block: __block.__forwording.
  4. Property: assign.weak.copy.
  5. Category: assoc.load

Now think about it, this TM is the interview iOS ah, but unfortunately, at that time did not have these knowledge, unfortunately. After that, I learned C++, ASM and Linux, as well as some knowledge related to MACH-O and reverse, in preparation for future interview opportunities.

The third time is this Wednesday, the second tier of the interview, I prepared all the interview questions I can prepare content, basic principles, reverse security, multi-threading and locking, memory layout, UI performance optimization, and so on, sure enough, a full hour of telephone interview, I easily passed, asked is some of the basic knowledge I prepared. Let me feel the opportunity finally come, but…. When I came out of the interview… All the questions are computer questions…

  1. Design a network framework, how to design different data parsing (header, body), and can be customized, how to deal with the reconnection mechanism, status code error forwarding mechanism, how to avoid callback hell, achievePromiseSelf-realization of.
  2. According to theUIControlimplementationUIButton.
  3. Find the median of two sorted arrays…
  4. Self-implementation of pow(double, double)….

Sure enough, networks, UI, algorithms… Okay, first time on the computer, I was blindfolded… Then the interviewer kept laughing beside him… Laugh a lot… Maybe it was his way of being nice to me… The final conclusion of the interview is that I have a wide range of knowledge and have done a lot of things, but I still lack in the depth of knowledge.

Later, I learned that they were recruiting technical experts, and they thought that my technical level could not meet the requirements, so I could not be admitted. Of course, I knew that I was rejected on the spot, and I also thought that the two interviews of Meituan and Ele. me were far from my level. However, I just want to enter a big company to learn, must become an expert? Now junior high school senior, senior are not needed, direct experts?… , my headhunter friend and I said, 3-1 level is the counterpart ali P6/P7, I choose to die…..

With this interview experience, my strategy has changed. I no longer pursue the halo of a big company. Isn’t it good to be happy and think like a machine? Does living like an algorithm feel like something important is missing? Do you have to study hard when you are not happy with your friends? Here thought of recently heard two words, the best product experience is to let the user do not have to think, cognition is pain, ignorance is bliss, people are really contradictory, values of a thought, a miss is a thousand miles….

1. Self-implementing POW (double, double)

This question is very confusing when the computer, because the power is double, completely do not know how to start, the interviewer reduced the difficulty to use integer type.

Method 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
}
Copy the code

Then, the first time to do the algorithm, I can only think of the most crude solution, is a cycle, I also know this is not the interviewer expected the answer, but what is the way…

Method 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
}
Copy the code

This is another solution that seems to be better after I read the information on the Internet.

Solution 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
}
Copy the code

This simply adds a negative value to the judgment…. But the power is double is still clueless, need to ask big guy and big god not hesitate to give advice.

Interview question 2 findMedianSortedArrays

This is an original LeetCode question, but I have not swiped the algorithm question bank so far… It was also the first time in my life that I met algorithm problems in an interview. Find the median of two sorted arrays.

Method 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
}
Copy the code

The first time to do the algorithm, can only ignore the algorithm complexity, can be completed is good, what bike…

Method 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}}Copy the code

This is the answer I got when I looked it up on the Internet… Not clear what is the idea, anyway, the interviewer prompts divide and rule, pinpoint the tail… I don’t know if it’s optimal.

Solution 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
}
Copy the code

This is consult frost god (@halfrost- a wisp of broken fluid hidden half of the frost) after the idea, is really very good implementation. But frost god modest say is not optimal solution….

An odd number of test
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))
Copy the code
--- scope of: findMedianSortedArrays ---
500045.0
500045.0
500045.0
Copy the code
Even the test
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))
Copy the code
--- scope of: findMedianSortedArrays ---
499665.5
499665.5
499665.5
Copy the code
Take more
--- scope of: findMedianSortedArrays_1 ---
timing: 2.50845623016357
--- scope of: findMedianSortedArrays_2 ---
timing: 1.28746032714844 e-05
--- scope of: findMedianSortedArrays_3 ---
timing: 0.0358490943908691
Copy the code

It can be seen that the answer to check the information online is three kinds of solution in the highest performance algorithm, frost god’s ideas and the answer on the Internet is three orders of magnitude, and I wrote the difference of five orders of magnitude…. As expected I write as expected is the most garbage algorithm….

Method 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
}
Copy the code
--- scope of: findMedianSortedArrays_3 ---
timing: 0.0358932018280029
--- scope of: findMedianSortedArrays_4 ---
timing: 0.0241639614105225
Copy the code

Following frost god’s ideas and the hints given by the interviewer, the above algorithm is given, but the order of magnitude of solution 3 is the same

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 {}Copy the code

The above is the interview of the original question, at the beginning I do not know what to ask me to do, said that as long as LET me implement all the above methods, just like the implementation of a own UIButton… At first, I thought I was going to use CALayer, and I was terrified… It’s not… Then, I wrote a UIImageView, a UILabel, and layout assignment as I normally do for custom controls. I saw the interviewer smiling at me and saying, “Do you think this question is so easy?” That simple…

And say, you know UIButton setTitle is only used to create UILabel, setImage is only used to create UIImageView, why did you kill frame… If UIView has sizeToFit, why don’t you implement sizeThatFits? You can’t use sizeThatFits at all. You know UIButton with AutoLayout layout, as long as you set the origin coordinates, the width and height can be self-adaptive, why don’t you customize it? SetBackgroundImage and SettimageEdGeInSets you can’t do it anyway.

I just want to say, who has nothing to put UIButton don’t, use UIContorl something like that… For a target-action design pattern… I keep interrupting me every time I’m trying to think. Maybe it’s part of the interviewer’s strategy… Forget it. Let’s make it happen.

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(a)lazy var imageView: UIImageView = UIImageView(a)lazy var backgroundImageView: UIImageView = UIImageView(a)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 {
        iftitleLabelIsCreated && ! 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 {returnimageView.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 {
            returnbackgroundImageView.image? .size ??CGSize.zero
        }
    }
    
    override func layoutSubviews(a) {
        super.layoutSubviews()

        iftitleLabelIsCreated && ! 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
        }
    }
}
Copy the code

AutoLayout and EdgeInsets do not work properly.

Contrast test

We compare our self-implemented Button with UIButton.

class ViewController: UIViewController {

    override func loadView(a) {
        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()
    }
}
Copy the code
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()

Copy the code

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()
    }
Copy the code

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()
Copy the code

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()
Copy the code

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()
Copy the code

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()

Copy the code

Here, we see a difference with the system implementation, because I set the bitmap directly in the render (display), instead of adding a new view as the system does. There is less performance cost… (Modified to the following question)

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()

Copy the code

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()

Copy the code

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()
Copy the code

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()
Copy the code

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()
Copy the code

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()
Copy the code

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()
Copy the code

What this problem does not implement is AutoLayout and EdgeInsets, the optimal size of sizeToFit is slightly different from the optimal size of the system, and the loading sequence of UIImageView and UILabel.

update
    lazy var titleLabel: UILabel =  {
        let titleLabel = UILabel()
        titleLabel.font = UIFont.systemFont(ofSize: 18)
        titleLabel.textAlignment = .center
        return titleLabel
    }()
Copy the code

There’s a slight discrepancy between the optimal size that you calculate at sizeToFit and the optimal size that the system has and the problem is that the default system font size for UILabel is 17, and the font size for titleLabel in UIButton is 18.

    internal func setImage(_ image: UIImage) {
        if! imageViewIsCreated { addSubview(imageView)if titleLabelIsCreated {
                insertSubview(imageView, belowSubview: titleLabel)
            }
            imageViewIsCreated = true
        }
        imageView.image = image
    }
Copy the code

For loading UIImageView and UILabel successively, you need to check whether titleLabel exists at setImage

Now that they are exactly the same, it is time to solve the problem of AutoLayout and EdgeInsets.

update2

Create through niB.. Thanks @dreamtrace _Lee for the idea.

1. Check whether the vm is created from niB

    var createdFromNib = false
    
    override init(frame: CGRect) {
        super.init(frame: frame)
    }
    
    required init? (coder aDecoder:NSCoder) {
        super.init(coder: aDecoder)
        createdFromNib = true
    }
Copy the code

2. Overwrite the system implementation function intrinsicContentSize and return the optimal size

    override var intrinsicContentSize: CGSize {
        return bestSize()
    }
    
    func bestSize(a) -> CGSize {
        iftitleLabelIsCreated && ! 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 {returnimageView.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 {
            returnbackgroundImageView.image? .size ??CGSize.zero
        }
    }
Copy the code

3. Determine the layout

    override func layoutSubviews(a) {
        super.layoutSubviews()

        if createdFromNib {
            frame.size = intrinsicContentSize
        }
        ...
   }
Copy the code

4. Test it without 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)
Copy the code

The same is true of AutoLayout and EdgeInsets

update3

IntrinsicContentSize {intrinsicContentSize}}; intrinsicContentSize {intrinsicContentSize}; intrinsicContentSize {intrinsicContentSize};

So the second step is all you need to do in update2, and no other judgment is required.

Interview question 4 network architecture implementation

This question really hits my weak spot. The network and multi-threading are my weakest areas. Now I have a good understanding of threads, but the network is still lacking. Write your own network architecture to improve yourself.

The interview summary

For the two algorithm questions, I do not have what too much to say, skills are not as good as people, but algorithm questions this kind of thing is not very useful in iOS, I do not believe those who have not brushed algorithm questions, in the face of a never seen algorithm questions can easily write the optimal solution. There is the TOPIC of the UI, pit, who will go to put a good ready-made do not, to disgust themselves, but also must be the same… I have asked the interviewer several times what feature they want to do… The answer is only, I don’t care how you write, as long as the same as the system…. Is the product attached….

Ok… Not as good as people, was also suspended for granted… No excuses… Listen to meituan friends said, now only recruit technical experts, other low positions are not recruited… Aye… The penson…

Finally, all the source code for this article is available on Github:

Making Repo: coderZsq. Target. Swift Follow: coderZsq, making Resume: coderZsq. Making. IO/coderZsq. We…

Gold-digging techniques: links to 👉 juejin.cn/post/1