Just a bit recommendation about creating customized view programmatically and the reality about why kind constructing with assortment views sucks.
iOS
How NOT to construct types for iOS apps?
Let’s begin with an trustworthy assertion: I tousled with this tutorial (quite a bit):
Constructing enter types for iOS apps
The factor is that this kind constructing methodology solely works if the cells are at all times seen on display, which is sort of a uncommon case. I found this situation whereas I used to be engaged on my present venture and a few fields have been consistently disappearing and transferring the cursor to the subsequent enter subject stopped working when the cell was out of body.
Reusability & reminiscence effectivity just isn’t at all times what you need.
Looks like UICollectionView
just isn’t the perfect answer for making enter types, as a result of the fixed cell reusability will mess up among the anticipated conduct. It is nonetheless good for lists with “a thousand parts”, however for an enter kind I might not advocate this method anymore. Yep, my mistake, sorry about it… 😬
Studying by making errors
Lengthy story brief, I made a mistake and doubtless you may additionally make quite a bit throughout your developer profession. Does this make you a nasty programmer? Under no circumstances. We’re human, we’re consistently making smaller or greater errors, however…
(Stay and) flip it into energy
Your errors will at all times stick with you, however you’ll be able to be taught from them quite a bit. The issue solely begins in case you preserve doing the identical errors time and again, or you do not even notice that you just’re doing one thing incorrect. It is actually onerous to take one step again and see the issue from a much bigger perspective. Generally you merely want another person to level out the difficulty for you, however adverse suggestions may also be painful.
Anyway, I do not wish to be an excessive amount of philosophical, this can be a Swift developer weblog ffs.
A couple of issues that I realized:
- my concepts should not at all times working, so do not belief me 100% (haha) 🤣
- it is at all times higher to code/work in pair with another person
- generally the “padawan” will train the “grasp” 😉
- an expert qa staff can prevent a variety of time
- VIPER is my architectural “silver bullet”, not assortment views
- UICollectionView primarily based kind constructing just isn’t working…
- …however the assortment view framework nonetheless rocks for complicated interfaces
- have some devoted time for code cosmetics & refactor
- use view subclasses programmatically (or SwiftUI sooner or later)
So the final level is essentially the most attention-grabbing one, let me clarify why.
Customized view subclasses from code solely
Making a UIView subclass programmatically is a comparatively straightforward activity. You may load a nib file or you are able to do it straight from code. A couple of weeks in the past I’ve realized a brand new trick, that was bugging me on a regular basis I made a brand new subclass in Swift:
Why the hell do I’ve to implement
init(coder:)
if I am not utilizing IB in any respect?
Additionally what the heck is occurring with init(body:)
, I do not wish to take care of these two init strategies anymore, since I am utilizing auto structure and I am fully attempting to disregard interface builder with the tousled storyboards and nibs as nicely.
class View: UIView {
@obtainable(*, unavailable)
override init(body: CGRect) {
tremendous.init(body: body)
self.initialize()
}
@obtainable(*, unavailable)
required init?(coder aDecoder: NSCoder) {
tremendous.init(coder: aDecoder)
self.initialize()
}
init() {
tremendous.init(body: .zero)
self.initialize()
}
func initialize() {
self.translatesAutoresizingMaskIntoConstraints = false
}
}
The answer: mark these silly init capabilities as unavailable, so noone can use them anymore. The one supply of reality can be your personal init methodology, which is sort of a reduction in case you have been so irritated concerning the tousled initialization course of like I used to be. 😤
Now you may have your personal base class that you should use as a mum or dad in your future views. In fact you may have to do the identical factor for nearly each UI aspect, like labels, buttons, textfields, and so on. That is a variety of work, however on a long run it’s very price it.
import UIKit
class TitleLabel: Label {
override func initialize() {
tremendous.initialize()
self.textAlignment = .heart
self.font = UIFont.preferredFont(forTextStyle: .largeTitle)
self.textColor = .systemBlue
}
func constraints(in view: UIView, padding: CGFloat = 8) -> [NSLayoutConstraint] {
[
self.topAnchor.constraint(equalTo: view.topAnchor, constant: padding),
self.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: padding),
self.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -1 * padding),
]
}
}
A great observe could be to have subclass for each customized person interface part, like the first button, secondary button, title label, header label, and so on. This fashion you do not have to configure your views within the view controller, plus you’ll be able to put your steadily used constraints into the subclass utilizing some helper strategies.
Additionally you’ll be able to have some niceextensions, these might help you with view configurations. You already know, identical to modifiers in SwiftUI. You may even recreate the very same syntax. The underlying conduct will not be the identical, however that is one other story. 📚
What concerning the kind new builder in iOS?
Oh, yeah virtually forgot. I’ve a model new, however nonetheless very comparable answer. I am utilizing view subclasses as a substitute of assortment view elements, plus the gathering view have been changed with a UIScrollView
+ UIStackView
mixture. 🐐
class ViewController: UIViewController {
weak var scrollView: ScrollView!
weak var stackView: VerticalStackView!
override func loadView() {
tremendous.loadView()
let scrollView = ScrollView()
self.view.addSubview(scrollView)
self.scrollView = scrollView
NSLayoutConstraint.activate([/*...*/])
let stackView = VerticalStackView()
self.scrollView.addSubview(stackView)
self.stackView = stackView
NSLayoutConstraint.activate([/*...*/])
}
override func viewDidLoad() {
tremendous.viewDidLoad()
self.title = "StackForm"
self.navigationController?.navigationBar.prefersLargeTitles = true
let electronic mail = EmailTextField(id: "email-input", placeholder: "E-mail")
self.stackView.addArrangedSubview(electronic mail)
let password = PasswordTextField(id: "password-input", placeholder: "Password")
self.stackView.addArrangedSubview(password)
let submit = SubmitButton(id: "submit-button", title: "Submit")
.onTouch { [weak self] _ in self?.submit() }
self.stackView.addArrangedSubview(submit)
}
func submit() {
guard
let electronic mail = (self.view.view(withId: "email-input") as? UITextField)?.textual content,
let password = (self.view.view(withId: "password-input") as? UITextField)?.textual content
else {
return
}
print("Account: (electronic mail) - (password)")
}
}
As you’ll be able to see I am nonetheless utilizing the identical view identification method, plus I nonetheless desire to have the SwiftUI-like .onTouch
motion handlers. You may ask although:
Why do not you merely go together with SwiftUI?
Nicely, the factor is that SwiftUI is iOS13 solely, which is simply round ~55% adoption these days, that is one of many foremost causes, but additionally SwiftUI is form of incomplete.
I am attempting to get as shut as I can to SwiftUI, so the transition can be much less ache within the ass when the time comes. SwiftUI can be superb, however nonetheless it is a big leap ahead. Generally I consider that Apple is speeding issues simply due to advertising and marketing / developer wants (yeah, we’re very impatient animals). Perhaps a easy wrapper framework round UIKit / AppKit with out the entire declarative syntax would have been a greater thought as a primary step… who is aware of… CoreKit -> AppleKit? 🤔
Anyway, you’ll be able to obtain a working instance of my newest kind constructing answer in Swift 5 from GitHub. Simply search for the StackForm
folder contained in the repository.
Thanks for studying, I am attempting please assist me by following on twitter and remember to subscribe to my month-to-month publication under.