InterfaceBuilder

时间:2016-03-02 01:14:20

标签: ios swift2

我有一个通用的UIViewController子类,它期望一个类型是UIView的子类,并且还实现了一个特定的协议。我有一个通用的UIViewController子类的子类。我在故事板中有一个视图控制器,它的类型设置为MyKeyboardAwareScrollViewController(通用UIViewController子类的子类)。当我运行我的程序时,我收到一条消息: Unknown class _TtC19ExploreCodeCoverage35MyKeyboardAwareScrollViewController in Interface Builder file.

任何想法为什么/如何解决?

协议:

protocol MyProtocol{
    func widgets() -> Void
    func activeView() -> UIView?
}

通用视图控制器子类(需要一个实现协议MyProtocol的UIView类型):

class KeyboardAwareScrollViewController<T:UIView where T:MyProtocol>: UIViewController {
    private let titleView: UIView
    private let contentView: T

    private weak var scrollView: UIScrollView?
    private weak var titleViewContainer: UIView?


    init(titleView:UIView, contentView: T){
        self.titleView = titleView
        self.contentView = contentView
        super.init(nibName: nil, bundle: nil)
    }

    required init?(coder aDecoder: NSCoder) {
        self.titleView = aDecoder.decodeObjectOfClass(UIView.self, forKey: "titleView")!
        self.contentView = aDecoder.decodeObjectOfClass(T.self, forKey: "contentView")!
        super.init(coder: aDecoder)
    }

    override func viewWillAppear(animated: Bool) {
        NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardShown:", name: UIKeyboardWillShowNotification, object: nil)
        NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardHidden:", name: UIKeyboardWillHideNotification, object: nil)
    }

    override func viewWillDisappear(animated: Bool) {
        NSNotificationCenter.defaultCenter().removeObserver(self)
    }

    func keyboardShown(notification: NSNotification){
        let kbSize = (notification.userInfo![UIKeyboardFrameEndUserInfoKey] as! NSValue).CGRectValue()

        if let scrollView = scrollView{
            let insets = UIEdgeInsets(top: 0.0, left: 0.0, bottom: kbSize.height, right: 0.0)
            scrollView.contentInset = insets
            scrollView.scrollIndicatorInsets = insets

            if let activeField = self.contentView.activeView(){
                let convertedFrame = scrollView.convertRect(activeField.superview!.bounds, fromView: activeField.superview!)
                let offsetFrame = CGRectOffset(convertedFrame, 0.0, 19.0)
                let frame = CGRectInset(offsetFrame, 0.0, 17.0)
                scrollView.scrollRectToVisible(frame, animated: false)
            }
        }
    }

    func keyboardHidden(notification: NSNotification){
        if let scrollView = scrollView{
            let insets = UIEdgeInsets(top: 0.0, left: 0.0, bottom: 0.0, right: 0.0)
            scrollView.contentInset = insets
            scrollView.scrollIndicatorInsets = insets
        }
    }

    override func loadView() {
        let view = UIView()
        view.translatesAutoresizingMaskIntoConstraints = false
        view.backgroundColor = UIColor.brownColor()

        let sv = UIScrollView()
        sv.backgroundColor = UIColor.clearColor()
        sv.opaque = false
        sv.translatesAutoresizingMaskIntoConstraints = false
        sv.alwaysBounceVertical = true

        self.scrollView = sv

        let titleContainer = buildTitleContainer(self.titleView)
        view.addSubview(titleContainer)
        view.addSubview(sv)

        //peg scroll view to container.
        view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|[scrollView]|", options:NSLayoutFormatOptions(rawValue: 0), metrics:nil, views: ["scrollView":sv]))
        view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("|[scrollView]|", options:NSLayoutFormatOptions(rawValue: 0), metrics:nil, views: ["scrollView":sv]))

        let contentViewWrapper = UIView()
        contentViewWrapper.translatesAutoresizingMaskIntoConstraints = false
        contentViewWrapper.addSubview(self.contentView)
        contentViewWrapper.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|->=0-[contentView]|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: ["contentView": contentView]))
        contentViewWrapper.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("|[contentView]|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: ["contentView": contentView]))

        sv.addSubview(contentViewWrapper)

        let viewsDictionary = [
            "scrollView": sv,
            "view": view,
            "contentViewWrapper": contentViewWrapper
        ]

        //peg contentView to be at least as tall as view.
        view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|[contentViewWrapper(>=view)]|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: viewsDictionary))
        //peg contentView to be equal to host view width
        view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("|[contentViewWrapper(==view)]|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: viewsDictionary))

        //peg title container to width of container.
        view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("|[titleContainer]|",
            options:NSLayoutFormatOptions(rawValue: 0),
            metrics: nil,
            views: ["titleContainer":titleContainer]))

        //title view height.
        view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|[titleContainer][contentView]",
            options:NSLayoutFormatOptions(rawValue: 0),
            metrics: nil,
            views: ["titleContainer":titleContainer, "contentView":self.contentView]))

        self.view = view
        self.titleViewContainer = titleContainer
    }


    func buildTitleContainer(titleView:UIView) -> UIView{
        let titleContainer = UIView()
        titleContainer.translatesAutoresizingMaskIntoConstraints = false
        titleContainer.backgroundColor = UIColor.orangeColor()

        titleContainer.addSubview(titleView)
        titleContainer.setContentCompressionResistancePriority(1000.0, forAxis: .Vertical)

        titleContainer.addConstraint(NSLayoutConstraint(item: titleView, attribute: .CenterY, relatedBy: .Equal, toItem: titleContainer, attribute: .CenterY, multiplier: 1.0, constant: 0.0))
        titleContainer.addConstraint(NSLayoutConstraint(item: titleView, attribute: .CenterX, relatedBy: .Equal, toItem: titleContainer, attribute: .CenterX, multiplier: 1.0, constant: 0.0))

        return titleContainer;
    }
}

实现协议的UIView子类:

class MyContentView:UIView, MyProtocol, UITextFieldDelegate{

    weak var myActiveView:UIView?

    init(){
        super.init(frame: CGRectZero)
        self.backgroundColor = UIColor.clearColor()
        self.opaque = false
        self.translatesAutoresizingMaskIntoConstraints = false

        let cells = Array(1...12).map{_ in cellView() }

        var cellsDictionary: Dictionary<String, UIView> = [:], cellsVerticalFormat = "V:|-"

        for (idx, cell) in cells.enumerate(){
            self.addSubview(cell)
            self.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("|-[cell]-|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: ["cell": cell]))
            let cellKey = "cell\(idx)"
            cellsDictionary[cellKey] = cell
            cellsVerticalFormat = cellsVerticalFormat + "[\(cellKey)]-"
        }

        cellsVerticalFormat = cellsVerticalFormat + "|"

        self.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat(cellsVerticalFormat, options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: cellsDictionary))
    }

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

    func cellView() -> UIView{
        let result = UIView()
        result.backgroundColor = UIColor.magentaColor()
        result.translatesAutoresizingMaskIntoConstraints = false

        let text = UITextField()
        text.translatesAutoresizingMaskIntoConstraints = false

        result.addSubview(text)
        text.delegate = self
        result.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("|-[text]-|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: ["text": text]))
        result.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-[text]-|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: ["text": text]))
        return result
    }

    func widgets() {
        print("\(MyContentView.self) widgets")
    }

    func activeView() -> UIView? {
        return myActiveView
    }

    func textFieldShouldBeginEditing(textField: UITextField) -> Bool{
        myActiveView = textField.superview!
        return true
    }

    func textFieldDidEndEditing(textField: UITextField) {
        if myActiveView === textField.superview! {
            myActiveView = nil
        }
    }

    func textFieldShouldEndEditing(textField: UITextField) -> Bool {
        return true
    }

    func textFieldShouldReturn(textField: UITextField) -> Bool {
        textField.resignFirstResponder()
        return false
    }

}

KeyboardAwareViewController子类:

class MyKeyboardAwareScrollViewController : KeyboardAwareScrollViewController<MyContentView>{
    let myContentView: MyContentView = MyContentView()

    let myTitleView: UILabel = {
        let result = UILabel()

        result.translatesAutoresizingMaskIntoConstraints = false
        result.text = "Pretend This Says\nCohn-Reznick"
        result.numberOfLines = 0
        result.textAlignment = .Center
        return result
    }()

    required init?(coder aDecoder: NSCoder) {
        super.init(titleView: myTitleView, contentView:myContentView)
    }
}

1 个答案:

答案 0 :(得分:0)

答案在这里:Xcode 7 Swift 2 impossible to instantiate UIViewController subclass of generic UITableViewController

TLDR; Objective-c和InterfaceBuilder无法“看到”通用的swift类。