xcode IBOutlet UIView导致当前VC在进行UIUpdates之前冻结

jjjwad0x  于 2023-02-16  发布在  其他
关注(0)|答案(1)|浏览(164)
    • 问题:**

UIView更新导致MainViewController冻结,直到UI更改更新为止。我可以使用dispatchAsync避免MainViewController冻结吗?或者这完全设置错误?
我有一个MainViewController,它有一个通过故事板连接为IBOutlet的UIView。

class MainViewController: UITableViewController {
    @IBOutlet weak var headerView: MettaHeaderView!

     func loadCustomView() {
        DispatchQueue.main.async {
             self.headerView.populateViews()
           }
      }
}

UIView类**的设置如下

class MettaHeaderView: UIView {
    
    //MARK: - Properties
    weak var delegate: MettaTableVC!
    let dataStore = DataStore.shared
    
    
    //MARK: - Outlets
    @IBOutlet weak var cardView: CurvedUIView!
    @IBOutlet weak var dayStack: UIStackView!
    
    @IBOutlet weak var plusBtn: UIButton!
    
    @IBOutlet weak var segmentedControl: UISegmentedControl!
    
    @IBOutlet weak var streakLbl: UILabel!
    
    @IBOutlet weak var todayImg: UIImageView!
    @IBOutlet weak var todayLbl: UILabel!
    
    @IBOutlet weak var yesterdayImg: UIImageView!
    @IBOutlet weak var yesterdayLbl: UILabel!
    
    @IBOutlet weak var twoDayAgoImg: UIImageView!
    @IBOutlet weak var twoDayAgoLbl: UILabel!
    
    @IBOutlet weak var threeDayAgoImg: UIImageView!
    @IBOutlet weak var threeDayAgoLbl: UILabel!
    
    @IBOutlet weak var fourDayAgoImg: UIImageView!
    @IBOutlet weak var fourDayAgoLbl: UILabel!
    
    @IBOutlet weak var fiveDayAgoImg: UIImageView!
    @IBOutlet weak var fiveDayAgoLbl: UILabel!
    
    @IBOutlet weak var sixDayAgoImg: UIImageView!
    @IBOutlet weak var sixDayAgoLbl: UILabel!
    
    
    
    
    //MARK: - Override Methods
    override func layoutMarginsDidChange() {
        super.layoutMarginsDidChange()
        self.layoutIfNeeded()
    }
    
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        self.endEditing(true)
    }
    

    
    //MARK: - Methods
    func initializeHeader(with delegate: MettaTableVC) {
        self.delegate = delegate
        styleCardView()
        let font = UIFont.systemFont(ofSize: 12)
        let selectedFont = UIFont.systemFont(ofSize: 12, weight: .medium)
        segmentedControl.setTitleTextAttributes([NSAttributedString.Key.font: font],
                                                for: .normal)
        segmentedControl.setTitleTextAttributes([NSAttributedString.Key.font: selectedFont],
                                                for: .selected)
    }
    
    func styleCardView() {
        self.layoutIfNeeded()
        self.layoutSubviews()
        cardView.curvedPercent = 0.17
        setFontSize()
    }
    
    func populateViews() {
        let totalDays = self.totalDays()
        let dayString = totalDays == 1 ? "Day" : "Days"
        self.streakLbl.text = "\(totalDays) \(dayString) with a Session"
        self.setDayLbls()
        self.setDayImages(with: dataStore.sessions)
    }
    
    func totalDays() -> Int {
        let grouped = dataStore.sessions.group { $0.dateString }
        
        return grouped.count
    }
    
    func setStreak(with sessions: [MeditationSession]) {
        streakLbl.text = "\(currentStreak(from: sessions)) day streak"
    }
    
    func currentStreak(from sessions: [MeditationSession]) -> Int {
        var streak = 0
        var lastDate: Date?
        let formatter = DateFormatter()
        formatter.dateFormat = "MM/dd/yyyy"

        for sesh in sessions {
            let date = sesh.date.dateValue()
            
            // Check if first day check complete yet
            if let last = lastDate {
                let difference = daysBetween(start: date, end: last)
                // Check if the same day
                if difference == 0 {
                    continue
                }
                // Check if day before
                if difference == 1 {
                    lastDate = date
                    streak += 1
                } else {
                    return streak
                }
            // If first go through
            } else {
                let difference = daysBetween(start: date, end: Date())
                // Check if today
                if difference == 0 {
                    lastDate = date
                    streak += 1
                    continue
                }
                // Check if day before
                if difference == 1 {
                    lastDate = date
                    streak += 1
                } else {
                    return streak
                }
            }
        }
        return streak
    }
    
    func daysBetween(start: Date, end: Date) -> Int {
        let cal = Calendar(identifier: .gregorian)
        let date1 = cal.startOfDay(for: start)
        let date2 = cal.startOfDay(for: end)
        
        return Calendar.current.dateComponents([.day], from: date1, to: date2).day!
    }
    
    func setDayLbls() {
        let lbls: [UILabel] = [sixDayAgoLbl, fiveDayAgoLbl, fourDayAgoLbl, threeDayAgoLbl, twoDayAgoLbl, yesterdayLbl, todayLbl]
        let formatter = DateFormatter()
        formatter.dateFormat = "EEEE"
        let todayString = formatter.string(from: Date())
        guard let today = Day(rawValue: todayString.lowercased()) else { return }
        let week = past7Days(from: today)
        
        for (index, val) in week.enumerated() {
            lbls[index].text = val
        }
    }
    
    func setFontSize() {
        let labels: [UILabel] = [sixDayAgoLbl, fiveDayAgoLbl, fourDayAgoLbl, threeDayAgoLbl, twoDayAgoLbl, yesterdayLbl, todayLbl]
        labels.forEach {
            let size: CGFloat = ($0.superview?.frame.width)! * 0.42
            $0.font = $0.font.withSize(size)
        }
    }
    
    func past7Days(from day: Day) -> [String] {
        var dayStrings: [String] = []
        var currentIndex: Int = day.order
        let days = Day.allCasesOrdered
        
        for _ in 0..<7 {
            print("here")
            let day = days[currentIndex]
            dayStrings.append(day.letter)
            if currentIndex > 0 {
                currentIndex -= 1
            } else {
                currentIndex = 6
            }
        }
        
        return dayStrings.reversed()
    }
    
    func setDayImages(with sessions: [MeditationSession]) {
        let dayImgViews: [UIImageView] = [todayImg, yesterdayImg, twoDayAgoImg, threeDayAgoImg, fourDayAgoImg, fiveDayAgoImg, sixDayAgoImg]
        var date: Date = Date()
        
        for index in 0...6 {
            print(index)
            let filtered = sessions.filter { $0.dateString == date.dateString() }
            dayImgViews[index].image = filtered.count == 0 ? #imageLiteral(resourceName: "Lotus_Monochromatic") : #imageLiteral(resourceName: "Lotus")
            
            date = Calendar.current.date(byAdding: .day, value: -1, to: date)!
        }
    }

在MainViewController中调用下面的函数会冻结整个VC,直到函数完成。有什么方法可以避免此问题或修复此问题吗?
自定义标题视图填充视图()

    • 冻结:**

这意味着整个屏幕将被冻结,直到该功能完成。
所以我发现这个问题是因为这个功能,但我不确定为什么会发生冻结:

func setDayImages(with sessions: [MeditationSession]) {
        let dayImgViews: [UIImageView] = [headerView.todayImg, headerView.yesterdayImg, headerView.twoDayAgoImg, headerView.threeDayAgoImg, headerView.fourDayAgoImg, headerView.fiveDayAgoImg, headerView.sixDayAgoImg]
        var date: Date = Date()
        
        for index in 0...6 {
            print(index)
            let filtered = sessions.filter { $0.dateString == date.dateString() }
            dayImgViews[index].image = filtered.count == 0 ? #imageLiteral(resourceName: "Lotus_Monochromatic") : #imageLiteral(resourceName: "Lotus")
            
            date = Calendar.current.date(byAdding: .day, value: -1, to: date)!
        }
    }
vsaztqbk

vsaztqbk1#

func setDayImages(with sessions: [MeditationSession])末尾概述的函数将图像插入UIImageViews,这意味着需要将每个图像作为位图加载到内存中,这是一个相当繁重的操作,您将在MainViewController的主线程上运行它。
我的解决方案是在主线程外将图像加载到UIImage()中,然后在主线程上对其进行赋值,看看这是否能提高性能,通常建议使用GCD在主线程外执行与UI无关的计算(例如DispatchQueue.global(.userInitiated).async)。
这是我最好的猜测,至少没有额外的性能诊断。

相关问题