Converting UIViewController from the simple Xib-file to Swift source code.
Source Xib file
The simple Xib file – is a Xib file which holds design bound to the single UIViewController. Think about it as a "one to one" relationship between UI and Code.
Here is how the simple Xib file may look like:
It has the UILabel bound to IBOutlet and UIButton bound to IBAction.
public class ViewController: UIViewController {
@IBOutlet private weak var titleLabel: UILabel!
@IBOutlet private weak var numberOfTapsLabel: UILabel!
private var numberOfTaps = 0
public override func viewDidLoad() {
super.viewDidLoad()
titleLabel.textColor = .blue
}
@IBAction private func onIncrement(_ sender: UIButton) {
numberOfTaps += 1
numberOfTapsLabel.text = "The button tapped \"\(numberOfTaps)\" times."
}
}
In Simulator this Xib-file looks as shown below:
Tapping on UIButton will change text of the second UILabel.
Generated code
The source code generated by Decode.app looks like below:
public class Generated: UIViewController {
private lazy var titleLabel = UILabel()
private lazy var button = UIButton(type: .system)
private lazy var numberOfTapsLabel = UILabel()
private lazy var stackView = UIStackView()
public init() {
super.init(nibName: nil, bundle: nil)
setupUI()
setupLayout()
}
required init?(coder: NSCoder) {
fatalError("Please use this class from code.")
}
private func setupUI() {
view.addSubview(stackView)
view.backgroundColor = UIColor.systemBackground
stackView.addArrangedSubview(titleLabel)
stackView.addArrangedSubview(button)
stackView.addArrangedSubview(numberOfTapsLabel)
stackView.alignment = .top
stackView.axis = .vertical
stackView.spacing = 10
stackView.translatesAutoresizingMaskIntoConstraints = false
numberOfTapsLabel.contentMode = .left
numberOfTapsLabel.font = UIFont.systemFont(ofSize: 17)
numberOfTapsLabel.setContentHuggingPriority(UILayoutPriority(rawValue: 251), for: .horizontal)
numberOfTapsLabel.setContentHuggingPriority(UILayoutPriority(rawValue: 251), for: .vertical)
numberOfTapsLabel.text = "The button tapped \"0\" times."
numberOfTapsLabel.textAlignment = .natural
numberOfTapsLabel.translatesAutoresizingMaskIntoConstraints = false
button.contentVerticalAlignment = .center
button.titleLabel?.font = UIFont.systemFont(ofSize: 17, weight: .medium)
button.titleLabel?.lineBreakMode = .byTruncatingMiddle
button.translatesAutoresizingMaskIntoConstraints = false
button.setTitle("Tap", for: .normal)
titleLabel.contentMode = .left
titleLabel.font = UIFont.systemFont(ofSize: 17, weight: .semibold)
titleLabel.numberOfLines = 0
titleLabel.setContentHuggingPriority(UILayoutPriority(rawValue: 251), for: .horizontal)
titleLabel.setContentHuggingPriority(UILayoutPriority(rawValue: 251), for: .vertical)
titleLabel.text = "Hi, This is an example UI!"
titleLabel.translatesAutoresizingMaskIntoConstraints = false
}
private func setupLayout() {
stackView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 16).isActive = true
stackView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 16).isActive = true
view.safeAreaLayoutGuide.trailingAnchor.constraint(equalTo: stackView.trailingAnchor, constant: 16).isActive = true
}
}
The generated code contains instances of UILabel and UIButton, as in original source file.
In Simulator the generated UIViewController looks as shown below:
Almost like in the original view, but there is few issues:
- The title label has a black color instead of blue.
- Tapping on button not changing a title of the second UILabel. The IBAction connection is broken.
Such issues are expected. Here is why:
- The label color was set in viewDidLoad method. This method is not present in generated code. We have to manually move it.
- The IBAction is not called because there is no IBOutlet and the Xib file anymore. We need to restore this connection manually.
Resolving issues
The diff-file below shows what was changed in order to restore connection between UI elements and source code.
@@ -1,5 +1,5 @@
import UIKit
-public class Generated: UIViewController {
+public class Adjusted: UIViewController {
private lazy var titleLabel = UILabel()
@@ -8,4 +8,6 @@
private lazy var stackView = UIStackView()
+ private var numberOfTaps = 0
+
public init() {
super.init(nibName: nil, bundle: nil)
@@ -18,4 +20,14 @@
}
+ public override func viewDidLoad() {
+ super.viewDidLoad()
+ titleLabel.textColor = .blue
+ }
+
+ @objc private func onIncrement(_ sender: UIButton) {
+ numberOfTaps += 1
+ numberOfTapsLabel.text = "The button tapped \"\(numberOfTaps)\" times."
+ }
+
private func setupUI() {
@@ -46,4 +58,6 @@
button.translatesAutoresizingMaskIntoConstraints = false
button.setTitle("Tap", for: .normal)
+ // 1️⃣ Button connected to the existing function (which was previously an IBAction).
+ button.addTarget(self, action: #selector(onIncrement(_:)), for: .touchUpInside)
titleLabel.contentMode = .left
The generated view after maintenance in Simulator looks as shown below:
Summary
An example above shows that converting the simple Xib file to Swift source code is easy doable task. The few things requires attention:
- View settings made in viewDidLoad method have to be moved to generated code.
- The connections from controls made via IBAction have to be reestablished manually via target-action assignments.
Downloads
- Example Xcode project: XibAndStoryboardsConversionApp.zip