RW-Swift-5.1-Cheatsheet-1.0.pdf
3.21MB

Swift 5.1 관련하여 간단하게 개념만 집고가자!

 

  1. Declaring constants and variables
  2. Numeric type conversion
  3. String
  4. Tuple
  5. Optionals
  6. Collection Types: Array
  7. Collection Types: Dictionary
  8. Collection Types: Set

  9. Control Flow: Loops
  10. Control Flow: Conditionals
  11. Functions
  12. Closures
  13. Enumerations 
  14. Structs
  15. Classes
  16. Inheritance
  17. designated & Convenience Initializers

  18. Extensions
  19. Error Handling
  20. Coding Protocols
  21. Access Control
  22. 스위프트에서의 물음표와 느낌표

 

1. Declaring constants and variables

let double: Double = 2.0 
let inferredDouble = 2.0 

var mutableInt: Int = 1 


2. Numeric type conversion

let integerValue = 8 
let doubleValue = 8.0 

// error: type mismatch 
//let sum = integerValue + doubleValue 
let sum = Double(integerValue) + doubleValue 


3. String - TODO: string 비교

let helloWorld = "Hello, world" 

let helloWorldProgram = """ 
dfdf 
dfdf 
""" 

// emptyString 
let emptyString = ""        // Using string literal 
let anotherEmptyString = String() 

var mutableString = "Swift" 
mutableString += " is awesome!" 

print("This is my opinion: \(mutableString)") 


4. Tuple

- 여러 값을 group화 할 수 있는 자료형 => Tuples are useful for simple groups of related values

- decompose - let (code, reason) = httpError

- underscore (_) : ignoring parts of the tuple

- 인덱스 숫자로 접근하여 값을 가져올 수 있음

- element에 이름 추가 가능

// Group multiple values into a single compound value
// : a number and a human-readable description.
let httpError = (503, "Server Error") 

// decompose 
let (code, reason) = httpError 
let codeByIndex = httpError.0 
let reasonByIndex = httpError.1 

// _ : ignoring parts of the tuple 
let (_, justTheReason) = httpError 

// access using index numbers
print("The status code is \(http404Error.0)")

/-----------------------------------
// element 이름 추가 가능
let http200Status = (statusCode: 200, description: "OK")
print("The status code is \(http200Status.statusCode)")


5. Optionals

- 해당 자료형 값 또는 nil 값을 갖는 변수

var catchphrase: String?                     // optional String

let count3: Int?  = catchphrase?.count   // optional Int (catchphrase가 nil일 수도 있으니까요)

- ! (forced unwrapping opration) : nil이 아니면 unwrapped optional, nil이면 crash

- optional binding: if let, guard let

- ?? : coalescing operator

- ? : chaing operator

- implicitly unwarpped optionals : 강제적으로 optional unwrap

// optional: String or nil 값을 갖는 변수 
var catchphrase: String?    // called optional String 
catchphrase = "Hey, everybody?" 

// Forced uwrapping operation(!) 
// catchphrase이 nil이 아닐 경우 count 값을 가짐, nil이면 crash  
let count1: Int = catchphrase!.count 

// Optional binding 
// catchphrase?count : optional Int 
// optional Int에 값이 포함되어 있으면 count라는 constant 생성  
if let count = catchphrase?.count { 
    print(count) 
} 

// Coalescing operator (??) - coalesce: 합치다 
//catchphrase가 nil이 아니면 count2는 cathphrase의 count을 넣음; nil이면 0 
let count2: Int = catchphrase?.count ?? 0 

// Chaining operator (?) 
// Optional Int: catchphrase의 count or nil 
let count3: Int? = catchphrase?.count 

// Implicitly unwrapped optionals (implicit: 절대적인) 
let forcedCatchphrase: String! = "Hey, everybody?" 
let implicitCatchphrase = forcedCatchphrase // 값을 넣을 때 ! mark 필요 없음 


6. Collection Types: Array

- contains

- append, insert

- remove

- arr[0]

// let collection : reassign과 element 바꾸는 것 안됨 
let immutableArray: [String] = ["Alice", "Bob"] 

// 타입 추론: mutableArray [String] 
var muttableArray = ["Eve", "Frank"] 
let isEveThere = immutableArray.contains("Eve") 
let name: String = immutableArray[0] 

// index가 out of range이면 crash 
mutableArray[1] = "Bart" 

// immutableArray[1] = "Bart" // Error: 바꿀 수 없음 
mutableArray.append("Ellen") 
mutableArray.insert("Gemma", at: 1) 
let removedPerson = mutableArray.remove(at: 1) 

mutableArray = ["Ilary", "David"] 
mutableArray[0] = "John" 


7. Collection Types: Dictionary

- key가 존재하지 않으면 nil return : optional 값 리턴

- dic["name], removeValue(forKey: )

let immutableDict: [String: String] = ["name", "Kirk", "rank": "captain"] 
var mutableDict = ["name": "Picard", "rank": "captain"] 

// key가 존재하지 않으면 nil return (String? - optional String) 
let name2: String? = immutableDic["name"] 

// update value for key 
mutableDic["name"] = "Janeway" 

// add new key and value 
mutableDic["ship"] = "Voyager" 

// delete by key, 해당 key가 nil이 아니면 
let rankWasRemoved: String? = mutableDic.removeValue(forKey: "rank") 


8. Collection Types: Set

- list와 비슷하지만 중복된 item은 ignore

- contains, insert, remove

// Set: 중복된 item은 ignore 
let immutableSet: Set = ["chocolate", "vanilla", "chocolate"] 
var mutableSet: Set = ["butterscotch", "strawberry"] 

immutableSet.contains("chocolate") 
mutableSet.insert("green tea") 

// 해당 item을 찾지 못하면 nil return  
let flavorWasRemoved: String? = mutableSet.remove("strawBerry") 

9. Control Flow: Loops

// Iterator list or set 
for item in listOrSet { 
    print(item) 
} 
// Iterator over dictionary 
for (key, value) in dictionary { 
    print("\(key) = \(value)") 
} 

for i in 0...10 { 
    print(i)    // 0 to 10 
} 

for i in 0..<10 { 
    print(i)    // 0 to 9 
} 

var x = 0 
while x < 10 { 
    x += 1 
    print(x) 
} 

repeat { 
    x -= 1 
    print(x) 
} while(x > 0) 


10. Control Flow: Conditionals

let number = 88 

if (number <= 10) { 

} else if (number > 10 && number < 100) { 

} else { 

} 

// Ternary operator (ternary: 3으로 이루어진) 
let height = 100 
let isTall = height > 200 ? true : false 

// guard: program의 제어를 변형하기 위해 
for n in 1...30 { 
    guard n % 2 == 0 else { 
        continue 
    } 
    print("\(n) is even") 
} 

let year = 2012 
switch year { 
case 2003, 2004: 
    print("Panther or Tiger") 
case 2010: 
    print("Lion") 
case 2012...2015: 
    print("Mountain Lion through El Captain") 
default: 
    fatalError("Not already classified") 
} 


11. Functions

_: argument label 제외

// void function 
func sayHello() { 
    print("Hello") 
} 
// function with parameters 
func sayHello(name: String) { 
    print("Hello \(name)!") 
} 
// function with default parameters 
func sayHello(name: String = "Lorenzo") { 
    print("Hello \(name)!") 
} 

func sayHello(name: STring = "Lozenzo", age: Int) { 
    print("\(name) is \(age) years old!") 
} 

// using just the non default value 
sayHello(age: 35) 

// function with parameters and return value 
func add(x: Int, y: Int) -> Int { 
    return x + y 
} 
let value = add(x: 8, y:10) 

// single expression만 포함할 경우 return 키워드 제거 가능 
func multiply(x: Int, y: Int) -> Int { 
    x + y 
} 

// arguments label 명시 
func add(x xVal: Int, y yVal: Int) -> Int { 
    return xVal + yVal 
} 

// TODO: argement label 제외  
func add(_ x: Int, y: Int) -> Int { 
    return x + y 
} 
let value = add(8, y: 10) 

// parameter로 다른 함수 접근 
func doMath(operation: (Int, Int) -> Int, a: Int, b: Int) -> Int { 
    return operation(a, b) 
} 


12. Closures:  TODO: 실행하기

// TODO: 
let adder: (Int, Int) -> Int = {(x, y) in x + y} 
// argument의 약어 사용  
let square: (Int) -> Int = {$0 * $0} 
// 함수에 closure 전달  
let addWithClosure = doMath(operation: adder, a: 2, b: 3) 

13. Enumerations 

- allCases : CaseIterable protocol을 채택하면 사용 가능

- rawValue

- associated value(연관값): enum case문에 추가 정보를 덧붙일 수 있음 

  case text(String)

- switch문으로 associated value를 캐치할 수 있다.

  case .text(let value):

enum Taste { 
    case sweet, sour, salty, bitter, umami 
} 
let vinegarTaste = Taste.sour 

// Iterating through an enum class 
enum Food: CaseIterable { 
    case pasta, pizza, hamburger 
} 
for food in Food.allCases { 
    print(food) 
} 

// enum with String raw values 
enum Currency: String { 
    case euro = "EUR" 
    case dollar = "USD" 
    case pound = "GBP" 
} 
let euroSymbol = Currency.euro.rawValue 
print("The currency symbol for Euro is \(euroSymbol)") 

// enum with associated values 
// associated value(연관값):  
// 열거형의 케이스(case)에 추가적인 정보를 덧 붙일 수 있는 독특한 방법 
enum Content { 
    case empty 
    case text(String) 
    case number(Int) 
} 
// matching enumeration values with a switch statement 
let content = Content.text("Hello") 
switch content { 
case .empty: 
    print("Value is empty") 
case .text(let value):  // String value 추출 
    print("Value is \(value)") 
case .number(_):        // Int value ignore 
    print("Value is a number") 
} 


14. Structs

- member initializer 자동 생성됨

struct User { 
    var name: String 
    var age: Int = 40 
} 
// member initilizer는 자동적으로 생성됨. 
let john = User(name: "John", age: 35) 
// member initilizer는 기본 파라미터 값을 사용.  
// TODO: User()이렇게 해도 돼? 
let dave = User(name: "Dave") 

print("\(john.name) is \(john.age) years old") 


15. Classes

- 반드시 하나의 designated initializer를 가져야 함

- computed property

- deinit: object의 리소스가 해제될 때 수행

class Person { 
    let name: String 
    // class initializer(designated initializer) 
    init(name: String) { 
        self.name = name 
    } 
    // using deinit to perform object's resources cleanup 
    deinit { 
        print("Perfom the deinitialization") 
    } 

    var numberOfLaughts: Int = 0 
    func laugh() { 
        numberOfLaughts += 1 
    } 
    // define a computed property 
    var isHappy: Bool { 
        return numberOfLaughs > 0 
    } 
} 

let david = Person(name: "David") 
david.laugh() 
let happy = david.isHappy 


16. Inheritance

- override computed property

- final: subclass를 방지하기 위해 사용

class Student: Person { 
    var numberOfExams: Int = 0 

    // override isHappy computed property providing additional logic 
    override var isHappy: Bool { 
        numberOfLaughs > 0 && numberOfExams > 2 
    } 
} 

let ray = Student(name: "Ray") 
ray.numberOfExams = 4 
ray.laugh() 
let happy = ray.isHappy 
// final: subclass를 방지하기 위해 사용 
final class Child: Person { } 


17. designated & Convenience Initializers

- designated initializer: class는 반드시 하나 가져야 함

- convenience initializer: 옵션

// class는 반드시 최소한의 하나의 designated initilizer를 가져야 함 
// convenience initilizer는 옵션 
// TODO:  designated initilizer 정의 
class ModeOfTransportation { 
    let name: String 
    // designated initilizer 정의 
    init(name: String) { 
        self.name = name 
    } 
    // convenience initilizer 정의 
    convenience init() { 
        // 내부 designated initilizer에게 위임 
        self.init(name: "Not classified") 
    } 
} 

class Vehicle: ModeOfTransportation { 
    let wheels: Int 
     
    init(name: String, wheels: Int) { 
        self.wheels = wheels 
        // superclass의 designated initilizer로 위임 
        super.init(name: name) 
    } 
    // override superclass convenience initilizer 
    override convenience init(name: String) { 
       // 내부 designated initilizer에게 위임 
        self.init(name: name, wheels: 4) 
    } 
} 

18. Extensions

- 존재하는 class, structure, enumeration, protocol 타입에 새로운 기능 추가

- TODO: Category와 extension의 차이점은?

 extension String { 
    // String type 확장 - String instance가 truthy or falsy인지 판단 
    var boolValue: Bool { 
        if self == "1" { 
            return true 
        }  
        return false 
    } 
} 

let isTrue = "0".boolValue 


19. Error Handling

- Error protocol 채택하여 enum으로 정의

- do catch 문으로 에러 캐치

- try? : 해당 값에 error가 던져지면 nil로 반환 (optional 반환)

  try! : 해당 값에 error가 던져지면 런타임 에러(앱이 죽는다는 얘기... 절대로 에러가 발생하지 않을 경우만 사용)

// error 상속받아 enum으로 기술 
enum BeverageMatchineError: Error { 
    case invalidSelection 
    case insufficientFunds 
    case outOfStock 
} 

func selectBeverage(_ selection: Int) throws -> String { 
    return "Waiting for beverage" 
} 

// do clause의 code에 의해서 error가 던져지면 처리  
let message: String 
do { 
    message = try selectBeverage(20) 
} catch BeverageMatchineError.invalidSelection { 
    print("Invalid selection") 
} catch BeverageMatchineError.insufficientFunds { 
    print("Insufficient funds") 
} catch BeverageMatchineError.outOfStock { 
    print("Out of stock") 
} catch { 
    print("Generic error") 
} 

// try? error가 던져지면, 그 expression의 값은 nil로 처리 
let nillableMessage = try? selectBeverage(10) 

// try! : 런타임에 error를 받으면 error를 받음. 
let throwableMessage = try! selectBeverage(10) 


20. Coding Protocols

- Codable: Decodable + Encodable protocol

- JSONDecoder: JSON String -> Data

- JSONEncoder: Data -> JSON String

import Foundatation 

// Codable: Decodable, Encodable protocol 
struct UserInfo: Codable { 
    let username: String 
    let loginCount: Int 
} 

// CustomStringConvertible 채택 
extension UserInfo: CustomStringConvertible { 
    var description: String { 
        return "\(username) has tried to login \(loginCount) time(s)" 
    } 
} 

// string literal 
let json = """ 
    {"username" : "David", "loginCount" : 2} 
""" 

// JSONDecoder를 사용하여 JSON serialize : JSON string -> Data 
let decoder = JSONDecoder() 

// String을 data(struct)로 표현  
let data = json.data(using: .utf8)! 
let userInfo = try! decoder.decode(UserInfo.self, from: data) 
print(userInfo) 

// JSONEncoder 사용하여 struct serialize :  
let encoder = JSONEncoder() 
let userInfoData = try! encoder.encode(userInfo) 
// Data -> JSON String으로 표현 
let jsonString = String(data: userInfoData, encoding: .utf8)! 
print(jsonString) 


21. Access Control

- public

- fileprivate

- private

- access관련이 없을 경우

// module(framework or application): 코드가 배포의 single unit 
// public: 다른 모듈에서 접근 가능 
public class AccessLevelsShowcase { 
    public var somePublicProperty = 0 
    // ? 
    var someInternalProperty = 0 

    // 소스 파일을 정의한 것으로부터 접근 가능  
    fileprivate func someFilePrivateMethod() { } 
    //  
    private func somePrivateMethod() { } 
}


22. 스위프트에서의 물음표와 느낌표

스위프트에서 이 두 가지 구두 문자 (? 와 !)는 사용된 모든 용법에서 공통된 의미를 가지고 있음

물음표 : 무언가 확실하지 않다는 뜻

느낌표 : 경고 표지판 같은 용도, 잠재적으로 위험 동작을 수행한다.

 

옵셔널의 언랩핑과 마찬가지로 몇 라인 코드를 더 작성해야한다 할지라도 try!대신에 try try?를 사용할 것을 권장합니다. 물론 try!와 옵셔널 강제 언랩핑이 필요한 경우가 분명 존재합니다.

 

 

 

Ref. 

Ray Wenderlich website

https://outofbedlam.github.io/swift/2016/03/22/try/

GCD is a low-level C-based API.
NSOperation and NSOperationQueue are Objective-C classes.
NSOperationQueue is objective C wrapper over GCD. If you are using NSOperation, then you are implicitly using Grand Central Dispatch.

 

GCD advantage over NSOperation:

  1. implementation
    For GCD implementation is very light-weight
    NSOperationQueue is complex and heavy-weight

NSOperation advantages over GCD:

  1. Control On Operation
    you can Pause, Cancel, Resume an NSOperation
  2. Dependencies
    you can set up a dependency between two NSOperations operation will not started until all of its dependencies return true for finished.
  3. State of Operation
    can monitor the state of an operation or operation queue. ready ,executing or finished
  4. Max Number of Operation
    you can specify the maximum number of queued operations that can run simultaneously

When to Go for GCD or NSOperation

when you want more control over queue (all above mentioned) use NSOperation and for simple cases where you want less overhead (you just want to do some work "into the background" with very little additional work) use GCD

 

 

 

 

 

Ref. 

https://stackoverflow.com/questions/10373331/nsoperation-vs-grand-central-dispatch

Both are used to unwrapped the Optional variable. (Optional Binding)

 

if let

  1. Can not access out the scope.
  2. no need to return statement. But we can write
if let a = a() {
  let x = b(a)
  x.fn()
  if let u = x.nxt() {
    let ux = u.brm()
    if let uxt = ux.nxt() {
       perform(uxt)
    }
  }
}

 

guard let

  1. Early exist process from the scope
  2. Require score existing like return, Throw etc.
  3. Create a new variable those can be access out the scope.
guard let a = a() else { return }
let x = b(a)
x.fn()
guard let u = x.nxt() else { return }
let ux = u.brm()
guard let uxt = ux.nxt() else { return }

perform(uxt)

 

 

 

Ref. 

https://stackoverflow.com/questions/32256834/swift-guard-vs-if-let

https://outofbedlam.github.io/swift/2016/03/31/guard-concise/

특히 UIView 클래스 계층 중요!

 

 

NSObject에 구현되어 있으므로 모든 객체에서 사용 가능

 

Person *p1 = [[Person alloc] init];
Pereson *p2 = [p1 copy];

copy 메소드 실행하면

NSCopying protocol에 있는

- (instancetype)copyWithZone:(NSZone *)zone method 실행 (zone: 시스템에서 지정한 메모리 공간)

 

아래 메소드를 구현해줘야 함 (NSCopying protocol을 따르게 해야함)

- (instancetype)copyWithZone:(NSZone *)zone {
	Person *newPerson = [[Person allocWithZone:zone] init];
    // 초기화할 멤버가 있다면 여기서 해줍니다.
    return newPerson;
}

 

직렬화(Serialization): OOP언어에서 특정 클래스 오브젝트를 파일로 저장하거나 파일에서 읽어들일 때 특수하게 가공하는 것을 의미. Objective-c나 Swift에서는 이부분은 Encode, Decode 용어를 사용

 

Encode: 직렬화(Serialize) 한다

Decode: 직렬화된 데이터를 오브젝트로 풀어내는 것(deserialization)을 의미

직렬화에서도 KVC(Key-Value Coding) 개념 사용됨 - property와 key 연결

NSCoder

  • byte stream을 추상화한 것
  • 데이터를 Coder로 쓰거나 Coder에서 데이터를 읽어 올 수 있음.
    (Coder - NSData 클래스에서 생성한 객체)
  • NSKeyedUnarchiver, NSKeyedArchiver를 사용하여 데이터 기록
    (NSCoder는 추상 클래스)

NSCoding protocol

- (id)initWithCoder:(NSCoder *)coder;               // 직렬화된 데이터에서 Object를 만들어 낼 때 호출

- (void)encodeWithCoder:(NSCoder *)coder;    // 직렬화할 때 자동 호출

 

NSKeyArchiver

// Swift
let data = NSKeyedArchiver.archivedDataWithRootObject(object)
NSUserDefaults.standardUserDefaults().setObject(data, forKey: "object-key")

// Objective-c
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:object];
[[NSUserDefaults standardUserDefaults] setObject:data forKey:@"object-key"];

 

NSKeyedUnarchiver

// Swift
if let data: NSData = NSUserDefaults.standardUserDefaults().objectForKey("object-key") as? NSData {
    let object: SomePersonClass = NSKeyedUnarchiver.unarchiveObjectWithData(data) as SomePersonClass
}

// Objective-C
NSData *data = [[NSUserDefaults standardUserDefaults] objectForKey:@"object-key"];
SomePersonClass *object = [NSKeyedUnarchiver.unarchiveObjectWithData:data];

 

NSUserDefaults

  • 파일 시스템에 초기 기본 설정과의 차이점을 User default database에 저장함
  • 프리미티브 타입이 아닌 객체를 저장하고 싶으면 위의 NSCoding protocol을 적용하여 저장함.

+ (NSUserDefaults *)standardUserDefaults    // 공유된 기본설정 객체
- (void)registerDefaults:(NSDictionary *)dictionary    // 초기 기본설정 등록

// 설정을 바꾸는 메소드
- (void)setBool:(BOOL)value forKey:(NSString *)defaultName 
- (void)setFloat:(float)value forKey:(NSString *)defaultName 
- (void)setInteger:(NSInteger)value forKey:(NSString *)defaultName 
- (void)setObject:(id)value forKey:(NSString *)defaultName

- (BOOL)boolForKey:(NSString *)defaultName
- (float)floatForKey:(NSString *)defaultName
- (NSInteger)intgerForKey:(NSString *)defaultName
 - (id)objectForKey:(NSString *)defaultName

- (void)removeObjectForKey:(NSString *)defaultName

 

 

 

 

Ref. http://seorenn.blogspot.com/2014/11/swiftobjective-c-serialization.html

Key-value coding

  • 변수 이름으로 변수의 값을 선정하거나 가져오는 방식 (key-value mapping)

  • 변수 이름: key, string
    문자열을 이용해 property에 접근
    - 접근자(Accessor Methods) 통하지 않고 property 이름인 문자열로 접근하므로, 객체간 의존성을 낮추고 결합도가 낮은 소프트웨어 개발을 있음.

  • 관련 함수는 NSKeyValueCoding 프로토콜에 의해 정의됨.
    NSObject가 이 protocol을 confirm하므로 모든 자료형 가능

    - setValue:forKey:

    - valueForKey:

 

// set value
Student *s = [[Student alloc] init];
[s setValue:@“Larry” forKey:@“firstName”];

// get value
NSString *x = [s valueForKey:@“firstName”];

 

 

Key paths

  • 객체들을 특정 경로로 정렬.

  • 이름을 가져오는데 키 경로(Key Path)를 이용
    NSString *mn = [selectedPerson valueForKeyPath:@“spouse.scotter.modelName”];

  • 키 경로 연산자: @avg, @count, @max, @min, @sum
    NSNumber *theAvg = [employees valueForKeyPath:@“@avg.expctedRaise”];

 

Key-value Observing

  • 객체의 property 변경되는 것을 알고 싶을  사용하는 기능.
    (keypath 통해 property 변경을 감지하고 알려줌)

- (void)addObserver:(NSObject *)anObserver

               forKeyPath:(NSString *)keyPath

                    options:(NSKeyValueObservingOptions)options

                   context:(void *)context

      • keyPath 지정된 property 감시할 것을 등록.
      • Observer 객체는 anObserver, 
      • options property 변경될  보내지는 notification message이며, 
        종류는 NSKeyValueObservingOptionNew, NSKeyValueObservingOptionOld, OR 연산으로 두가지 같이   있음.

- (void)observeValueForKeyPath:(NSString *)keyPath

                                      ofObject:(id)object

                                        change:(NSDictionary *)change

                                        context:(void *)context

// NSObject에 정의  -> fido의 값이 변경되면 나에게 메시지를 줘!
[theAppDelegate addObserver:self
                 forKeyPath:@“fido”
                    options:NSKeyValueChangeOldKey
                     context:somePointer];

/* keypath : @“fido”
object: AppDelegate
context: observer로 등록할 때 인수로 사용한 context 주소 공간을 가리키는 포인터
change: fido 이전값, 새로운 값 
*/
- (void)observeValueForKeyPath:(NSString *)keyPath
				   	  ofObject:(id)object
					    change:(NSDictionary *)change
					   context:(void *)context {
                       //...
}

Cocoa Framework

  • 목적에 맞게 확장해야 할 기존 객체가 많음

  • ex) TableView의 subclass를 만드는 대신에, 간단하게 TableView에 helper object를 주면 됨.

Delegate

  • delegate outlet이 helper object를 가리키도록 설정

UITableView

  • dataSource라는 helper object가 있음 
    - UITableDataSource의 informal protocol을 준수해야함.

 

Delegate 동작 방식

객체가 delegate 메서드를 구현하면 Cocoa framework가 그 메서드 호출

NSObject에 아래 함수 가지고 있음
- (BOOL)respondsToSelector:(SEL)aSelector; // aSelector 메서드 존재 시 YES return

// delegate가 메서드를 구현했는지 확인
if([delegate respondsToSelector:@selector(tableView:shouldSelectRow:)]) {
    // 메서드 실행
    ok = [delegate tableView:self shouldSelectRow:rowIndex];
}

 

Protocol

java에서의 interface (약속!!!!)

 

- protocol: method 정의

- implement: class에서 사용

+ Recent posts