Пользовательский @IBDesignable UIButton приводит к сбою Xcode

#ios #swift #xcode #uibutton #ibdesignable

#iOS #swift #xcode #uibutton #ibdesignable

Вопрос:

Я хотел создать округлую кнопку с тенью для моего проекта iOS в Swift. Итак, я придумал следующий пользовательский класс кнопок:

 import UIKit

@IBDesignable class MainButton: UIButton {
    private var shadowLayer: CAShapeLayer!
    
    override init(frame: CGRect) {
        super.init(frame: frame)
    }
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        
        let image = createBackgroundImage()
        setBackgroundImage(image, for: UIControl.State.normal)
        clipsToBounds = true
        
        contentEdgeInsets = UIEdgeInsets(top: 5, left: 20, bottom: 5, right: 20)
        
        layer.masksToBounds = false
        layer.shadowColor = UIColor.black.cgColor
        layer.shadowOffset = CGSize(width: 0, height: 3)
        layer.shadowOpacity = 0.2
        layer.shadowRadius = 6
    }
    
    func createBackgroundImage() -> UIImage {
        let rect = CGRect(x: 0, y: 0, width: frame.width, height: frame.height)
        UIGraphicsBeginImageContextWithOptions(frame.size, false, 0)
        let color = UIColor.white
        color.setFill()
        UIBezierPath(roundedRect: rect, cornerRadius: frame.height * 0.5).addClip()
        color.setFill()
        UIRectFill(rect)
        let image: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
        UIGraphicsEndImageContext()
        return image
    }
}
  

Как только я устанавливаю этот класс для кнопки в моей раскадровке, процесс «IBDEsignablesAgent-iOS» занимает почти 100% моего процессора, и Xcode зависает сам. Такое поведение делает практически невозможным корректную отладку проблемы.

Я совершенно уверен, что делаю что-то в неправильном порядке или неправильным методом. Но я понятия не имею, как это решить. Надеюсь, кто-нибудь здесь сможет указать мне правильное направление.

Спасибо, Йенс

Комментарии:

1. Вы пытались Instruments -> TimeProfiler ?

2. layoutSubviews вызывается часто (десятки раз в секунду). Вы не должны выполнять никаких настроек (определенно не устанавливать изображения). Если вы хотите что-то там настроить, это должно быть связано с размером представления, и вы должны проверить, действительно ли размер изменился. В противном случае ваши изменения просто приведут к созданию нового макета.

Ответ №1:

Просто проверьте, действительно ли изменился размер представления:

 private var lastSize: CGSize = .zero

override func layoutSubviews() {
   super.layoutSubviews()

   guard frame.size != lastSize else { return }

   lastSize = frame.size

   ...
}
  

Создание теней происходит медленно и layoutSubviews вызывается десятки раз в секунду (в основном, один раз в каждом кадре).

Ответ №2:

Моя пользовательская кнопка с некоторой тенью и закругленными углами, я использую ее непосредственно в раскадровке, нет необходимости касаться ее программно.

 class RoundedCornerButtonWithShadow: UIButton {
    override func awakeFromNib() {
        super.awakeFromNib()
        self.layer.masksToBounds = false
        self.layer.cornerRadius = self.frame.height/2
        self.layer.shadowColor = UIColor.black.cgColor
        self.layer.shadowPath = UIBezierPath(roundedRect: self.bounds, cornerRadius: self.layer.cornerRadius).cgPath
        self.layer.shadowOffset = CGSize(width: 0.0, height: 3.0)
        self.layer.shadowOpacity = 0.5
        self.layer.shadowRadius = 1.0
    }
}
  

Комментарии:

1. не будет работать, если вы динамически меняете размер кнопки, например, меняете заголовок.