Получить имя типа производного типа в статическом методе базового класса или расширения Swift - PullRequest
2 голосов
/ 02 апреля 2019

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:

[MT] IBSceneUpdate: [обновление сцены, делегат =] Ошибка Domain = IBMessageChannelErrorDomain Code = 3 "Не удалось связаться с вспомогательным инструментом" UserInfo= {NSLocalizedFailureReason = Агент поднятисключение «NSInternalInconsistencyException»: не удалось загрузить NIB в комплекте: «NSBundle (загружен)» с именем «BaseNibLoadable.Type», IBMessageSendChannelException = Не удалось загрузить NIB в комплекте: «NSBundle (загружен)» с именем «BaseNibLoadable.Type»,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 Ответ

1 голос
/ 02 апреля 2019

Как мне сделать так, чтобы он печатал Торт, а не Обувь?

Изменение

print(Self.nibName)

до

print(type(of:self).nibName)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...