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
InfoViewController
SelectionViewController
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.
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
}
}
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é.) –
@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. –
Désolé. J'ai mal compris "ça ressemble toujours à la XIB intacte". –