查看不显示另一个ChildViewController

时间:2017-08-21 14:13:27

标签: ios swift viewcontroller childviewcontroller parentviewcontroller

iOS / Swift中的childViewControllers的多级层次结构存在问题。从最低到最高的当前设置有三个层:

  1. InfoViewController
  2. SelectionViewController
  3. MainViewController
  4. InfoViewController有一个从XIB加载的视图。

    SelectionViewController包含UIStackView InfoViewControllerUIButton

    MainViewController是顶级VC,通常嵌入UINavigationController

    问题

    当我将InfoViewController及其视图直接添加到MainViewController时,一切都很有效。

    func setupInfoViewControllerDirectlyOnMainVC () {
        addChildViewController(infoViewController)
        infoViewController.view.embedInside(otherView: infoContainerView)
        infoViewController.didMove(toParentViewController: self)
    }
    

    但是,如果我使用相同的方法将SelectionViewController添加到MainViewController,嵌入的InfoViewController不会更新它的UI - 它总是看起来像未触及的XIB文件在控制。当 NOT 嵌入此SelectionViewController时,其行为符合预期。

    如下所示,UI是可见的,但是通过询问它的ViewController对它做出的任何更改都没有显示 - 它看起来与它创建的XIB文件完全相同。

    example of empty UI

    下面是从BasicInfoView开始的类设置,后面是上面列出的三个viewControllers。

    BasicInfoView

    class PLBasicInfoView: PLDesignableViewFromXib {
    
        //
        // MARK: Outlets
        //
        //
    
        @IBOutlet weak var photoView: PFRoundImageView!
        @IBOutlet weak var titleLabel: UILabel!
        @IBOutlet weak var subtitleLabel: UILabel!
    
    
        var imageFile:PFFile? {
            didSet {
                photoView.file = imageFile
                photoView.loadInBackground()
            }
        }
    
        //
        // MARK: Initialization
        //
        //
    
        override var nameOfXib: String {
            return "PLBasicInfoView"
        }
    
        override var intrinsicContentSize: CGSize {
            return CGSize(width: super.intrinsicContentSize.width, height: 56)
        }
    
    }
    

    BasicInfoViewController

    class PLBasicInfoViewController: UIViewController {
    
        /**
         The BasicInfoView which will be managed by this controller.
         */
        var basicInfoView = PLBasicInfoView()
    
        /**
         This is the master stack view which contains all subviews.
         */
        var stackView = UIStackView()
    
    
        /**
         PFFile representing the image to be displayed in the imageView. Setting a valid imageFile object automatically laods the image from the server. If set to nil, the defaultImage is displayed instead.
         */
        var imageFile: PFFile? {
            didSet {
                if imageFile != nil {
                    basicInfoView.imageFile = imageFile
                } else {
                    basicInfoView.photoView.image = defaultImage
                }
            }
        }
    
        /**
         Default UIImage to be displayed in the imageView if there is no imageFile assigned.
         */
        var defaultImage: UIImage! {
            return #imageLiteral(resourceName: "ios7-camera-outline")
        }
    
    
        /**
         Main text of the infoView
         */
        var titleText:String? {
            didSet {
                basicInfoView.titleLabel.isHidden = (titleText == nil)
                basicInfoView.titleLabel.text = titleText
            }
        }
    
        /**
         Secondary text of the infoView. Displays under titleText.
         */
        var subtitleText:String? {
            didSet {
                basicInfoView.subtitleLabel.isHidden = (subtitleText == nil)
                basicInfoView.subtitleLabel.text = subtitleText
            }
        }
    
        /**
         Embed our stackView into main view. The custom embedInsider(otherView:UIView) method (UIView extension) will take care of the subview additional as well as all layout constraints.
         */
        func setupStackView () {
            stackView.embedInside(otherView: view)
            stackView.axis = .vertical
            stackView.addArrangedSubview(basicInfoView)
        }
    
        override
        func viewDidLoad() {
            super.viewDidLoad()
            setupStackView()
        }
    
    
    }
    

    SelectionViewController

    class PLSelectableInfoViewController: UIViewController {
    
    
        /**
         If true, the info view will be shown and the selection button will be hidden.
         */
        var isAssigned = false {
            didSet {
                selectionButton.isHidden = isAssigned
                infoView.isHidden = !isAssigned
            }
        }
    
    
        /**
         The View controller dispaying the object in question.
         */
        var infoViewController: PLBasicInfoViewController! {
            return PLBasicInfoViewController()
        }
    
        private
        var infoView: UIView!
    
        /**
         Button on bottom of stack. Intended to allow user to assign a new value to the contact property.
         */
        var selectionButton = PLButton()
    
        /**
         Stack view containing all subviews.
         */
        var stackView = UIStackView()
    
    
        //
        // MARK: UIViewController Overrides
        //
        //
    
        override
        func viewDidLoad() {
            super.viewDidLoad()
            setupStackView()
            addInfoView()
        }
    
    
        private
        func setupStackView () {
            stackView.embedInside(otherView: view)
            stackView.axis = .vertical
        }
    
        private
        func addInfoView () {
            addChildViewController(infoViewController)
            infoView = infoViewController.view
            stackView.addArrangedSubview(infoView)
            infoViewController.didMove(toParentViewController: self)
        }
    
    }
    

    删除了一些不相关的代码

    备注

    请注意,实际上,BasicInfoViewController和SelectionViewController都是子类。例如,我有一个ContactInfoViewController,可以传递一个Contact对象并显示全名,公司名称和照片(如上所述,这很好)。还有一个SelectionViewController的子类来补充:ContactSelectionViewController。 ContactSelectionViewController还有一个Contact对象属性,可以将其赋值,然后传递给嵌入式ContactInfoViewController - 这是不显示数据的点。我在下面列出了这些子类以供参考。

    ContactInfoViewController

    同样,当直接放入MainViewController时,这非常有效。

    class PLContactInfoViewController: PLBasicInfoViewController {
    
        /**
         Contact object managed by this controller.
         */
        var contact: PLContact? {
            didSet {
                if contact == nil {
                    titleText = "Not Set"
                    subtitleText = nil
                    return
                }
                contact?.fetchIfNeededInBackground(block: { (object, error) in
                    if let _ = object as? PLContact {
                        self.updateWithContact()
                    }
                })
            }
        }
    
        override
        var defaultImage: UIImage! {
            return #imageLiteral(resourceName: "ios7-contact-outline")
        }
    
    
        private
        func updateWithContact () {
            if let c = contact {
                titleText = c.fullName
                imageFile = c.photo
                c.company?.fetchIfNeededInBackground(block: { (object, error) in
                    if let comp = object as? PLCompany {
                        self.subtitleText = comp.name
                    } else {
                        self.subtitleText = nil
                    }
                })
            }
        }
    
    }
    

    ContactSelectionViewController

    此VC正常运行,但嵌入式ContactInfoViewController不显示数据。出于某种原因,ContactInfoViewController中的视图在嵌入此控制器时未使用数据进行更新。

    class PLContactAssignmentViewController: PLSelectableInfoViewController {
    
    
        /**
         The contact currently selected by this contorller
         */
        var selectedContact: PLContact? {
            didSet {
                isAssigned = !(selectedContact == nil)
                contactInfoViewController.contact = selectedContact
            }
        }
    
    
        override
        var infoViewController: PLBasicInfoViewController! {
            return PLContactInfoViewController()
        }
    
    
        private
        var contactInfoViewController: PLContactInfoViewController {
            return infoViewController as! PLContactInfoViewController
        }
    
    }
    

1 个答案:

答案 0 :(得分:1)

尝试

    var _infoViewController: PLBasicInfoViewController?
    var infoViewController: PLBasicInfoViewController! {
        if let vc = _infoViewController {
            return vc
        }
        _infoViewController = PLBasicInfoViewController()
        return _infoViewController!
    }

lazy var infoViewController: PLBasicInfoViewController = {
        return PLBasicInfoViewController()
    }()

这可能是因为每次尝试访问时都会启动PLBasicInfoViewController。