2020 - perception of iOS interview failure

Original author: Castie1
Original link: https://juejin.im/post/6844903591010910216

Daily bullshit

Last July, I interviewed a large company for the first time: are you hungry? I was very excited to receive the call of a large company. I felt that the opportunity to turn over was finally coming. I ran to the interview excitedly, thinking that the topic would be the same as that of the general primary iOS interview. I didn't make any preparation. In fact, I didn't know what to prepare. I remember talking about at that time:

  1. UI: how to avoid frame jamming and asynchronous rendering
  2. Performance: performance optimization, Vsync, CPU / GPU
  3. Network: how to implement request caching strategy
  4. Security: lild re signature, Mach-O
  5. Front end: how to avoid DOM redrawing
  6. Back end: how to balance the load

There are also some extreme cases. I can't remember clearly for a long time. Anyway, the feeling of this interview is, shit... I'm just a piece of garbage ~ at that time, I remember that my architect suggested me to consolidate the basic skills of iOS, and then recommended the basic books: computer network, operating system principle, HTTP authoritative guide, TCP/IP authoritative guide, in-depth analysis of Max OS X & iOS operating system... These books, Apart from the HTTP authoritative guide, I finished reading it with my teeth clenched. For me, it's a Book of heaven. I have indigestion at all

In December last year, I interviewed a large company for the second time: Jingdong. Due to my previous experience, I became very calm. I knew that I would be eliminated by large companies and had an insurmountable natural barrier with excellent majors. To my surprise, I needed to exchange my ID card for temporary access control to enter the building of Jingdong... At that time, the interview questions were much softer than hungry, although I still couldn't answer them at that time

  1. Runtime: isa, message forwarding, 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 iOS interview. Unfortunately, I didn't have this knowledge at that time. It's a pity After that, I studied C + +, ASM and Linux, and also learned some knowledge about MACH-O and reverse, so as to prepare for the interview later

The third time is the second echelon of this Wednesday's interview. I prepared all the interview questions I can prepare, including the underlying principle, reverse security, multithreading and locking, memory layout, UI performance optimization, etc. sure enough, I passed the telephone interview for a full hour, and asked some of the underlying knowledge I had prepared, which made me feel that the opportunity finally came, but... After my on-site interview... All the questions were computer questions

  1. How to design and implement a self-defined callback mechanism for. Body, how to deal with the error of. Body, and how to avoid the error of. Body
  2. Implement UIButton according to UIControl
  3. Find the median of two sorted arrays
  4. Self implementation of pow(double, double) function

Sure enough, the network, UI, algorithm... Well, the first time I did a computer question, I got confused... Then the interviewer kept laughing... Kept laughing... Maybe it was a way for him to be friendly to me... The final interview conclusion was that I had a wide range of knowledge and had done a lot of things, but I was still lack of depth of knowledge

Later, I learned that they recruited the rank of technical expert. I felt that my technical level could not meet the requirements and could not be admitted. Of course, I knew it on the spot. I also felt that the two interview experiences of meituan and hungry were far from my level... However, I just wanted to study in a large company, so I had to be an expert? Now I don't need junior high school senior and senior. Direct experts... My headhunting friend told me that the level of 3-1 is the benchmark of Alibaba P6/P7. I choose to die

With this interview experience, my strategy has also changed. I no longer pursue the aura of large companies. Isn't it good to be happy? Do I have to think like a machine? Living like an algorithm, does it feel like something important is missing? Is it not a happy day to boast with your friends? Do you have to study hard? I think of two words I heard recently. The best product experience is to let users not think. Cognition is pain, ignorance is bliss. People are really contradictory. One thought of values is a thousand miles away

Interview question 1 self realization pow(double, double)

This question is very confused when it comes to the computer. Because the power is double and I don't know how to start at all, the interviewer reduces the difficulty and uses integer

Solution 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
}

Then, the first time I did the algorithm problem, I can only think of the most rough way to solve it, which is a cycle. I also know that this is not the answer expected by the interviewer, but what method is there

Solution 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
}

This is another seemingly better solution 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
}

This is just adding a negative value judgment... But if the power is double, there is still no clue. You need to ask the boss and God for advice

If you are changing jobs or are preparing to change jobs, you might as well use your hands to add our communication group 1012951431 To get a detailed interview information from a large factory and add a guarantee for your job hopping.

Interview question 2 findmediansoortedarrays

This is the original question of LeetCode, but I haven't brushed the algorithm question bank so far... It's also the algorithm question I encountered in my first interview in my life The title means to find the median of two sorted arrays

Solution 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
}

The first time I do an algorithm problem, I can only ignore the complexity of the algorithm. If I can complete it, it's good. What bike do I want

Solution 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
    }
}

This is the answer when I checked the information on the Internet... I haven't figured out what the idea is. Anyway, the interviewer prompted to divide and rule and cut the beginning and end... I don't know whether it is the optimal algorithm

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
}

This is to consult frost God( @Half frost - a wisp of war fluidization hidden half frost )The idea given later is really well realized But frost humbly said it was not the optimal solution

Odd 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))
--- scope of: findMedianSortedArrays ---
500045.0
500045.0
500045.0
Even 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))
--- scope of: findMedianSortedArrays ---
499665.5
499665.5
499665.5
Time consuming comparison
--- scope of: findMedianSortedArrays_1 ---
timing: 2.50845623016357
--- scope of: findMedianSortedArrays_2 ---
timing: 1.28746032714844e-05
--- scope of: findMedianSortedArrays_3 ---
timing: 0.0358490943908691

It can be seen that the answer of searching data online is the algorithm with the highest performance among the three solutions. Frost God's idea is three orders of magnitude worse than the answer online, and what I wrote is five orders of magnitude worse... Sure enough, what I wrote is the most garbage algorithm

Solution 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

The above algorithm is given along the idea of frost God and the tips given by the interviewer, but the order of magnitude of solution 3 is the same

If you are changing jobs or are preparing to change jobs, you might as well use your hands to add our communication group 1012951431 To get a detailed interview information from a large factory and add a guarantee for your job hopping.

Interview question 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 { 

}

The above is the original question during the interview. At the beginning, I didn't know what I was asked to do. I said that I just needed to implement all the above methods, just like implementing my own UIButton... At the beginning, I thought I was asked to implement it with CALayer, which scared me... Fortunately not... Then I wrote a UIImageView and a UILabel according to my usual custom control writing method, Then the layout assignment... I saw the interviewer smile at me and say, do you think this question is so simple... So simple

Then say, you can only create uilabel when you know UIButton setTitle, and UIImageView when you know SETIMAGE. Why do you write the frame to death... Don't you know that UIView has sizeToFit? Why don't you implement sizeThatFits? You can't use it at all... You know that when UIButton uses AutoLayout layout, as long as you set the origin coordinates, the width and height can be adaptive. Why don't you implement it when you customize it? Don't do setBackgroundImage and setImageEdgeInsets. You won't

What I want to say is, who doesn't need to use UIButton when he has nothing to do... Just for a target action design pattern... I keep interrupting when I think about my ideas. Maybe this is a strategy of the interviewer... Forget roast, let's try our best to achieve it

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
        }
    }
}

Although some functions have been realized, there is still no idea about the functions of AutoLayout and EdgeInsets. Please solve your doubts

If you are changing jobs or are preparing to change jobs, you might as well use your hands to add our communication group 1012951431 To get a detailed interview information from a large factory and add a guarantee for your job hopping.

Test comparison

We compare our self - implemented Button with 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()

Here, we see that it is different from the implementation of the system, because I set the bitmap directly in the display instead of adding a new view to the system Such performance consumption will be less... (to modify the following problem)

If you are changing jobs or are preparing to change jobs, you might as well use your hands to add our communication group 1012951431 To get a detailed interview information from a large factory and add a guarantee for your job hopping.

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

If you are changing jobs or are preparing to change jobs, you might as well use your hands to add our communication group 1012951431 To get a detailed interview information from a large factory and add a guarantee for your job hopping.

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

What hasn't been realized is AutoLayout and EdgeInsets. There is a slight difference between the optimal size calculated in sizeToFit and the optimal size of the system. There is also a problem of loading UIImageView and UILabel successively

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

There is a slight difference between the optimal size calculated in sizeToFit and the optimal size of the system. This problem is that the default system font size of UILabel is 17, while the font size of 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
    }

For the problem of loading UIImageView and UILabel successively, you need to judge whether the titleLabel exists when setImage

Now it is exactly the same. The next step is to solve the problems of AutoLayout and EdgeInsets

update2

Create through nib... Thank you @ dream trace_ Lee provides ideas

Implementation method:

1. Judge whether it 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
    }

2. Rewrite the system to implement the function intrinsicContentSize and return the best size

    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. Judge the layout

    override func layoutSubviews() {
        super.layoutSubviews()

        if createdFromNib {
            frame.size = intrinsicContentSize
        }
        ...
   }

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)

The same perfection, conquered AutoLayout, and then EdgeInsets~~~

update3

I've always misunderstood that the method of intrinsicContentSize takes effect after adding constraints. Whether it's nib or manual constraints, it will take effect

Therefore, only the second step needs to be implemented in update2, and no other judgment is required

Interview question 4 network architecture implementation

This question really hits my weakness. Network and multithreading are my weakest points. Now I should have a good understanding of threads, but the network is still lacking. Therefore, I will write a network architecture to improve myself after learning Linux and intensive reading of afnetworking & & sdwebimage in the future

Interview summary

For the two algorithm problems, I don't have much to say. I'm not as skilled as a person, but the algorithm problem is not very useful on iOS. I don't believe that those students who haven't brushed the algorithm problem can write the optimal solution calmly in the face of an algorithm problem they've never seen before There is also the question of UI, pit bar, who will put the ready-made ones well, don't use them, and disgust themselves. It must be the same... I have asked the interviewer several times what function they want to do... The only answer is, I don't care how you write, just the same as the system... Is the product attached

Well... Skills are inferior to people, and it's natural to be hung up... I won't make any excuses... I heard from my friends of meituan that now only technical experts are recruited, and other low-level places are not recruited... Eh... Follow your luck

Finally, all the source codes in this article can be found on github:

GitHub Repo: coderZsq.target.swift
Follow: coderZsq ยท GitHub
Resume: coderzsq.github.io/coderZsq.we...

Data recommendation

If you are changing jobs or are preparing to change jobs, you might as well use your hands to add our communication group 1012951431 To get a detailed interview information from a large factory and add a guarantee for your job hopping.

Tags: iOS Interview

Posted by alvinshaffer on Mon, 02 May 2022 03:32:58 +0300