본 블로그 글은 chatGPT 가 준 코드와 iOS 개발 기초 개념들을 chatGPT 를 통해 공부한 글입니다.
ChatGPT 90%, 기타 블로그 10% 참고하여 틀린 내용이 있을 수도 있습니다.
틀린 내용 있을 시, 지적해주시면 감사하겠습니다.
UIView 와 UIViewController 에 대한 정의를 살펴봅시다.
UIView 와 UIViewController
UIView
이는 화면을 구성하는 요소들의 기본 클래스이며, 위치와 크기를 갖는 사각형으로, 배경색을 가지고 있고 문자나 이미지 등의 컨텐츠를 가지는 것이 가능합니다.
• Label, Image, Button, 기타 인터페이스 요소를 표시하려면, UIKit Framework가 제공하는 뷰 하위클래스를 사용하면 됩니다.
UIViewController
이는 앱의 근간을 이루는 객체로 모든 앱은 최소한 하나 이상의 뷰 컨트롤러를 가지고 있는데, 한 마디로 사용자가 화면을 보는 것에 대한 관리기능을 제공하는 객체입니다. (xcode에서 프로젝트를 생성하면 기본적으로 ViewController 파일 하나는 이미 존재함)
UIViewController와 UIView는 일대다(one-to-many) 관계입니다. UIViewController는 일반적으로 여러 개의 UIView 객체를 관리합니다.
예시 코드
다은은 UIViewController 를 생성하여 UIView 를 참조시키는 방법입니다.
class MyViewController: UIViewController {
let myView = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
override func viewDidLoad() {
super.viewDidLoad()
self.view.addSubview(myView)
// ...
}
// ...
}
UIViewController에서 UIView 를 참조하는 경우에는 보통 UIViewController 클래스의 인스턴스 변수로 UIView 를 생성하고, 이를 UIViewController의 view 계층 구조에 추가하여 화면을 구성합니다.
예를 들어, 위와 같이 UIViewController 클래스의 인스턴스 변수로 UIView 를 생성하고, 이를 view 계층 구조에 추가하여 화면을 구성할 수 있습니다.
<코드 해석을 덧붙이자면..>
위 코드에서 MyViewController 클래스는 myView 라는 인스턴스 변수로 UIView를 생성하고, viewDidLoad 메서드에서 myView 를 UIViewController 의 view 계층 구조에 추가합니다.
이렇게 함으로써 UIViewController는 myView 를 참조하며, myView는 UIViewController에 의해 소유됩니다. 이때 myView 변수는 강한 참조(strong var)입니다.
이렇게 UIViewController의 view 위에서 UIView, UIButton, UITextField 등을 붙입니다.
Delegate 패턴.... Protocol 을 먼저 알아보자.
프로토콜을 먼저 알아야 한다.
프로토콜이란?
작업의 설계도와 같습니다
프로토콜에서는 직접 구현을 하지 않습니다. delegate는 프로토콜로 구현되어 있습니다.
Delegate 패턴
delegate : 위임
내가 해야할 일을 다른 누군가에게 시킨다.
객체지향 프로그래밍(OOP)에서 하나의 객체가 모든 일을 처리하는 것이 아니라 일들 중 일부를 다른 객체에 넘기는 것
유명한 싱글턴, 팩토리, 어댑터, 옵저버 등의 디자인 패턴도 이러한 '패턴' 인 것이다.
이론보다 코드를 통해 좀 더 쉽게 이해할 수 있을 것 같습니다.
import UIKit
protocol MyButtonDelegate: AnyObject {
func buttonTapped(_ button: MyButton)
}
class MyButton: UIButton {
weak var delegate: MyButtonDelegate?
override init(frame: CGRect) {
super.init(frame: frame)
// Interface Builder에서 쓰이지 않고, 코딩(Programmatically)으로 UIView를 상속받은 클래스를 만들 때 사용
// ex) let sampleButton = UIButton(frame: CGRect(x: 3, y: 0, width: 100, height: 200))
self.addTarget(self, action: #selector(buttonTapped(_:)), for: .touchUpInside)
}
required init?(coder: NSCoder) {
// Interface Builder에서 생성되는 초기화 구문
// Interface Builder란 간단하게 말해서는 xib, nib, storyboard를 사용하여 VIew를 작업하는 것!
fatalError("init(coder:) has not been implemented")
}
@objc private func buttonTapped(_ sender: UIButton) {
guard let delegate = delegate else { return }
guard let myButton = sender as? MyButton else { return }
delegate.buttonTapped(myButton)
}
}
class MyViewController: UIViewController, MyButtonDelegate {
override func viewDidLoad() {
super.viewDidLoad()
let myButton = MyButton(type: .system)
myButton.frame = CGRect(x: 100, y: 100, width: 100, height: 50)
myButton.setTitle("Tap me", for: .normal)
myButton.delegate = self // delegate 프로퍼티에 self 할당
self.view.addSubview(myButton)
}
func buttonTapped(_ button: MyButton) {
print("Button tapped!")
}
}
위의 코드를 해석하면 MyViewController 에서
MyButton 을 강한 참조 (let myButton = MyButton(type: .system)) 를 하였고
self.view.addSubview 를 통해 MyViewController 의 view 에 추가하고 있습니다
위의 코드는 전체 코드이지만 이 정도만 분석하고 밑에서 자세히 코드를 분할하여 알아보겠습니다.
여기서 delegate 를 살펴보겠습니다
protocol MyButtonDelegate: AnyObject {
func buttonTapped(_ button: MyButton)
}
delegate 는 protocol 로 구현되어 있습니다.
그래서 구현 내용은 없고 선언만 되어 있는 것을 확인할 수 있습니다.
아까 얘기한 protocol 정의를 다시 리마인드하면 "작업의 설계도"와 같습니다.
아무튼 위 delegate 는 메세지를 전달하기 위해 사용되는 프로토콜입니다.
대리자 -> 프로토콜 채택
class MyViewController: UIViewController, MyButtonDelegate {
// Delegate 채택함!!!
let myButton = MyButton(type: .system)
....
myButton.delegate = self // delegate 는 나임!!!
//채택한 프로토콜 준수하기 위한 메소드 구현!!!
func buttonTapped(_ button: MyButton) {
print("Button tapped!")
}
}
여기서 아까 정의한 MyButtonDelegate 라는 프로토콜을 채택한 것을 볼 수 있습니다.
아까 MyButtonDelegate 프로토콜에는 buttonTapped 라는 메서드가 선언되어 있었는데 MyViewController 대리자는 이 메서드를 구현해야 합니다.
뷰 -> MyButton
import UIKit
protocol MyButtonDelegate: AnyObject {
func buttonTapped(_ button: MyButton)
}
class MyButton: UIButton {
weak var delegate: MyButtonDelegate?
override init(frame: CGRect) {
super.init(frame: frame)
// Interface Builder에서 쓰이지 않고, 코딩(Programmatically)으로 UIView를 상속받은 클래스를 만들 때 사용
// ex) let sampleButton = UIButton(frame: CGRect(x: 3, y: 0, width: 100, height: 200))
self.addTarget(self, action: #selector(buttonTapped(_:)), for: .touchUpInside)
}
required init?(coder: NSCoder) {
// Interface Builder에서 생성되는 초기화 구문
// Interface Builder란 간단하게 말해서는 xib, nib, storyboard를 사용하여 VIew를 작업하는 것!
fatalError("init(coder:) has not been implemented")
}
@objc private func buttonTapped(_ sender: UIButton) {
guard let delegate = delegate else { return }
guard let myButton = sender as? MyButton else { return }
delegate.buttonTapped(myButton)
}
}
class MyViewController: UIViewController, MyButtonDelegate {
override func viewDidLoad() {
super.viewDidLoad()
let myButton = MyButton(type: .system)
myButton.frame = CGRect(x: 100, y: 100, width: 100, height: 50)
myButton.setTitle("Tap me", for: .normal)
myButton.delegate = self // delegate 프로퍼티에 self 할당
self.view.addSubview(myButton)
}
func buttonTapped(_ button: MyButton) {
print("Button tapped!")
}
}
전체 코드를 다시 가져왔습니다.
MyButton 클래스에서 buttonTapped 함수를 구현한 이유는 해당 버튼이 탭되었을 때 실행되어야 하는 로직을 처리하기 위해서입니다.
그리고 MyButtonDelegate 프로토콜을 선언하고, weak var delegate: MyButtonDelegate? 라는 delegate 프로퍼티를 선언한 것은 MyButton 클래스 내에서 해당 버튼이 탭되었을 때 실행되어야 하는 로직을 MyViewController 클래스 내에서 구현하도록 위임하기 위해서입니다.
즉, MyButton 클래스는 버튼이 탭되었을 때 실행되어야 하는 로직을 구현하고, MyViewController 클래스는 이를 구현하기 위해 MyButtonDelegate 프로토콜을 준수하고, MyButton 클래스의 인스턴스의 delegate 프로퍼티에 자기 자신(self)을 할당하여 버튼 탭 이벤트가 발생하면 MyViewController 클래스 내의 buttonTapped 함수가 실행되도록 위임하고 있습니다.
이렇게 간단히 개념을 한 번 훑어보았습니다.
아무것도 모르는 상태라 쉽지 않았지만 이렇게 전체적으로 크게 훑어본 후에 세부 개념들을 자세히 훑어보면 더 잘 기억되지 않을까 싶습니다.
다음에는 protocol, 옵셔널 바인딩.. 세부 개념을 파헤쳐 보겠습니다.
'🦜 Swift' 카테고리의 다른 글
[iOS] 뷰 컨트롤러의 수명 주기, 팝업창 띄우기 - 2 (0) | 2023.05.13 |
---|---|
[iOS] Navigation Controller 공부 기록 - 1 (0) | 2023.05.13 |
[iOS] weak var (0) | 2023.05.04 |
[Swift] 인스턴스의 생성과 소멸 (0) | 2022.11.20 |
[Swift] 상속 (0) | 2022.11.20 |