在基类或扩展Swift

时间:2019-04-01 23:33:35

标签: ios swift storyboard xib ibdesignable

TL:DR 将此粘贴到Swift游乐场:

import UIKit

public protocol NibLoadable {
    static var nibName: String { get }
}

extension NibLoadable where Self: UIView {
    public static var nibName: String {
        return String(describing: self)
    }

    func printName(){
        print(Self.nibName)
    }
}

public class Shoes: UIView, NibLoadable {


    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        printName()
    }

    override init(frame: CGRect) {
        super.init(frame: frame)
        printName()
    }
}

public class Cake: Shoes {

}

let cake = Cake() // this line prints 'Shoes'

如何使它打印Cake,而不是Shoes

完整说明:

我发现了将xib文件加载到情节提要中的方法,如下所示: https://stackoverflow.com/a/47295926/2057955

这很棒,但是我必须像这样将样板NibLoadable代码放到每个视图中:

required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setupFromNib()
    }

    override init(frame: CGRect) {
        super.init(frame: frame)
        setupFromNib()
    }

当您以这种方式获得20-30个视图时,这显然很烦人。

所以我正在尝试建立一个可以解决这个问题的基类,然后让所有内容都继承它。

不幸的是,无论我尝试了什么,String(describing: Self.self)总是返回我的基类的名称,而不是派生类的名称。

当我在XCode中打开Storyboard时,在控制台日志中出现此异常:

  

[MT] IBSceneUpdate:[场景更新,委托=]错误域= IBMessageChannelErrorDomain代码= 3“无法与帮助工具通信” UserInfo = {NSLocalizedFailureReason =该代理引发了“ NSInternalInconsistencyException”异常:无法在捆绑包中加载NIB :名称为“ BaseNibLoadable.Type”的“ NSBundle(已加载)”,IBMessageSendChannelException =无法在捆绑包中加载名称为“ BaseNibLoadable.Type”的“ NSBundle(已加载)”,NSLocalizedDescription =无法与帮助工具通信}

示例:

@IBDesignable
class BaseNibLoadable: UIView, NibLoadable {
    // MARK: - NibLoadable
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setupFromNib()
    }

    override init(frame: CGRect) {
        super.init(frame: frame)
        setupFromNib()
    }
}
@IBDesignable
class SomeHeader: BaseNibLoadable {

    @IBOutlet fileprivate weak var headerLabel: UILabel!
    @IBInspectable var header: String? {
        didSet {
            self.headerLabel.text = header
        }
    }
}

很明显,我的主捆绑包(两者都同一个捆绑包)包括SomeHeader.xib文件。

所以我要寻找的是以某种方式获得在nibName静态方法中实例化的实际类型的名称。

更新 根据要求,这是我在问题顶部链接的原始答案(相反,因为它很长,所以仅提供其中的代码,否则...请点击链接):

public protocol NibLoadable {
    static var nibName: String { get }
}

public extension NibLoadable where Self: UIView {

    public static var nibName: String {
        return String(describing: Self.self) // defaults to the name of the class implementing this protocol.
    }

    public static var nib: UINib {
        let bundle = Bundle(for: Self.self)
        return UINib(nibName: Self.nibName, bundle: bundle)
    }

    func setupFromNib() {
        guard let view = Self.nib.instantiate(withOwner: self, options: nil).first as? UIView else { fatalError("Error loading \(self) from nib") }
        addSubview(view)
        view.translatesAutoresizingMaskIntoConstraints = false
        view.leadingAnchor.constraint(equalTo: self.safeAreaLayoutGuide.leadingAnchor, constant: 0).isActive = true
        view.topAnchor.constraint(equalTo: self.safeAreaLayoutGuide.topAnchor, constant: 0).isActive = true
        view.trailingAnchor.constraint(equalTo: self.safeAreaLayoutGuide.trailingAnchor, constant: 0).isActive = true
        view.bottomAnchor.constraint(equalTo: self.safeAreaLayoutGuide.bottomAnchor, constant: 0).isActive = true
    }
}

更新2

我确实知道子类当时肯定在堆栈中,因为如果我登录Thread.callStackSymbols,则实际的具体视图类名称在那里。

1 个答案:

答案 0 :(得分:1)

  

我该如何打印蛋糕而不是鞋子?

更改

print(Self.nibName)

print(type(of:self).nibName)