I want to create a epub book reader app with custom page view controller instead default. I want to load data from JSON file and pass it into child view controller. But I have a problem: my data doesn't showing when I launch the project.
My ParentViewController:
private struct PagesData: Decodable {
var pagesData: [PageData]
}
private struct PageData: Decodable {
let textData, textPosition: String
}
class CustomPageViewController: UIViewController {
private var pagesContent: [ContentViewController] = []
private var pagesData = [PageData]()
let contentViewController = ContentViewController()
var pageNumber = 0
override func viewDidLoad() {
super.viewDidLoad()
let childViewController = UIStoryboard(name: "Storyboard", bundle: nil).instantiateViewController(withIdentifier: "ContentViewController")
self.addChildViewController(childViewController)
self.view.addSubview(childViewController.view)
childViewController.didMove(toParentViewController: self)
childViewController.view.frame = self.view.frame
loadData()
}
func loadData() {
let url = Bundle.main.url(forResource: "pages", withExtension: "json")!
let data = try! Data(contentsOf: url)
let result = try! JSONDecoder().decode(PagesData.self, from: data)
for page in result.pagesData {
let contentVC = ContentViewController()
contentVC.configure(text: page.textData,
image: "image\(pagesContent.count).png",
position: page.textPosition)
pagesContent.append(contentVC)
}
}
}
My ChildViewController:
class ContentViewController: UIViewController {
var textPosition = "bottomLeft"
private lazy var textLabel: UILabel = {
let label = UILabel()
label.textAlignment = .left
label.numberOfLines = 0
label.textColor = .white
label.sizeToFit()
label.font = UIFont.systemFont(ofSize: 25, weight: .bold)
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
private lazy var imageView: UIImageView = {
let image = UIImageView()
image.contentMode = .scaleToFill
image.translatesAutoresizingMaskIntoConstraints = false
image.backgroundColor = .gray
return image
}()
override func viewDidLoad() {
super.viewDidLoad()
setupViews()
setupConstraints()
}
func configure(text: String, image: String, position: String) {
textLabel.text = text
imageView.image = UIImage(named: image)
textPosition = position
}
private func setupViews() {
view.addSubview(imageView)
view.addSubview(textLabel)
}
private func setupConstraints() {
imageView.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 0).isActive = true
imageView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor, constant: 0).isActive = true
imageView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: 0).isActive = true
imageView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor, constant: 0).isActive = true
switch textPosition {
case "topCenter":
textLabel.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor,
constant: 16).isActive = true
textLabel.leadingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.leadingAnchor,
constant: 16).isActive = true
textLabel.trailingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.trailingAnchor,
constant: -16).isActive = true
case "centerCenter":
textLabel.leadingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.leadingAnchor,
constant: 16).isActive = true
textLabel.trailingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.trailingAnchor,
constant: -16).isActive = true
textLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
textLabel.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
case "bottomCenter":
textLabel.bottomAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.bottomAnchor,
constant: -16).isActive = true
textLabel.leadingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.leadingAnchor,
constant: 16).isActive = true
textLabel.trailingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.trailingAnchor,
constant: -16).isActive = true
case "topLeft":
textLabel.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor,
constant: 16).isActive = true
textLabel.leadingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.leadingAnchor,
constant: 16).isActive = true
textLabel.trailingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.trailingAnchor,
constant: -16 - (view.frame.size.width/2)).isActive = true
case "centerLeft":
textLabel.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor,
constant: 16).isActive = true
textLabel.bottomAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.bottomAnchor,
constant: -16).isActive = true
textLabel.leadingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.leadingAnchor,
constant: 16).isActive = true
textLabel.trailingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.trailingAnchor,
constant: -16 - (view.frame.size.width/2)).isActive = true
case "bottomLeft":
textLabel.bottomAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.bottomAnchor,
constant: -16).isActive = true
textLabel.leadingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.leadingAnchor,
constant: 16).isActive = true
textLabel.trailingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.trailingAnchor,
constant: -16 - (view.frame.size.width/2)).isActive = true
case "topRight":
imageView.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor,
constant: 0).isActive = true
imageView.leadingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.leadingAnchor,
constant: 0).isActive = true
imageView.trailingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.trailingAnchor,
constant: 0).isActive = true
case "centerRight":
textLabel.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor,
constant: 16).isActive = true
textLabel.bottomAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.bottomAnchor,
constant: -16).isActive = true
textLabel.leadingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.leadingAnchor,
constant: 16 + (view.frame.size.width/2)).isActive = true
textLabel.trailingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.trailingAnchor,
constant: -16).isActive = true
case "bottomRight":
textLabel.bottomAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.bottomAnchor,
constant: -16).isActive = true
textLabel.leadingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.leadingAnchor,
constant: 16 + (view.frame.size.width/2)).isActive = true
textLabel.trailingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.trailingAnchor,
constant: -16).isActive = true
default:
textLabel.bottomAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.bottomAnchor,
constant: -16).isActive = true
textLabel.leadingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.leadingAnchor,
constant: 16).isActive = true
textLabel.trailingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.trailingAnchor,
constant: -16).isActive = true
}
}
}
How to resolve the problem? And what I should fix in this project?
Answers
It seems like the issue might be related to how you're setting up and adding child view controllers in your CustomPageViewController
. Here are some suggestions to resolve the problem:
- Properly Add Child View Controllers: Make sure you're properly adding the child view controllers to your
CustomPageViewController
. It seems like you're instantiating a child view controller from a storyboard, but you're not using thecontentViewController
property you declared. Instead, you're adding the child view controller directly to the parent view controller's view. Modify your code to use thecontentViewController
property instead:
override func viewDidLoad() {
super.viewDidLoad()
loadData()
}
func loadData() {
let url = Bundle.main.url(forResource: "pages", withExtension: "json")!
let data = try! Data(contentsOf: url)
let result = try! JSONDecoder().decode(PagesData.self, from: data)
for page in result.pagesData {
let contentVC = ContentViewController()
contentVC.configure(text: page.textData,
image: "image\(pagesContent.count).png",
position: page.textPosition)
pagesContent.append(contentVC)
}
// Add the first child view controller to the parent view controller
if let firstChildVC = pagesContent.first {
addChild(firstChildVC)
view.addSubview(firstChildVC.view)
firstChildVC.didMove(toParent: self)
}
}
-
Update Constraints: Ensure that the constraints are set up correctly in your
ContentViewController
. It seems like you're setting up constraints for bothimageView
andtextLabel
, but depending on thetextPosition
, you may only need to add one of them to the view hierarchy. Double-check the logic in yoursetupConstraints()
method and make sure it aligns with your intended layout. -
Ensure JSON Data is Loaded: Verify that your JSON data is properly loaded and decoded. Add some debug print statements to check if the JSON data is loaded correctly and if the decoding process succeeds.
By making these adjustments and ensuring proper setup of child view controllers and constraints, you should be able to resolve the issue and display the data correctly in your app.