【问题标题】:Get the type name of derived type in a static method of base class or extension Swift在基类或扩展Swift的静态方法中获取派生类型的类型名称
【发布时间】:2019-08-23 04:48:14
【问题描述】:

TL:DR 将此粘贴到 Swift Playground 中:

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 : 'NSBundle (loaded)' with name 'BaseNibLoadable.Type', IBMessageSendChannelException=Could not load NIB in bundle: 'NSBundle (loaded)' with name 'BaseNibLoadable.Type', NSLocalizedDescription=Failed to communication with helper tool}

例子:

@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,实际的具体视图类名称就在那里。

【问题讨论】:

  • @matt 好的,让我重新讨论一下我再次链接到的答案。我想做的是使用 xibs 构建视图,然后将这些视图添加到其他故事板并让 IB 呈现 UI,而不是空白视图。这意味着此特定代码在应用程序运行时不会运行,它仅由界面构建器运行,试图呈现我的视图。
  • 所以你需要在你的应用中添加 SomeHeader.xib、SomeHeader.swift 和 OtherStoryboard.storyboard。然后,您将在情节提要的某处添加一个 UIView。然后您将该视图的类名更改为 SomeHeader - 瞧,您会在 IB 中看到您的标题。
  • 如果我将样板代码放入 Someheader 文件(例如删除 BaseNibLoadable),这完全可以正常工作。现在我只是想摆脱样板。
  • 好的,所以这就像一个 IBDesignable 视图?
  • @matt 正确。让我更新问题中的代码。

标签: ios swift storyboard xib ibdesignable


【解决方案1】:

如何让它打印蛋糕,而不是鞋子?

改变

print(Self.nibName)

print(type(of:self).nibName)

【讨论】:

  • 实际上,我蹩脚的答案只适用于调试符号,当我上传到 testflight 时,应用程序崩溃了。您的解决方案无处不在,而且它实际上是正确的。太感谢了! (可惜 Stack 没有 reddit 的“赠送金币”)
  • 谢谢,但如果没有您的提炼,我无法做到这一点,这也是很多工作。我们一起解决了!
猜你喜欢
  • 2011-03-05
  • 2021-11-10
  • 2011-07-22
  • 2013-01-10
  • 2010-11-25
  • 1970-01-01
  • 1970-01-01
  • 2023-04-09
  • 2015-03-30
相关资源
最近更新 更多