메소드는 특정 형식에 속한 함수입니다. 인스턴스 메소드랑은 구현하는 위치와 인스턴스로 호출한다는 차이가 있습니다. 함수는 특정 형식에 연관되지 않은 동작을 구현합니다.
class Sample {
var data = 0
static var sharedData = 123
func doSomething() {
print(data)
// 스태틱 멤버는 타입 멤버와 같으므로, 형식 이름을 붙여야한다.
Sample.sharedData
}
func call() {
doSomething()
}
}
let a = sample()
a.data
// 인스턴스 메소드 호출
a.call()
struct Size {
var width = 0.0
var height = 0.0
// 값 형식에서는 속성을 바꾸려면, mutating을 붙여줘야 한다
mutating func enlarge() {
width += 1.0
height += 1.0
}
}
var s = Size()
s.enlarge()
형식에 연관된 메소드인 타입 메소드에 대해 알아보겠습니다.
// 문법
static func name(parameters) -> ReturnType {
statements
}
class func name(parameters) -> ReturnType {
statements
}
Type.method(parameters)
class Circle {
static let pi = 3.14
var radius = 0.0
func getArea() -> Double {
return radius * radius * Circle.pi
}
static func printPi() {
// 타입 메소드는 타입 속성에 바로 접근이 가능하다
print(pi)
}
}
Circle.printPi()
class StrokeCircle: Circle {
// static 타입 메소드를 서브 클래스에서 오버라이딩 불가하다. 에러 ! class로 선언하면 가능.
override static func printPi() {
print(pi)
}
}
서브 스크립트를 직접 구현하는 방법에 대해 알아보겠습니다.
값을 읽어야 하므로 get 블록 생략은 하면 x
subscript(parameters) -> ReturnTypes {
get {
return expression
}
set(name) {
statements
}
}
class List {
var data = [1, 2, 3]
// 인자라벨을 따로 구현하여 가독성을 높이는 방법도 있다.
subscript(i index: Int) -> Int {
get {
return data[index]
}
set {
data[Index] = newValue
}
}
}
subscript에서 두개의 파라미터를 전달 하려면, 콤마로 구분해서 전달 해야한다.
이는 점문법으로 서브스크립트에 접근하는 단축문법을 가능 하게 해줍니다.
@dynamicMemberLookup
struct Person {
var name: String
var address: String
subscript(dynamicMember member: String) -> String {
switch member {
case "nameKey":
return name
case "addressKey":
return address
dafault:
return "n/a"
}
}
}
let p = Person(name: "James", address: "seoul")
p[dynamicMember: "nameKey"] // James
p[dynamicMember: "addressKey"] // seoul
p.nameKey // James
p.addressKey // seoul
// 문법
class ClassName: SuperClassName {
}
class Figure {
var name = "Unknown"
init(name: String) {
self.name = name
}
func draw() {
print("draw \(name)")
}
}
// 상속
class Circle: Figure {
var radius = 0.0
}
// 상속받은 생성자를 사용하는 모습
let c = Circle(name: "Circle")
c.draw()
c.name
// 더 이상 상속을 할 수 없는 클래스, 다른 클래스를 상속하는건 가능하나
// final class 를 상속하는건 할 수 없다.
final class Rectangle: Figure {
var width = 0.0
var height = 0.0
}
서브 클래스는 슈퍼 클래스의 멤버를 상속합니다.
상속 받은 멤버나 메소드등을 서브클래스 구현에 맞게 재변경하는걸 오버라이딩 한다고 한다.
class Circle: Figure {
var radius = 0.0
// 읽기전용 속성을 추가
var diameter: Double {
return radius * 2
}
// 키워드가 필요하다 상위 클래스의 메소드를 아예 재구현한 버전
override func draw() {
print("hi")
}
// 상위 메소드에 더하는 버전
override func draw() {
super.draw()
print("hi")
}
}
// 속성을 오버라이딩 하는 방법
class Oval: Circle {
override var diameter: Double {
get {
return super.diameter
}
// 읽기 전용 속성을 읽기/쓰기 가능한 속성으로 오버라이딩 하는것은 가능하다.
// 반대는 허용되지 않는다.
set {
super.radius = newValue / 2
}
}
// 프로퍼티 관찰자는 변수 저장 속성에만 가능하다. 읽기-전용 속성에는 불가능
override var radius: Double {
willSet {
print(newValue)
}
didSet {
print(oldValue)
}
}
추가로 오버라이딩을 금지하려면 final 키워드를 멤버나, 메소드의 접두어에 작성하면 된다.
서브 클래스의 인스턴스를 슈퍼 클래스형식으로 타입을 저장하는걸 Upcasting 이라고 한다. Downcasting은 업캐스팅된 인스턴스를 다시 원래대로 처리하기 위해 사용합니다(더 낮은 계층으로는 불가). 타입 캐스팅을 사용함.
업캐스팅을 하면, 해당 슈퍼클래스 형식의 내부로만 접근이 가능하게 된다. 메모리 공간에는 하위 클래스의 멤버들이 생성되어 있기는 하다.
코드의 안전성을 위해서 사용하는것 같다. 필요없는 멤버의 접근을 막는것 같기도.
// Upcasting
let s: Figure = Square(name: "Square")
// Downcasting
let downcastedS = s as! Square