Extension과 Protocol은 Swift에서 자주 사용되는 기능이다. 값에 접근이 불가함에도 Extension으로 추가 기능을 구현할 수 있고, Protocol의 경우 POP라는 개념으로 Apple에서 밀어주는? 개념이다. Generic의 경우 코드 중복을 줄일 수 있는 좋은 기능이다. 잘 다뤄둔다면 중급(?) 이상의 개발자가 되는데 큰 도움을 줄 것이다.(~그렇게 믿고 있다 ㅜㅜ~) 그럼 시작해보자!
어떤 작업/기능을 위한 method, property의 interface 정의시 사용
class, struct, enum에 채택되며 그때 해당 type은 요구 사항을 구현 해야 함
이를 구현한 경우, type이 protocol을 준수한다고 함
Objective-C에 비해 나아진 점
예시
protocol SomeProtocol {
var mustBeSettable: Int { get, set }
var doesNotNeedToBeSettable: Int { get }
}
Protocol Type
Inheritance
Class-only Protocol
protocol SomeClassOnlyProtocol: AnyObject, SomeInheritedProtocol {
// statement
}
Protocol Composition
두개 이상 protocol을 만족하는 type을 정의할 수 있음
protocol Named {
var name: String { get }
}
protocol Aged {
var age: Int { get }
}
struct Person: Named, Aged {
var name: String
var age: Int
}
func withHappyBirthday(to celebrator: Named & Aged) {
// statement
}
is
, as
연산자의 의미
is
as
as?
as!
Optinal Protocol Requirement
@objc
attribute 사용하여 선언@objc optional var ...
@objc optional func ...
Protocol Constraint
where
사용protocol RandomBAckgroundColorView where Self: UIView {
// statement
}
Protocol Extension
extension RandomNumberGenerator {
func randomBool() -> Bool {
return random() > 0.5
}
}
extension CounterDataSource {
var fixedIncrement: Int {
return 0
}
}
optional
을 대체할 수 있음@objc
attribute 지울 수 있음where
사용extension Collection where Element: Equatable {
func allEqual() -> Bool {
for element in self {
if element != self.first {
return False
}
}
}
}
<>
안에 들어간 것을 placeholder라 함
function내부에서 parameter type이나 return type으로 사용가능
func swap<T>(_ a: inout T, _ b: inout T) {
let temp = a
a = b
b = a
}
struct Stack<Element> {
var items = [Element]()
mutating func push(_ item: Element) {
self.items.append(item)
}
mutating func pop() -> Element {
return self.items.removeLast()
}
}
Type Constraint
func someFunction<T: SomeClass, U: SomeProtocol>(someT: T, someU: U) {
}
Associated Type
protocol 정의 시 그 protocol이 사용할 임의의 type을 선언해 둘 수 있음
associatedtype
protocol Container {
associatedtype Item // Item이라는 type이 있을 거야~
mutating func append(_ item: Item)
var count: Int { get }
subscript(i: Int) -> Item { get }
}
struct Stack<Element>: Container {
var items = [Element]()
mutating func push(_ item: Element) {
self.items.append(item)
}
mutating func pop() -> Element {
return self.items.removeLast()
}
typealias Item = Element // associated type인 Item을 Element라 할거야: type inference로 생략가능
mutating func append(_ item: Element) {
self.push(item)
}
var count: Int {
return items.count
}
subscript(i: Int) -> Element {
return items[i]
}
}
where
func allItemsMatch<C1: Container, C2: Container>(_ c1: C1, c2: C2) -> Bool where C1.item == C2.Item, C1.Item: Equatable {
}
C1.item == C2.Item
은 두 container의 item이 동일한 type이라는 제약C1.Item: Equatable
item이 비교 가능한 type이어야 한다는 제약