Oddzielny widok od ViewController w Swift
Nie skłamię, jeśli powiem, że wyświetlenia są jednym z najważniejszych elementów aplikacji mobilnych. Użytkownicy wchodzą w interakcję z widokami podczas korzystania z naszych aplikacji. Użytkownicy chcą, aby aplikacje były piękne, więc będą mieli lepsze wrażenia. Naszym celem jako programistów jest nie tylko stworzenie atrakcyjnego interfejsu użytkownika, ale także stworzenie interfejsu użytkownika, który jest łatwy w obsłudze, aktualizacji i utrzymaniu. Myślę, że każdy przynajmniej raz widział okropne kontrolery widoku z ponad 500 liniami kodu. Jeśli chcesz coś dodać lub zmienić w takiej sytuacji, będziesz musiał poświęcić dużo czasu.
Zrozumienie problemu
Dlaczego tak się dzieje? Ponieważ dajemy kontrolerom widoków wiele obowiązków. Tworzymy i konfigurujemy widoki, obsługujemy akcje, delegatów, przeglądamy cykl życia kontrolera, routing, a nawet logikę biznesową wewnątrz kontrolera widoku. I jestem pewien, że możesz kontynuować tę listę obowiązków. Musimy je rozdzielić między różne warstwy naszej architektury. Logika biznesowa przechodzi do Presenter/Controller/ViewModel/Interactor w zależności od używanego wzorca. Routing jest obowiązkiem routera lub koordynatora. W kontrolerze widoku możemy obsłużyć jego cykl życia, akcje widoków i delegatów, takich jak UITablewViewDataSource, UISearchBarDelegatei inne. Ale gdzie konfigurujemy widoki podrzędne? Musimy to zrobić w osobnej klasie widoku. Pomoże nam to podzielić kod na mniejsze części i uniknąć ogromnych kontrolerów widoku.
Zacznijmy kodować
W tym samouczku potrzebujemy tylko jednego obiektu kontrolera widoku do uruchomienia. Nie krępuj się użyć ViewControllerklasy wygenerowanej przez XCode. Ale sugeruję zmianę nazwy na coś takiego jak MainViewController. Aby podzielić kontroler i jego widok, potrzebujemy UIViewpodklasy reprezentującej widok kontrolerów. W nowym pliku utwórz nową klasę, nazwij ją jak chcesz, nazwę ją MainView. Przy takim nazewnictwie łatwo zrozumieć, że MainViewjest to widok pliku MainViewController. Teraz dodajmy kilka widoków podrzędnych do pliku MainView. Zamierzam utworzyć prosty formularz logowania z 2 polami tekstowymi, etykietami i przyciskiem.
class MainView: UIView {
let usernameHintLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.text = "Username"
label.font = .systemFont(ofSize: 14, weight: .semibold)
label.textAlignment = .left
return label
}()
let usernameTextField: UITextField = {
let textfield = UITextField()
textfield.translatesAutoresizingMaskIntoConstraints = false
textfield.borderStyle = .roundedRect
textfield.placeholder = "Username"
textfield.font = .systemFont(ofSize: 18, weight: .regular)
return textfield
}()
// More subviews
init() {
super.init(frame: .zero)
setup()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
setup()
}
func setup() {
// Setup your view, add subviews and constraints
}
}
Po MainViewzakończeniu nadszedł czas, aby dodać go do pliku MainViewController. Nie musimy dodawać go jako widoku podrzędnego. UIViewController ma już viewwłaściwość. Ten widok jest widokiem, którym zarządza kontroler. Więc to, co musimy zrobić, to przypisać MainViewdo MainViewControllerwidoku. I zrobimy to wewnątrz loadView()metody. Dokumentacja Apple mówi, że loadView()tworzy widok, którym zarządza kontroler. Więc tego właśnie potrzebujemy.
override func loadView() {
super.loadView()
view = MainView()
}
Uzyskaj dostęp do właściwości widoku z poziomu kontrolera
Kiedy interfejs użytkownika jest już gotowy, nadszedł czas, aby dodać akcję dla przycisku i zapewnić delegatów do pól tekstowych. Możesz uzyskać dostęp do widoku przez viewnieruchomość. Ale viewma UIViewtyp, więc nie możesz uzyskać dostępu do żadnych elementów z MainView. Jeśli chcesz uzyskać dostęp do przycisku i pól tekstowych, musisz wykonać rzutowanie typu.
func setupTextFields() {
let view = view as? MainView
view?.usernameTextField.delegate = self
view?.passwordTextField.delegate = self
}
func setupButton() {
(view as? MainView)?.submitButton.addTarget(self, action: #selector(buttonPressed), for: .primaryActionTriggered)
}
var rootView: MainView {
view as! MainView
}
func setupTextFields() {
rootView.usernameTextField.delegate = self
rootView.passwordTextField.delegate = self
}
func setupButton() {
rootView.submitButton.addTarget(self, action: #selector(buttonPressed), for: .primaryActionTriggered)
}
Nie chcesz ciągle powtarzać kodu rootViewi loadView()w każdym kontrolerze, jeśli zamierzasz go używać w swojej aplikacji. Dzięki Apple Swift ma typy ogólne. Za pomocą generycznych możemy stworzyć ogólną klasę kontrolera widoku, która będzie powiązana z określoną klasą widoku. I możesz dodawać do niego loadView()i rootViewimplementacje, więc nie musisz tego powtarzać za każdym razem.
Utwórz UIViewControllerpodklasę i nazwij ją GenericViewController.
class GenericViewController: UIViewController { }
class GenericViewController<T: UIView>: UIViewController { }
class GenericViewController<T: UIView>: UIViewController {
public var rootView: T { return view as! T }
override open func loadView() {
self.view = T()
}
}
class MainViewController: GenericViewController<MainView> {
override func viewDidLoad() {
super.viewDidLoad()
}
func setupTextFields() {
rootView.usernameTextField.delegate = self
rootView.passwordTextField.delegate = self
}
func setupButton() {
rootView.submitButton.addTarget(self, action: #selector(buttonPressed), for: .primaryActionTriggered)
}
@objc func buttonPressed() { }
}
Wniosek
To podejście można zastosować w każdym projekcie. Dzięki temu będzie bardziej przejrzysty, zrozumiały i łatwiejszy w obsłudze, debugowaniu i utrzymaniu.
Mam nadzieję, że podobał Ci się ten artykuł i okazał się przydatny. Podziel się swoimi przemyśleniami w sekcji komentarzy.
Kod źródłowy można znaleźć tutaj .
Check out my other articles about iOS Development
https://medium.com/@artem.khalilyaev
![Czym w ogóle jest lista połączona? [Część 1]](https://post.nghiatu.com/assets/images/m/max/724/1*Xokk6XOjWyIGCBujkJsCzQ.jpeg)



































