Welcome to the Treehouse Community
Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.
Looking to learn something new?
Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.
Start your free trialSimon Di Giovanni
8,429 PointsError when clicking 'Start your adventure' button, after creating the closure for artworkView
In this video, the closure for the lazy var artworkView is created. I have created that in my app, however, while the app compiles and runs the first view, when I click on 'Start your adventure' there seems to be an error relating to the constants for the Y axis on artworkView.
mport UIKit
extension NSAttributedString {
var stringRange: NSRange {
return NSMakeRange(0, self.length)
}
}
extension Story {
var attributedText: NSAttributedString {
let attributedString = NSMutableAttributedString(string: text)
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineSpacing = 10
attributedString.addAttribute(NSAttributedStringKey.paragraphStyle, value: paragraphStyle , range: attributedString.stringRange)
return attributedString
}
}
extension Page {
func story(attributed: Bool) -> NSAttributedString {
if attributed == true {
return story.attributedText
} else {
return NSAttributedString(string: story.text)
}
}
}
class PageController: UIViewController {
var page: Page?
// MARK: User Interface Properties
lazy var artworkView: UIImageView = {
let imageView = UIImageView()
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.image = self.page?.story.artwork
return imageView
}()
let storyLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.numberOfLines = 0
return label
}()
let firstChoiceButton: UIButton = {
let button = UIButton(type: .system)
button.translatesAutoresizingMaskIntoConstraints = false
return button
}()
let secondChoiceButton: UIButton = {
let button = UIButton(type: .system)
button.translatesAutoresizingMaskIntoConstraints = false
return button
}()
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
init(page: Page) {
self.page = page
super.init(nibName: nil, bundle: nil)
}
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
if let page = page {
storyLabel.attributedText = page.story(attributed: true)
if let firstChoice = page.firstChoice {
firstChoiceButton.setTitle(firstChoice.title, for: .normal)
firstChoiceButton.addTarget(self, action: #selector(PageController.loadFirstChoice), for: .touchUpInside)
} else {
firstChoiceButton.setTitle("Play Again", for: .normal)
firstChoiceButton.addTarget(self, action: #selector(PageController.playAgain), for: .touchUpInside)
}
if let secondChoice = page.secondChoice {
secondChoiceButton.setTitle(secondChoice.title, for: .normal)
secondChoiceButton.addTarget(self, action: #selector(PageController.loadSecondChoice), for: .touchUpInside)
}
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
NSLayoutConstraint.activate ([
artworkView.topAnchor.constraint(equalTo: view.topAnchor),
artworkView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
artworkView.rightAnchor.constraint(equalTo: view.rightAnchor),
artworkView.leftAnchor.constraint(equalTo: view.leftAnchor),
])
NSLayoutConstraint.activate([
storyLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 16.0),
storyLabel.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -16.0),
storyLabel.topAnchor.constraint(equalTo: view.centerYAnchor, constant: -48.0),
])
NSLayoutConstraint.activate([
firstChoiceButton.centerXAnchor.constraint(equalTo: view.centerXAnchor),
firstChoiceButton.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -80.0)
])
NSLayoutConstraint.activate([
secondChoiceButton.centerXAnchor.constraint(equalTo: view.centerXAnchor),
secondChoiceButton.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -32)
])
}
@objc func loadFirstChoice() {
if let page = page, let firstChoice = page.firstChoice {
let nextPage = firstChoice.page
let pageController = PageController.init(page: nextPage)
navigationController?.pushViewController(pageController, animated: true)
}
}
@objc func loadSecondChoice() {
if let page = page, let secondChoice = page.secondChoice {
let nextPage = secondChoice.page
let pageController = PageController.init(page: nextPage)
navigationController?.pushViewController(pageController, animated: true)
}
}
@objc func playAgain() {
navigationController?.popToRootViewController(animated: true)
}
}
And here is the error
Terminating app due to uncaught exception 'NSGenericException', reason: 'Unable to activate constraint with anchors <NSLayoutYAxisAnchor:0x604000466340 "UIImageView:0x7fd915f22290.top"> and <NSLayoutYAxisAnchor:0x604000466500 "UIView:0x7fd915e08520.top"> because they have no common ancestor. Does the constraint or its anchors reference items in different view hierarchies? That's illegal.'
Could someone please help?
1 Answer
Simon Di Giovanni
8,429 PointsFor anyone with this problem, I solved it myself.
I had accidentally deleted my 'view.addSubview' code in the viewWillLayoutSubview's method.