13-2. 값 타입에 대한 초기화, 클래스에 대한 초기화(1)

구조체 타입에 대한 멤버별 초기화 구문

  1. 구조체 타입은 클로저 내 초기화 구문을 정의하지 않을 경우, 자동으로 멤버별 초기화 구문을 받는다. 기본 초기화 구문과 다르게 구조체는 기본값을 가지지 않은 저장된 프로퍼티라도 초기화 구문을 받는다.
struct Size {
	var width = 0.0, height = 0.0
}

let twoBytwo = Size(width : 2.0, height : 2.0)
//다음과 같이 기본값을 설정하여 초기화 구문 없이도 구조체 초기화가 가능하다.
let zeroByzero = Size()
//다음과 같이 구조체의 프로퍼티에 초기값을 지정한 경우에는 별도의 초기화 없이도 인스턴스 생선이 가능하다.
  1. 초기화 구문은 인스턴스의 초기화 부분을 수행하기 위해서 초기화 구문을 호출할 수 있다. 값 타입의 경우 자체 초기화 구문을 작성할 때 값 타입으로부터 다른 초기화 구문 참조를 위하여 self. init이라는 키워드를 사용한다. 초기화 구문 내에서만 self.init을 호출 할 수 있다.
struct Size {
	var width : 0.0, height : 0.0
}

struct Point {
	var x = 0.0, y = 0.0
}
//위의 두 구조체 값을 사용하는 Rect라는 새로운 구조체를 정의한다.

struct Rect {
	var origin = Point()
    var size = Size()
    init{}
    //일반 초기화 구문
    init(origin: Point, size : Size) {
    	self.origin = origin
        self.size = size
    }
    //두번째 사용자화 초기화 구문
    init(center : Point, size : Size) {
    	let originX = center.x - (size.width / 2)
        let originY = center.y - (size.height / 2)
        self.init(origin: Point(x : originX, y : originY), size : size)
    }
    //여기서의 특징은 self.init을 통해서 두 번쨰 사용자화 초기화 구문을 가져다가 새로운 초기화에 사용했다는 것이다.
}  

클래스의 상속과 초기화

  1. 상위 클래스에서 상속한 클래스의 모든 프로퍼티를 포함하는 모든 클래스의 저장된 프로퍼티는 초기화 중 반드시 초기값 할당이 되어야 한다. 지정된 초기화 구문은(designated initializer)는 클래스의 주 초기화 구문이다. 클래스의 경우 지정된 초기화 구문이 거의 없는 편이며 클래스별 하나만 있는 것이 일반적이다.
  2. 편의 초기화 구문(convenience initializer)는 클래스에 대해 초기화 구문을 지원하는 보조 초기화 구문이다. 지정된 초기화 구문의 파라미터를 기본값으로 설정하여 이와 동일한 클래스에서 지정된 초기화 구문을 호출하도록 할 수 있다.
init(parameters) {
 // statement
 }
 //다음은 지정된 초기화 구문이다.
 
 convenience init(parameters) {
 	//statement
}
//다음은 편의 초기화 구문이다. 앞에 convenience init이라는 키워드를 작성하여 사용한다.

초기화 구문의 상속과 재정의

  1. 상위 클래스 초기화 구문은 특정 상황에서 상속되지만, 안전하고 적절한 경우에 대해 상속된다. 상위 클래스에 지정된 초기화 구문을 재정의할 때는 override수식어를 작성해야 한다.
class Vehicle {
	var numberOfWheels = 0
    var description : String {
    	return "\(numberOfWheels) wheel(s)"
    }
}
//자동차 클래스를 정의하였다. 
let vehicle = Vehicle()
print(vehicle.description)
//0을 출력하게 된다.

class Bicycle : Vehicle {
	override init() {
    	super.init()
        numberOfWheels = 2
    }
}
//다음은 자동차 클래스를 상속하는 자전거라는 하위클래스를 정의한다.
//이 클래스의 초기화 구문은 상위 클래스의 초기화 구문인 super.init()을 호출하는 것으로 시작한다.
//하위 클래스의 초기화 구문이 초기화 프로세스의 2단계에서 사용자 정의없이 수행되고
//상위 클래스가 인자가 없는 지정된 초기화 구문을 가지고 있는 경우, super.init()을 생략할 수 있다.

class Hoverboard : Vehicle {
	var color : String
    init(color : String) {
    	self.color = color
        //super.init() // 암시적으로 호출되었으므로 코드를 명시하지 않아도 자동호출된다.
    }
    
    override var description : String {
    	return "\(super.description)"
    }
}
//다음의 클래스는 Color프로퍼티만 설정한다. 
//하위 클래스는 초기화 중 상속된 프로퍼티 변수 수정이 가능하지만 상수는 수정이 불가하다.
  1. 하위 클래스가 지정된 초기화 구문을 정의하지 않는 경우, 자동으로 상위 클래스의 지정된 초기화 구문 모두를 상속한다. 또한 하위 클래스가 사용자 정의 초기화 구문을 제공할 경우 모든 상위 클래스의 지정된 초기화 구문을 자동으로 상속한다.

지정된 초기화 구문화 편의 초기화 구문의 동작

  1. 아래의 예제에서는 지정 초기화 구문, 편의 초기화 구문, 자동상속 초기화 구문의 동작을 볼 수 있다.
class Food {
	var name : String
    init(name : String) {
    	self.name
    }
    //지정 초기화 구문
    
    convenience init() {
    	self.init(name : "[unnamed]")
    }
    //편의 초기화 구문
}

let namedMeat = Food(name : "bacon)
//namedMeat는 베이컨이라는 이름을 가지고 초기화를 거쳐 인스턴스가 생성된다.
//다음 지정 초기화 구문을 통해 새로운 Food 인스턴스에 저장된 모든 것은 완벽하게 초기화 된다. 

let mysteryMeat = Food()
//이 mysteryMeat는 [unnamed]를 출력하게 된다.
//이 클래스는 인자가 없는 init()의 편의 초기화도 제공한다. 

class RecipeIngredient : Food {
	var quantity : Int
    init(name : String, quantity : Int) {
    	self.quantity = quantity
        super.init(name : name)
    }
//이 클래스는 위의 Food클래스를 상속하며, 생성자 호출 간 두개의 파라미터를 받아 초기화를 진행한다. 이 때 name파라미터는 상속한 클래스의 지정 초기화를 위해 사용된다. 
	override convenience init(name : String) {
    	self.init(name : name, quantity : 1)
    }
}
//보는 것처럼 편의 초기화 구문은, 사용자가 인스턴스를 손쉽게 생성하는 경우와 그에 대한 초기화 상태를 미리 제공하는 것이다. 
//따라서 지정 초기화화 편의초기화는 엄연히 다르며, 편의초기화 구문도 클래스 상속 시,
//정상적으로 상속해야 하고, 생성자 재정의 시 override키워드를 붙여준다.
  1. 클래스 초기화 구문에 정의 앞에. required 수식어를 작성하여 클래스의 모든 하위 클래스가 해당 초기화 구문을 구현해야 함을 명시할 수 있다.
class SomeClass {
	required init() {
    	//statement
    }
}
//다음과 같은 경우 상속하는 모든 하위 클래스는 위의 초기화 구문을 구현해야 한다.

class someSubclass : SomeClass {
	required init() {
     // statement
    }
}

클로저 또는 함수를 사용하여 기본 프로퍼티 값 설정

저장된 프로퍼티의 기본값에 일부 사용자 정의 또는 설정이 필요한 경우 해당 프로퍼티에 대한 사용자 정의된 기본 값을 제공하기 위해 클로저를 사용할 수 있다. 그럴경우 인스턴스가 초기화 될 때마다 클로저가 호출되고 반환값이 기본값으로 할당된다.

class SomeClass {
	let someProperty : someType = {
    //클로저 안에 새로운 기본 값을 생성하고 선언한다 
    	return someValue
    }()
}

//아래의 예시는 체스 보드에서의 검정과 하얗의 색 값을 설정하기 위한 클로저로 초기화된다.

struct Chessboard {
	let boardColor : [Bool] = {
    	var temporaryBoard = [Bool]()
        var isBlack = false
        for i in 1...8 {
        	for j in 1...8 {
            	temporaryBoard.append(isBlack)
                isBlack = !isBlack
            }
            isBlack = !isBlack
        }
        return temporaryBoard
    }()
    //인스턴스가 생성될 때마다, 클로저가 실행되고 boardColors의 기본값은 계산되고 반환된다.

좋은 웹페이지 즐겨찾기