delegate
delgeate의 뜻 : 대표자, 위임하다
클래스나 구조체가 다른타입의 인스턴스에게 책임을 전달(위임)할수 있도록 하는 디자인 패턴
위임된 기능은 프로토콜에서 정의한다
delegate가 위임된 기능을 제공
위임은 특정작업에 응답하거나, 외부에서 데이터를 가져오는데 사용
대리자, 조력자 의 개념
어떠한 일이 있을 때 delegate가 대신 전담해달라는 개념
-> delegate로 선언된(보통 자신이 만든 클래스) 객체는 자신을 임명한 객체(테이블뷰, 피커뷰 등)가 일을 도와달라고 하면 지정된 메소드를 통하여 처리해줌
델리게이트 패턴
-> 하나의 객체가 모든일을 처리하는것이 아닌 일부 처리해야할 일 중 일부기능을 다른 객체에 넘기는 것
보통 프로토콜을 사용
class ViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource {
//ViewController 라는 이름의 클래스 생성 : 부모는 UIViewController, 프로토콜은 UIPickerViewDelegate(필요한 기능의 메소드만 구현), UIPickerViewDataSource(필수메소드 모두 구현해야함)
@IBOutlet var pickerImage : UIPickerView! //인스턴스 생성
pickerImage.delegate = self //pickerImage가 UIPickerView의 델리게이트임을 지정
func pikcerView(_ pickerView: UIPckerView, didSelectRow row: Int, inComponent component: Int) {
//comform
//피커뷰가 필요할 때 호출함
//사용자가 룰렛을 선택할때마다 피커뷰가 호출
}
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
//comform
//필수 메소드
//피커뷰가 컴포넌트의 수를 알고싶을때 호출
}
}
UIPickerViewDelegate : 어떤 행동에 대한 반응 동작 메소드(필요한 것만 구현)
UIPickerView에 대한 프로토콜로 UIPickerView를 도와줄 조력자
UIPickerView에 어떤 일이 일어났을 때 하고 싶은 일들이 메소드 목록(선언)되어 있다
UIPickerView를 사용하는 클래스에서는 UIPickerViewDelegate를 채택(adopt) 해야 하며
채택한 클래스에서는 자신이 델리게이트라고 지정해야함. -> pickerImage.delegate = self
구현한 기능은 iOS프레임워크 내부적으로 원하는 시점에 UIPickerView가 자동으로 호출(callback)
그 시점에서 하고 싶은 기능들을 메소드 내부에 구현
UIPickerViewDataSource : 데이터를 받아 뷰를 그려주는 메소드(필수메소드는 반드시 구현)
TableView의 DataSource
필수메소드 2개
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return items.count
} //numberOfRowsInSection section : 섹션의 행(row) 갯수
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellTypeIdentifier", for: indexPath)
cell.textLabel!.text = "Cell text"
return cell
} //cellForRowAt indexPath : 각 행에 들어가는 데이터
//섹션의 갯수는 default 1
TableView의 Delegate
UITableViewDelegate 프로토콜
header, footer view를 만들고 관리
행, header, footer 높이 지정
스무스한 스크롤링을 위해 높이 추정치 제공
행 선택시 하고싶은 작업
스와이프 할때 작업
테이블 내용 편집 지원
초기화
Designated Initializers & Convenience Initializers
다양한 방법으로 객체를 만들 수 있도록 편의를 제공하려면 init을 overloading해야 하고 코드 중복이 발생
코드 중복 방지
class Man {
var age : Int
var weight : Double
func display() {
print("나이 = \(age), 몸무게 = \(weight)")
}
init(age: Int, weight: Double) {
self.age = age // self.age 는 클래스의 프로퍼티
self.weight = weight // age 는 init의 매개변수
}
convenience init(age:Int) { // 매개변수 1개
self.init(age:age, weight: 3.5) // init overloading을 사용했다면 weight프로퍼티에 직접 초기값 부여
}
convenience init() { //매개변수 0개
self.init(age:20, weight: 60.5) // 프로퍼티 2개 다 초기값 부여
}
}
var kim = Man(age:10, weight: 20.4)
var lee : Man = Man(age: 1)
//주의사항
class Man {
var age : Int
var weight : Double
func display() {
print("나이 = \(age), 몸무게 = \(weight)")
}
init() {
self.age = 1
self.weight = 99
}
init(age: Int, weight: Double) {
self.age = age
self.weight = weight
}
convenience init(age:Int) { // convenience init(매개변수) {
self.init() // 초기화 위임 -> self.init()
self.age = age // 자신의 초기화 코드 -> self.age = age
} // } 위의 순서가 바뀌면 에러
}
var kim = Man() // 1번 init
var lee : Man = Man(age: 1, weight: 20.5) // 2번 init
var han = Man(age:20) // 3번 init
kim.display() // 1, 99
lee.display() // 1, 20.5
han.display() // 20, 99
failabel initiaizer (실패 가능한 생성자 : init? init!)
init 다음에 ? 나 ! 하며 옵셔널 값이 리턴 됨
오류 상황에 nil 값을 리턴하는 조건문이 있음 -> return nil
class Man {
var age : Int
var weight : Double
func display() {
print("나이 = \(age), 몸무게 = \(weight)")
}
init?(age: Int, weight: Double) { //실패 가능한 생성자
if age <= 0 {
return nil //오류상황에서는 nil 리턴
} else {
self.age = age
}
self.weight = weight
}
}
var kim : Man = Man(age: 1, weight: 20.5)
kim.display() // 옵셔널 값이므로 언래핑 해줘야 한다
//1. 옵셔널 바인딩 if let kim1 = kim { kim1.display() }
//2. 인스턴스 생성과 동시에 옵셔널 바인딩 if let kim2 = Man(age:1,weight:2){ kim2.display() }
//3. 강제 언래핑 -> crash
crash 날때 발생하는 오류와 .so파일
initializer가 상속 되는 경우
//자식클래스에 Designated Initializer가 없는 경우
class Man {
var age : Int
var weight : Double
func display() {
print("나이 = \(age), 몸무게 = \(weight)")
}
init(age: Int, weight: Double) {
self.age = age
self.weight = weight
}
convenience init(age:Int) {
self.init(age:age, weight: 3.5)
}
}
class Student : Man {
var name : String = "kim" //자식클래스의 프로퍼티
init(age:Int, weight:Double, name : String){ // 자식클래스의 Designated Initializer
self.name = name //자식클래스의 프로퍼티 초기화
super.init(age:age, weight:weight) //부모클래스의 init 호출
}
func namePlus() {
print("\(age),\(name),\(weight)")
}
}
var kim1 = Student(age: 20,weight: 65.2,name: "fewa")
kim1.display()
var lee1 = Student(age: 19,weight: 65.2,name: "fewa")
lee1.namePlus() //부모클래스의 Convenience Initializer 상속 불가능
//자식클래스에 초기화가 필요한 프로퍼티가 없을 경우
class Man {
var age : Int
var weight : Double
func display() {
print("나이 = \(age), 몸무게 = \(weight)")
}
init(age: Int, weight: Double) {
self.age = age
self.weight = weight
}
convenience init(age:Int) {
self.init(age:age, weight: 3.5)
}
}
var kim = Man(age:10, weight:20.5)
kim.display()
var lee = Man(age:1)
lee.display()
class Student : Man {
// 초기화가 필요한 프로퍼티가 없음
}
var kim1 = Student(age: 20,weight: 65.2) //Designated Initializer 상속
kim1.display()
var lee1 = Student(age: 19) //Convenience Initializer 상속
lee1.display()
class Man {
var age : Int
var weight : Double
func display() {
print("나이 = \(age), 몸무게 = \(weight)")
}
init(age: Int, weight: Double) {
self.age = age
self.weight = weight
}
convenience init(age:Int) {
self.init(age:age, weight: 3.5)
}
}
class Student : Man {
var name : String
override init(age:Int, weight:Double){
self.name = "Kim" //자식클래스의 프로퍼티 초기화
super.init(age:age, weight:weight) //부모클래스의 메소드 호출
}
}
var kim1 = Student(age: 20,weight: 65.2)
kim1.display()
var lee1 = Student(age: 19) //부모클래스의 Convenience Initializer 상속
lee1.display()
required initializer
부모클래스의 init 메소드 앞에 required 가 붙으면 자식 클래스에서 반드시 required 키워드로 재작성 해야한다
출처 : https://www.youtube.com/channel/UCM8wseo6DkA-D7yGlCrcrwA