0

I used Time Profile to check what caused my app to become very stutter and stutter when quick change the pageiwController's page, and it detects that layout events take many CPU and Thread usage (pls see below 'pic'), it costs Max 182% CPU and Max 96% Thread resources, it must be unreasonable. they are system events, how can i optimize them?

Thank you very much in advance!

enter image description here

code snippet 1: archors

private func aulayoutViews() {
    view.addSubview(pageControl)
    view.addSubview(navigationBar)

    //MARK: navigationBar
    PageViewController.navigationBarHeight = 44

    navigationBar.translatesAutoresizingMaskIntoConstraints = false
    navigationBar.widthAnchor.constraint(equalToConstant: self.view.frame.width).isActive = true
    navigationBar.heightAnchor.constraint(equalToConstant: PageViewController.navigationBarHeight).isActive = true
    navigationBar.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: 0).isActive = true

    if #available(iOS 11.0, *) {
        navigationBar.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor, constant: 0).isActive = true
    } else {
        navigationBar.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 20).isActive = true
    }

    //MARK: pageControl
    PageViewController.pageControlHeight = 10

    pageControl.translatesAutoresizingMaskIntoConstraints = false
    pageControl.widthAnchor.constraint(equalToConstant: self.view.frame.width).isActive = true
    pageControl.heightAnchor.constraint(equalToConstant: PageViewController.pageControlHeight).isActive = true
    pageControl.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: 0).isActive = true
    pageControl.topAnchor.constraint(equalTo: self.navigationBar.bottomAnchor, constant: 0).isActive = true
}

code snippet 2: mainly stack view impelmentaion

 private func layoutViews() {
    var updateTimeX: CGFloat = CGFloat()
    var updateTimeY: CGFloat = CGFloat()

    switch iPhoneType {
    case .iPhoneSE:
        updateTimeX = 0
        updateTimeY = 0
    case .iPhone:
        updateTimeX = 0
        updateTimeY = 8
    case .iPhonePlus:
        updateTimeX = 4
        updateTimeY = 8
    default: //case .iPhoneX:
        updateTimeX = 0
        updateTimeY = 8
    }

    //MARK: updateTime的autolayout
    self.view.addSubview(updateTime)
    updateTime.translatesAutoresizingMaskIntoConstraints = false
    updateTime.topAnchor.constraint(equalTo:  self.view.layoutMarginsGuide.topAnchor, constant: updateTimeY).isActive = true

    NSLayoutConstraint.activate(NSLayoutConstraint.constraints(
        withVisualFormat: "H:|-updateTimeX-[updateTime]",
        options: [],
        metrics: ["updateTimeX": updateTimeX],
        views: ["updateTime": updateTime]))

    self.view.addSubview(stackView)
    stackView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor).isActive = true

    NSLayoutConstraint.activate(NSLayoutConstraint.constraints(
        withVisualFormat: "H:|[stackView]-16-|",
        options: [],
        metrics: nil,
        views: ["stackView": stackView]))

    stackView.translatesAutoresizingMaskIntoConstraints = false
    stackView.addArrangedSubview(contentStackView)
    stackView.addArrangedSubview(buttonAQIStackView)
    stackView.axis = .vertical
    stackView.alignment = .leading
    stackView.distribution = .fill
    stackView.spacing = 8

    contentStackView.translatesAutoresizingMaskIntoConstraints = false
    contentStackView.addArrangedSubview(tempWeatherStackView)
    contentStackView.addArrangedSubview(sunWindHumidityStackView)
    contentStackView.axis = .vertical
    contentStackView.alignment = .leading
    contentStackView.distribution = .fill
    contentStackView.spacing = -16

    tempWeatherStackView.translatesAutoresizingMaskIntoConstraints = false
    tempWeatherStackView.addArrangedSubview(currentTemp)
    tempWeatherStackView.addArrangedSubview(currentWeather)
    tempWeatherStackView.axis = .horizontal
    tempWeatherStackView.alignment = .firstBaseline
    tempWeatherStackView.distribution = .fill
    tempWeatherStackView.spacing = -32

    sunWindHumidityStackView.translatesAutoresizingMaskIntoConstraints = false
    sunWindHumidityStackView.addArrangedSubview(sunTime)
    sunWindHumidityStackView.addArrangedSubview(wind)
    sunWindHumidityStackView.addArrangedSubview(humidity)
    sunWindHumidityStackView.axis = .horizontal
    sunWindHumidityStackView.alignment = .top
    sunWindHumidityStackView.distribution = .fill
    sunWindHumidityStackView.spacing = 8

    weatherButton.translatesAutoresizingMaskIntoConstraints = false
    weatherButton.heightAnchor.constraint(equalToConstant: 24).isActive = true

    AQIButton.translatesAutoresizingMaskIntoConstraints = false
    AQIButton.heightAnchor.constraint(equalToConstant: 24).isActive = true

    buttonAQIStackView.translatesAutoresizingMaskIntoConstraints = false
    buttonAQIStackView.addArrangedSubview(weatherButton)
    buttonAQIStackView.addArrangedSubview(AQIButton)
    buttonAQIStackView.axis = .horizontal
    buttonAQIStackView.alignment = .fill
    buttonAQIStackView.distribution = .fill
    buttonAQIStackView.spacing = 8
}

code snippet 3: stack view & constrains

private func layoutViews() {
    var iconImageSize: CGFloat = CGFloat()
    var stackWidth: CGFloat = CGFloat()
    var scrollHeight: CGFloat = CGFloat()
    var stackViewWidth: CGFloat = CGFloat()

    switch iPhoneType {
    case .iPhoneSE:
        iconImageSize = 29
        stackWidth = 79.5
        scrollHeight = 980
        stackViewWidth = stackWidthCalculateBy(stackWidth, totalStackQty: 16, sceneStackQty: 6, sceneSpacing: 16)
    case .iPhone:
        iconImageSize = 32
        stackWidth = 92
        scrollHeight = 109.76
        stackViewWidth = stackWidthCalculateBy(stackWidth, totalStackQty: 16, sceneStackQty: 6, sceneSpacing: 16)
    case .iPhonePlus:
        iconImageSize = 32
        stackWidth = 96
        scrollHeight = 122.24
        stackViewWidth = stackWidthCalculateBy(stackWidth, totalStackQty: 16, sceneStackQty: 6, sceneSpacing: 16)
    default: //case .iPhoneX:
        iconImageSize = 32
        stackWidth = 92
        scrollHeight = 109.76
        stackViewWidth = stackWidthCalculateBy(stackWidth, totalStackQty: 16, sceneStackQty: 6, sceneSpacing: 16)
    }

    //MARK: stackView
    scrollView.addSubview(stackView)
    stackView.translatesAutoresizingMaskIntoConstraints = false

    stackView.axis = .horizontal
    stackView.alignment = .fill
    stackView.distribution = .equalSpacing

    NSLayoutConstraint.activate(NSLayoutConstraint.constraints(
        withVisualFormat: "V:|[stackView(scrollHeight)]|",
        options: [],
        metrics: ["scrollHeight": scrollHeight],
        views: ["stackView": stackView]))

    NSLayoutConstraint.activate(NSLayoutConstraint.constraints(
        withVisualFormat: "H:|[stackView(stackViewWidth)]|",
        options: [],
        metrics: ["stackViewWidth": stackViewWidth],
        views: ["stackView": stackView]))

    for index in 0...ix {
        tempStackView[index].addArrangedSubview(highTempLabel[index])
        tempStackView[index].addArrangedSubview(lowTempLabel[index])

        tempStackView[index].translatesAutoresizingMaskIntoConstraints = false
        tempStackView[index].axis = .vertical
        tempStackView[index].alignment = .fill
        tempStackView[index].distribution = .fillEqually

        iconImage[index].translatesAutoresizingMaskIntoConstraints = false
        iconImage[index].widthAnchor.constraint(equalToConstant: iconImageSize).isActive = true
        iconImage[index].heightAnchor.constraint(equalToConstant: 62).isActive = true
        iconImage[index].contentMode = .scaleAspectFit

        iconTempStackView[index].addArrangedSubview(iconImage[index])
        iconTempStackView[index].addArrangedSubview(tempStackView[index])

        iconTempStackView[index].translatesAutoresizingMaskIntoConstraints = false
        iconTempStackView[index].axis = .horizontal
        iconTempStackView[index].alignment = .fill
        iconTempStackView[index].distribution = .fill

        weekLabel[index].setContentHuggingPriority(UILayoutPriority(rawValue: 249), for: .horizontal)
        weekDateStackView[index].addArrangedSubview(weekLabel[index])
        weekDateStackView[index].addArrangedSubview(dateLabel[index])

        weekDateStackView[index].translatesAutoresizingMaskIntoConstraints = false
        weekDateStackView[index].axis = .horizontal
        weekDateStackView[index].alignment = .fill
        weekDateStackView[index].distribution = .fill
        weekDateStackView[index].spacing = 8

        contentStackView[index].widthAnchor.constraint(equalToConstant: stackWidth).isActive = true
        contentStackView[index].addArrangedSubview(weekDateStackView[index])
        contentStackView[index].addArrangedSubview(iconTempStackView[index])
        contentStackView[index].addArrangedSubview(weatherLabel[index])

        contentStackView[index].translatesAutoresizingMaskIntoConstraints = false
        contentStackView[index].axis = .vertical
        contentStackView[index].alignment = .fill
        contentStackView[index].distribution = .equalSpacing

        stackView.addArrangedSubview(contentStackView[index])
    }

    //MARK: scrollView
    view.addSubview(scrollView)
    scrollView.translatesAutoresizingMaskIntoConstraints = false

    NSLayoutConstraint.activate(NSLayoutConstraint.constraints(
        withVisualFormat: "H:|[scrollView]|",
        options: [],
        metrics: nil,
        views: ["scrollView": scrollView]))

    NSLayoutConstraint.activate(NSLayoutConstraint.constraints(
        withVisualFormat: "V:[scrollView(scrollHeight)]|",
        options: [],
        metrics: ["scrollHeight": scrollHeight],
        views: ["scrollView": scrollView]))
}
stephen
  • 519
  • 6
  • 22
  • 1
    You probably need to post more.... Code? Explanation? IB? Exactly **what** is a user doing (and please, include what code is being executed) when things "stutter"? For instance, today I've moved some `UIKit` code that created a new `CIImage` mask based on `UISlider` changes that relate to a color change into GLSL code inside a `CIKernel`. I understand, my issue isn't anything *like* your's, but that still leaves the question for you - what can *you* tell *me* so that I can reproduce whatever issue is causing your stuttering? –  Jan 28 '18 at 04:54
  • @dfd There’s no special for layout code, i put all layout relevant codes in one method for each different view controller class, and the main purpose for the method are: first add subviews, second auto layout subviews. The way used to layout views are anchor, stack view and constraints. Please see codes updated in the question description (PS: others that not showing are very similar to above). – stephen Jan 30 '18 at 13:43
  • @dfd All subviews will added to a scroll view’s content subview, after that the scroll view will be added to a content viewController’s view, which act as the PageViewController’s page. In such a way, the user can not just swipe left and right to see different aspect of information, but also swift up and down to see more information. – stephen Jan 30 '18 at 13:44
  • Not much jumps out at me. Two years ago I used a page view and scroll view, and my auto layout was (a) totally in code and (b) solely using anchor syntax. So first, I noted that you "mix" anchors and visual layout language - but I don't think that should be much of an issue. But is it possible that you simply have *too* much happening in a root view? Subviews with layout, stack views with layout, then a loop (`for index in 0...ix`) that adds even more constraints? I'd consider two things... (1) `UIStackViews` are made to reduce constraints and (2) break things up with a navigation controller. –  Jan 30 '18 at 15:14

0 Answers0