0

Je rencontre un problème avec une hiérarchie à plusieurs niveaux de childViewControllers dans iOS/Swift. Il y a trois couches à la configuration de la plus haut le plus bas actuel:Affichage ne pas afficher pour childViewController d'un autre ChildViewController

  1. InfoViewController
  2. SelectionViewController
  3. MainViewController

Le InfoViewController a une vue qui est chargé à partir XIB au catalogue.

SelectionViewController contient UIStackView avec InfoViewController et UIButton.

MainViewController est le VC de niveau supérieur qui est généralement intégré dans un UINavigationController.

Le problème

Quand j'ajouter le InfoViewController et il est vue directement sur le tout MainViewController fonctionne très bien.

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

Cependant, si j'ajoute le SelectionViewController au MainViewController en utilisant la même méthode, l'embarqué InfoViewController ne met pas à jour l'interface utilisateur est - il ressemble toujours le fichier intact qu'il XIB est le contrôle. Quand il est pas intégré dans ce SelectionViewController se comporte comme prévu.

Comme indiqué ci-dessous, l'interface utilisateur est visible, mais toutes les modifications apportées en demandant à ViewController ne s'affichent pas - elle ressemble exactement au fichier XIB à partir duquel elle a été créée.

example of empty UI

est inférieure à la configuration de la classe en commençant par le BasicInfoView suivi par les trois viewControllers énumérés ci-dessus.

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) 
    } 

} 

Certains code non pertinent a été supprimé

Remarques

S'il vous plaît noter que, dans la pratique, à la fois BasicInfoViewController et SelectionViewController sont sous-classés. Par exemple, j'ai un ContactInfoViewController qui peut être passé un objet Contact et afficher le nom complet, le nom de l'entreprise et la photo (comme expliqué ci-dessus, cela fonctionne bien).Il y a aussi une sous-classe de SelectionViewController pour compléter ceci: ContactSelectionViewController. ContactSelectionViewController possède également une propriété d'objet Contact qui peut être affectée et transmise au ContactInfoViewController intégré - c'est le point auquel les données ne sont pas affichées. J'ai inclus ces sous-classes ci-dessous pour référence supplémentaire.

ContactInfoViewController

Encore une fois, cela fonctionne parfaitement lorsqu'il est placé directement dans le 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

Cette fonction VC correctement, mais le ContactInfoViewController intégré ne présente pas de données. Pour une raison quelconque, la vue de ContactInfoViewController n'est pas mise à jour avec des données lorsqu'elle est intégrée dans ce contrôleur.

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 
    } 

} 
+0

Je ne peux pas dire grand-chose de la question, mais j'ai trouvé la fonction de débogage de Xcode utile pour ce genre de problème, en particulier l'investigation des contraintes. (Au cas où vous ne l'auriez pas essayé.) –

+0

@PhillipMills Il semble que ce soit plus un problème de référencement qu'un problème de mise en page. Tout s'affiche correctement; cependant, il se comporte comme si InfoView n'était pas la même instance que l'InfoView attaché à InfoViewController. –

+0

Désolé. J'ai mal compris "ça ressemble toujours à la XIB intacte". –

Répondre

1

Essayez

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

ou

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

Il est peut-être parce que vous initiez PLBasicInfoViewController chaque fois que vous essayez d'accéder.