tvOS 14 UIBlurEffect crash

I have in my project different code which is responsible for the blur effect in my app. In tvOS 13 this worked fine but in tvOS 14 I have to remove the code otherwise the app will crash. What exactly do I have to change in the code to make it run on tvOS 14. Thanks for the help.

Code Block
private func sharedSetup(effect: UIBlurEffect, radius: CGFloat = 90) {
let UICustomBlurEffect = NSClassFromString("_UICustomBlurEffect") as! UIBlurEffect.Type
let raw = effect.value(forKey: "_style") as! Int
let style = UIBlurEffect.Style(rawValue: raw)!
let effect = UICustomBlurEffect.init(style: style)
effect.setValue(1.0, forKey: "scale")
effect.setValue(radius, forKey: "blurRadius")
effect.setValue(UIColor.clear, forKey: "colorTint")
self.blurEffect = effect
}

Answered by janapple in 700854022

With the following code it works in tvOS 14 and higher:

import UIKit

@IBDesignable class VisualEffect: UIVisualEffectView {
    var _blurRadius: CGFloat = 90
    var _style: UIBlurEffect.Style = .dark

    @IBInspectable var blurRadius: CGFloat {
        get {
            return _blurRadius
        } set (radius) {
            if(_blurRadius != radius) {
                _blurRadius = radius
                if #available(tvOS 14.0, *) {
                    let neweffect = BlurEffektView.effect(with: _style)
                    neweffect.blurRadius = blurRadius
                    effect = neweffect
                    blurEffect = neweffect}
            } else {
                blurEffect.setValue(radius, forKey: "blurRadius")
            }
        }
    }

    /// Blur effect for tvOS >= 14
    private lazy var customBlurEffect_tvOS14: BlurEffektView = {
        let effect = BlurEffektView.effect(with: .dark)

        effect.blurRadius = blurRadius
        return effect
    }()

    /// Blur effect for tvOS < 14
    private lazy var customBlurEffect: UIBlurEffect = {
        return (NSClassFromString("_UICustomBlurEffect") as! UIBlurEffect.Type).init()
    }()

    private var blurEffect: UIBlurEffect!

    override init(effect: UIVisualEffect?) {
        guard let effect = effect as? UIBlurEffect else {
            fatalError("Effect must be of class: UIBlurEffect")
        }
        super.init(effect: effect)
        sharedSetup(effect: effect)
        self.effect = blurEffect
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        var effect: UIBlurEffect

        if #available(tvOS 14.0, *) {
            effect = customBlurEffect_tvOS14
        } else {
            effect = customBlurEffect
        }
        sharedSetup(effect: effect)
        self.effect = blurEffect
    }

    private func sharedSetup(effect: UIBlurEffect, radius: CGFloat = 90) {
        let raw = effect.value(forKey: "_style") as! Int
        let style = UIBlurEffect.Style(rawValue: raw)!

        if #available(tvOS 14.0, *) {
            let newEffect = BlurEffektView.effect(with: style)
            newEffect.blurRadius = blurRadius
            let subviewClass = NSClassFromString("_UIVisualEffectSubview") as? UIView.Type
            let visualEffectSubview: UIView? = self.subviews.filter({ type(of: $0) == subviewClass }).first
            visualEffectSubview?.backgroundColor = UIColor.clear
            self.blurEffect = newEffect
        } else {
            let UICustomBlurEffect = NSClassFromString("_UICustomBlurEffect") as! UIBlurEffect.Type
            let newEffect = UICustomBlurEffect.init(style: style)
            newEffect.setValue(1.0, forKey: "Scale")
            newEffect.setValue(radius, forKey: "blurRadius")
            newEffect.setValue(UIColor.clear, forKey: "colorTint")
            self.blurEffect = newEffect
        }
    }
}
I have the same issue. I think it's because this is an undocumented way of doing that.
Accepted Answer

With the following code it works in tvOS 14 and higher:

import UIKit

@IBDesignable class VisualEffect: UIVisualEffectView {
    var _blurRadius: CGFloat = 90
    var _style: UIBlurEffect.Style = .dark

    @IBInspectable var blurRadius: CGFloat {
        get {
            return _blurRadius
        } set (radius) {
            if(_blurRadius != radius) {
                _blurRadius = radius
                if #available(tvOS 14.0, *) {
                    let neweffect = BlurEffektView.effect(with: _style)
                    neweffect.blurRadius = blurRadius
                    effect = neweffect
                    blurEffect = neweffect}
            } else {
                blurEffect.setValue(radius, forKey: "blurRadius")
            }
        }
    }

    /// Blur effect for tvOS >= 14
    private lazy var customBlurEffect_tvOS14: BlurEffektView = {
        let effect = BlurEffektView.effect(with: .dark)

        effect.blurRadius = blurRadius
        return effect
    }()

    /// Blur effect for tvOS < 14
    private lazy var customBlurEffect: UIBlurEffect = {
        return (NSClassFromString("_UICustomBlurEffect") as! UIBlurEffect.Type).init()
    }()

    private var blurEffect: UIBlurEffect!

    override init(effect: UIVisualEffect?) {
        guard let effect = effect as? UIBlurEffect else {
            fatalError("Effect must be of class: UIBlurEffect")
        }
        super.init(effect: effect)
        sharedSetup(effect: effect)
        self.effect = blurEffect
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        var effect: UIBlurEffect

        if #available(tvOS 14.0, *) {
            effect = customBlurEffect_tvOS14
        } else {
            effect = customBlurEffect
        }
        sharedSetup(effect: effect)
        self.effect = blurEffect
    }

    private func sharedSetup(effect: UIBlurEffect, radius: CGFloat = 90) {
        let raw = effect.value(forKey: "_style") as! Int
        let style = UIBlurEffect.Style(rawValue: raw)!

        if #available(tvOS 14.0, *) {
            let newEffect = BlurEffektView.effect(with: style)
            newEffect.blurRadius = blurRadius
            let subviewClass = NSClassFromString("_UIVisualEffectSubview") as? UIView.Type
            let visualEffectSubview: UIView? = self.subviews.filter({ type(of: $0) == subviewClass }).first
            visualEffectSubview?.backgroundColor = UIColor.clear
            self.blurEffect = newEffect
        } else {
            let UICustomBlurEffect = NSClassFromString("_UICustomBlurEffect") as! UIBlurEffect.Type
            let newEffect = UICustomBlurEffect.init(style: style)
            newEffect.setValue(1.0, forKey: "Scale")
            newEffect.setValue(radius, forKey: "blurRadius")
            newEffect.setValue(UIColor.clear, forKey: "colorTint")
            self.blurEffect = newEffect
        }
    }
}
tvOS 14 UIBlurEffect crash
 
 
Q