신속한 건설 과정


구성 프로세스는 클래스, 구조 또는 열거형 유형의 인스턴스를 사용하기 위한 준비 프로세스입니다. 이 프로세스에는 인스턴스의 각 속성에 대한 초기 값을 설정하고 필요한 준비 및 초기화 작업을 수행하는 작업이 포함됩니다.

Swift 생성자는 init() 메소드를 사용합니다.

Objective-C의 생성자와 달리 Swift의 생성자는 값을 반환할 필요가 없습니다. 주요 임무는 새 인스턴스가 처음 사용되기 전에 적절하게 초기화되었는지 확인하는 것입니다.

클래스 인스턴스는 초기화 해제를 정의하여 클래스 인스턴스가 해제되기 전에 메모리 정리 작업을 수행할 수도 있습니다.



저장된 속성의 초기 할당

클래스 및 구조체의 인스턴스를 생성할 때 모든 저장된 속성에 대해 적절한 초기값을 설정해야 합니다.

저장된 속성이 생성자에 할당되면 해당 값이 직접 설정되고 속성 관찰자가 트리거되지 않습니다.

생성자의 저장소 속성 할당 프로세스:

  • 초기값을 생성합니다.

  • 속성 정의에서 기본 속성 값을 지정하세요.

  • 인스턴스를 초기화하고 init() 메서드를 호출합니다.


생성자

생성자는 특정 유형의 새 인스턴스를 생성할 때 호출됩니다. 가장 간단한 형태는 init 키워드의 이름을 딴 매개 변수가 없는 인스턴스 메서드와 유사합니다.

Syntax

init()
{
    // 实例化后执行的代码
}

Example

다음 구조는 매개변수 없이 생성자 init를 정의하고 저장된 속성 length 및 width 값을 6과 12로 초기화합니다.

struct rectangle {
    var length: Double
    var breadth: Double
    init() {
        length = 6
        breadth = 12
    }
}
var area = rectangle()
print("矩形面积为 \(area.length*area.breadth)")

위 프로그램 실행의 출력 결과 is :

矩形面积为 72.0

기본 속성 값

생성자에서 저장된 속성의 초기 값을 설정할 수 있으며, 속성이 선언될 때 속성의 기본값을 설정할 수도 있습니다.

기본값을 사용하면 생성자를 더 간단하고 명확하게 만들 수 있으며, 속성 유형을 기본값에서 자동으로 추론할 수 있습니다.

다음 예에서는 속성이 선언될 때 속성의 기본값을 설정합니다.

struct rectangle {
	// 设置默认值
    var length = 6
    var breadth = 12
}
var area = rectangle()
print("矩形的面积为 \(area.length*area.breadth)")

위 프로그램 실행의 출력 결과는 다음과 같습니다.

矩形面积为 72

구성 매개변수

constructor init(), 다음과 같이 표시:

struct Rectangle {
    var length: Double
    var breadth: Double
    var area: Double
    
    init(fromLength length: Double, fromBreadth breadth: Double) {
        self.length = length
        self.breadth = breadth
        area = length * breadth
    }
    
    init(fromLeng leng: Double, fromBread bread: Double) {
        self.length = leng
        self.breadth = bread
        area = leng * bread
    }
}

let ar = Rectangle(fromLength: 6, fromBreadth: 12)
print("面积为: \(ar.area)")

let are = Rectangle(fromLeng: 36, fromBread: 12)
print("面积为: \(are.area)")

위 프로그램 실행의 출력 결과는 다음과 같습니다.

面积为: 72.0
面积为: 432.0

내부 및 외부 매개변수 이름

은 함수 및 메소드 매개변수와 동일합니다. 내부에 사용되는 매개변수 이름도 있습니다. 생성자를 호출할 때 사용되는 생성자와 매개변수 이름입니다.

그러나 생성자는 함수나 메소드처럼 괄호 앞에 구별 가능한 이름이 없습니다. 따라서 생성자를 호출할 때 호출할 생성자는 주로 생성자에 있는 매개변수 이름과 유형에 따라 결정됩니다.

생성자를 정의할 때 매개변수의 외부 이름을 제공하지 않으면 Swift는 내부 이름과 동일한 각 생성자 매개변수에 대해 자동으로 외부 이름을 생성합니다.

struct Color {
    let red, green, blue: Double
    init(red: Double, green: Double, blue: Double) {
        self.red   = red
        self.green = green
        self.blue  = blue
    }
    init(white: Double) {
        red   = white
        green = white
        blue  = white
    }
}

// 创建一个新的Color实例,通过三种颜色的外部参数名来传值,并调用构造器
let magenta = Color(red: 1.0, green: 0.0, blue: 1.0)

print("red 值为: \(magenta.red)")
print("green 值为: \(magenta.green)")
print("blue 值为: \(magenta.blue)")

// 创建一个新的Color实例,通过三种颜色的外部参数名来传值,并调用构造器
let halfGray = Color(white: 0.5)
print("red 值为: \(halfGray.red)")
print("green 值为: \(halfGray.green)")
print("blue 值为: \(halfGray.blue)")

위 프로그램 실행의 출력 결과는 다음과 같습니다.

red 值为: 1.0
green 值为: 0.0
blue 值为: 1.0
red 值为: 0.5
green 值为: 0.5
blue 值为: 0.5

외부 이름 매개변수 없음

생성자의 매개변수에 외부 이름을 제공하지 않으려면 밑줄 _을 사용하여 외부 이름을 표시할 수 있습니다. 그것을 설명합니다.

struct Rectangle {
    var length: Double
    
    init(frombreadth breadth: Double) {
        length = breadth * 10
    }
    
    init(frombre bre: Double) {
        length = bre * 30
    }
    //不提供外部名字
    init(_ area: Double) {
        length = area
    }
}

// 调用不提供外部名字
let rectarea = Rectangle(180.0)
print("面积为: \(rectarea.length)")

// 调用不提供外部名字
let rearea = Rectangle(370.0)
print("面积为: \(rearea.length)")

// 调用不提供外部名字
let recarea = Rectangle(110.0)
print("面积为: \(recarea.length)")

위 프로그램 실행의 출력 결과는 다음과 같습니다.

面积为: 180.0
面积为: 370.0
面积为: 110.0

옵션 속성 유형

사용자 정의된 유형에 논리적으로 null 값을 허용하는 저장된 속성이 포함된 경우 이를 옵션 유형(옵션 속성 유형)으로 정의해야 합니다.

저장 속성이 선택 사항으로 선언되면 자동으로 빈 nil로 초기화됩니다.

struct Rectangle {
    var length: Double?
    
    init(frombreadth breadth: Double) {
        length = breadth * 10
    }
    
    init(frombre bre: Double) {
        length = bre * 30
    }
    
    init(_ area: Double) {
        length = area
    }
}

let rectarea = Rectangle(180.0)
print("面积为:\(rectarea.length)")

let rearea = Rectangle(370.0)
print("面积为:\(rearea.length)")

let recarea = Rectangle(110.0)
print("面积为:\(recarea.length)")

위 프로그램 실행의 출력 결과는 다음과 같습니다.

面积为:Optional(180.0)
面积为:Optional(370.0)
面积为:Optional(110.0)

구성 중 상수 속성 수정

구성 프로세스가 끝나기 전에 상수 값을 결정할 수 있는 한 값을 수정할 수 있습니다. 건설 프로세스 중 어느 시점에서든 일정한 속성을 갖습니다.

클래스 인스턴스의 경우 상수 속성은 이를 정의하는 클래스의 생성 프로세스 중에만 수정할 수 있습니다. 하위 클래스에서는 수정할 수 없습니다.

길이 속성은 이제 상수이지만 해당 클래스의 생성자에서 해당 값을 설정할 수 있습니다.

struct Rectangle {
    let length: Double?
    
    init(frombreadth breadth: Double) {
        length = breadth * 10
    }
    
    init(frombre bre: Double) {
        length = bre * 30
    }
    
    init(_ area: Double) {
        length = area
    }
}

let rectarea = Rectangle(180.0)
print("面积为:\(rectarea.length)")

let rearea = Rectangle(370.0)
print("面积为:\(rearea.length)")

let recarea = Rectangle(110.0)
print("面积为:\(recarea.length)")

위 프로그램 실행의 출력은 다음과 같습니다.

面积为:Optional(180.0)
面积为:Optional(370.0)
面积为:Optional(110.0)

기본 생성자

기본 생성자는 간단히 생성됩니다. 모든 속성 값이 기본값으로 설정된 인스턴스:

다음 예에서는 ShoppingListItem 클래스의 모든 속성이 기본값을 가지며 상위 클래스가 없는 기본 클래스에 대해 자동으로 기본값을 가져옵니다. 모든 속성 값에 대한 기본 생성자

class ShoppingListItem {
    var name: String?
    var quantity = 1
    var purchased = false
}
var item = ShoppingListItem()


print("名字为: \(item.name)")
print("数理为: \(item.quantity)")
print("是否付款: \(item.purchased)")

위 프로그램 실행의 출력은 다음과 같습니다.

名字为: nil
数理为: 1
是否付款: false

구조에 대한 멤버별 초기화

구조가 모든 저장된 속성에 대해 기본값을 제공하고 사용자 정의된 초기화를 제공하지 않는 경우 , 멤버별 생성자를 자동으로 얻을 수 있습니다.

멤버별 생성자를 호출할 때 멤버 속성 이름과 동일한 매개변수 이름을 전달하여 멤버 속성의 초기 할당을 완료합니다.

다음 예에서는 길이와 너비라는 두 가지 속성을 포함하는 Rectangle 구조를 정의합니다. Swift는 100.0과 200.0의 초기 할당을 기반으로 이 두 속성의 Double 유형을 자동으로 추론할 수 있습니다.

struct Rectangle {
    var length = 100.0, breadth = 200.0
}
let area = Rectangle(length: 24.0, breadth: 32.0)

print("矩形的面积: \(area.length)")
print("矩形的面积: \(area.breadth)")

두 저장 속성 모두 기본값을 가지므로 Rectangle 구조는 자동으로 멤버별 생성자 init(너비:높이:)를 가져옵니다. 이를 사용하여 Rectangle의 새 인스턴스를 만들 수 있습니다.

위 프로그램의 실행 출력은 다음과 같습니다.

名字为: nil
矩形的面积: 24.0
矩形的面积: 32.0

값 유형의 생성자 프록시

생성자는 다른 생성자를 호출하여 인스턴스 생성 프로세스의 일부를 완료할 수 있습니다. 이 프로세스를 생성자 위임이라고 하며 여러 생성자 간의 코드 중복을 줄입니다.

다음 예에서 Rect 구조는 Size 및 Point의 생성 프로세스를 호출합니다.

struct Size {
    var width = 0.0, height = 0.0
}
struct Point {
    var x = 0.0, y = 0.0
}

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)
    }
}


// origin和size属性都使用定义时的默认值Point(x: 0.0, y: 0.0)和Size(width: 0.0, height: 0.0):
let basicRect = Rect()
print("Size 结构体初始值: \(basicRect.size.width, basicRect.size.height) ")
print("Rect 结构体初始值: \(basicRect.origin.x, basicRect.origin.y) ")

// 将origin和size的参数值赋给对应的存储型属性
let originRect = Rect(origin: Point(x: 2.0, y: 2.0),
    size: Size(width: 5.0, height: 5.0))

print("Size 结构体初始值: \(originRect.size.width, originRect.size.height) ")
print("Rect 结构体初始值: \(originRect.origin.x, originRect.origin.y) ")


//先通过center和size的值计算出origin的坐标。
//然后再调用(或代理给)init(origin:size:)构造器来将新的origin和size值赋值到对应的属性中
let centerRect = Rect(center: Point(x: 4.0, y: 4.0),
    size: Size(width: 3.0, height: 3.0))

print("Size 结构体初始值: \(centerRect.size.width, centerRect.size.height) ")
print("Rect 结构体初始值: \(centerRect.origin.x, centerRect.origin.y) ")

위 프로그램의 실행 출력은 다음과 같습니다.

Size 结构体初始值: (0.0, 0.0) 
Rect 结构体初始值: (0.0, 0.0) 
Size 结构体初始值: (5.0, 5.0) 
Rect 结构体初始值: (2.0, 2.0) 
Size 结构体初始值: (3.0, 3.0) 
Rect 结构体初始值: (2.5, 2.5)

Constructor 프록시 규칙

값 유형클래스 유형
상속은 지원되지 않으므로 생성자 위임 프로세스는 자신이 제공한 다른 생성자에게만 위임할 수 있기 때문에 상대적으로 간단합니다. self.init를 사용하여 사용자 정의 생성자에서 동일한 값 유형의 다른 초기화 프로그램을 참조할 수 있습니다. 다른 클래스에서 상속할 수 있습니다. 즉, 클래스는 상속된 모든 저장 속성이 생성 중에 올바르게 초기화되도록 하는 책임을 집니다.

클래스 상속 및 생성 프로세스

Swift는 모든 클래스 인스턴스의 저장된 속성이 초기 값을 얻을 수 있도록 두 가지 유형의 클래스 생성자를 제공합니다. 이들은 지정 초기화와 편의 초기화입니다.

지정 생성자편의 생성자
클래스에서 가장 중요한 생성자클래스의 보조 및 보조 생성자
클래스에서 제공하는 모든 속성을 초기화하고, 클래스의 생성자를 호출합니다. 상위 클래스 체인을 따라 상위 클래스를 상향 조정하여 상위 클래스의 초기화를 구현합니다. 편의 초기화는 동일한 클래스에서 지정된 생성자를 호출하고 해당 매개변수에 대한 기본값을 제공하도록 정의할 수 있습니다. 또한 특별한 목적을 위해 또는 특정 입력을 사용하여 인스턴스를 생성하기 위해 편의 초기화를 정의할 수도 있습니다.
모든 클래스에는 지정된 초기화가 하나 이상 있어야 합니다.필요한 경우에만 클래스에 편의 초기화를 제공하세요.
Init(parameters) {
    statements
}
convenience init(parameters) {
      statements
}

지정된 생성자 인스턴스

class mainClass {
    var no1 : Int // 局部存储变量
    init(no1 : Int) {
        self.no1 = no1 // 初始化
    }
}
class subClass : mainClass {
    var no2 : Int // 新的子类存储变量
    init(no1 : Int, no2 : Int) {
        self.no2 = no2 // 初始化
        super.init(no1:no1) // 初始化超类
    }
}

let res = mainClass(no1: 10)
let res2 = subClass(no1: 10, no2: 20)

print("res 为: \(res.no1)")
print("res2 为: \(res2.no1)")
print("res2 为: \(res2.no2)")

위 프로그램 실행의 출력 결과는

res 为: 10
res 为: 10
res 为: 20

편의 생성자 인스턴스

class mainClass {
    var no1 : Int // 局部存储变量
    init(no1 : Int) {
        self.no1 = no1 // 初始化
    }
}

class subClass : mainClass {
    var no2 : Int
    init(no1 : Int, no2 : Int) {
        self.no2 = no2
        super.init(no1:no1)
    }
    // 便利方法只需要一个参数
    override convenience init(no1: Int)  {
        self.init(no1:no1, no2:0)
    }
}
let res = mainClass(no1: 20)
let res2 = subClass(no1: 30, no2: 50)

print("res 为: \(res.no1)")
print("res2 为: \(res2.no1)")
print("res2 为: \(res2.no2)")

위 프로그램 실행의 출력 결과는

res 为: 20
res2 为: 30
res2 为: 50

생성자의 상속과 오버로드

Swift의 하위 클래스 상위 클래스의 생성자는 기본적으로 상속되지 않습니다.

상위 클래스의 생성자는 확실하고 안전한 경우에만 상속됩니다.

부모 클래스 지정 생성자를 재정의하는 경우 재정의 수정자를 작성해야 합니다.

class SuperClass {
    var corners = 4
    var description: String {
        return "\(corners) 边"
    }
}
let rectangle = SuperClass()
print("矩形: \(rectangle.description)")

class SubClass: SuperClass {
    override init() {  //重载构造器
        super.init()
        corners = 5
    }
}

let subClass = SubClass()
print("五角型: \(subClass.description)")

위 프로그램 실행의 출력 결과는 다음과 같습니다.

矩形: 4 边
五角型: 5 边

지정 생성자 및 편의 생성자의 인스턴스

다음 예에서는 동작 중인 지정 생성자, 간편 초기화 및 자동 생성자의 상속을 보여줍니다.

MainClass와 SubClass라는 두 클래스를 포함하는 클래스 계층 구조를 정의하고 해당 생성자가 상호 작용하는 방식을 보여줍니다.

class MainClass {
    var name: String
    
    init(name: String) {
        self.name = name
    }
    
    convenience init() {
        self.init(name: "[匿名]")
    }
}
let main = MainClass(name: "php")
print("MainClass 名字为: \(main.name)")

let main2 = MainClass()
print("没有对应名字: \(main2.name)")

class SubClass: MainClass {
    var count: Int
    init(name: String, count: Int) {
        self.count = count
        super.init(name: name)
    }
    
    override convenience init(name: String) {
        self.init(name: name, count: 1)
    }
}

let sub = SubClass(name: "php")
print("MainClass 名字为: \(sub.name)")

let sub2 = SubClass(name: "php", count: 3)
print("count 变量: \(sub2.count)")

위 프로그램 실행의 출력 결과는 다음과 같습니다.

MainClass 名字为: php
没有对应名字: [匿名]
MainClass 名字为: php
count 变量: 3

클래스의 실패 가능한 생성자

클래스, 구조체 또는 열거형 개체가 자체 생성 과정에서 실패할 수 있는 경우 실패 가능한 생성자를 정의합니다.

변수 초기화 실패의 가능한 이유는 다음과 같습니다.

  • 잘못된 매개변수 값이 전달되었습니다.

  • 일부 필수 외부 리소스가 누락되었습니다.

  • 특정 조건이 충족되지 않습니다.

이 공사 과정에서 실패할 수 있는 상황을 적절하게 처리하기 위해서입니다.

클래스, 구조 또는 열거형 유형의 정의에 실패할 수 있는 하나 이상의 초기화 프로그램을 추가할 수 있습니다. 구문은 init 키워드 뒤에 물음표(init?)를 추가하는 것입니다.

예제

다음 예에서는 종이라는 문자열 유형의 상수 속성을 갖는 Animal이라는 구조가 정의됩니다.

동시에 구조는 문자열 유형 매개변수 종을 사용하여 실패할 수 있는 생성자를 정의합니다. 이 실패 가능한 초기화는 들어오는 매개변수가 빈 문자열인지 확인하는 데 사용됩니다. 빈 문자열이면 실패할 수 있는 초기화는 개체 생성에 실패하고 그렇지 않으면 성공합니다.

struct Animal {
    let species: String
    init?(species: String) {
        if species.isEmpty { return nil }
        self.species = species
    }
}

//通过该可失败构造器来构建一个Animal的对象,并检查其构建过程是否成功
// someCreature 的类型是 Animal? 而不是 Animal
let someCreature = Animal(species: "长颈鹿")

// 打印 "动物初始化为长颈鹿"
if let giraffe = someCreature {
    print("动物初始化为\(giraffe.species)")
}

위 프로그램 실행의 출력 결과는 다음과 같습니다.

动物初始化为长颈鹿

열거형 유형의 실패 가능한 초기화

하나 이상의 매개변수로 실패 가능한 초기화를 구성하여 열거형의 특정 열거형 멤버를 얻을 수 있습니다.

Example

다음 예에서는 TemperationUnit이라는 열거형 유형이 정의됩니다. 여기에는 세 가지 가능한 열거형 멤버(Kelvin, 섭씨 및 화씨)와 문자 값에 해당하는 열거형 멤버를 찾는 데 사용되는 실패 가능한 초기화 프로그램이 포함되어 있습니다.

enum TemperatureUnit {
	// 开尔文,摄氏,华氏
    case Kelvin, Celsius, Fahrenheit
    init?(symbol: Character) {
        switch symbol {
        case "K":
            self = .Kelvin
        case "C":
            self = .Celsius
        case "F":
            self = .Fahrenheit
        default:
            return nil
        }
    }
}


let fahrenheitUnit = TemperatureUnit(symbol: "F")
if fahrenheitUnit != nil {
    print("这是一个已定义的温度单位,所以初始化成功。")
}

let unknownUnit = TemperatureUnit(symbol: "X")
if unknownUnit == nil {
    print("这不是一个已定义的温度单位,所以初始化失败。")
}

위 프로그램 실행의 출력은 다음과 같습니다.

这是一个已定义的温度单位,所以初始化成功。
这不是一个已定义的温度单位,所以初始化失败。

실패할 수 있는 초기화 프로그램 클래스

값 유형(예: 구조 또는 열거형 유형)의 실패 가능한 초기화에는 생성 실패가 발생하는 시기와 위치에 대한 제한이 없습니다.

그러나 클래스의 실패 가능한 초기화 프로그램은 모든 클래스 속성이 초기화된 후와 모든 클래스 간의 생성자 간 프록시 호출이 발생한 후에만 실패 동작을 트리거할 수 있습니다.

Example

다음 예에서는 StudRecord라는 클래스가 정의됩니다. StudName 속성은 상수이므로 StudRecord 클래스가 성공적으로 생성되면 Studname 속성은 nil이 아닌 값을 가져야 합니다.

class StudRecord {
    let studname: String!
    init?(studname: String) {
        self.studname = studname
        if studname.isEmpty { return nil }
    }
}
if let stname = StudRecord(studname: "失败构造器") {
    print("模块为 \(stname.studname)")
}

위 프로그램 실행의 출력 결과는 다음과 같습니다.

模块为 失败构造器

실패할 수 있는 생성자 재정의

다른 생성자와 마찬가지로 기본 클래스의 실패할 수 있는 생성자를 하위 클래스의 실패할 수 있는 생성자로 재정의할 수도 있습니다.

또는 기본 클래스의 실패할 수 있는 초기화를 하위 클래스의 실패할 수 없는 초기화로 재정의할 수도 있습니다.

실패할 수 없는 초기화를 실패할 수 없는 초기화로 재정의할 수 있지만 그 반대는 작동하지 않습니다.

실패할 수 없는 초기화는 결코 실패할 수 있는 초기화에 위임할 수 없습니다.

예제

다음 예는 실패할 수 있는 생성자와 실패할 수 없는 생성자를 설명합니다.

class Planet {
    var name: String
    
    init(name: String) {
        self.name = name
    }
    
    convenience init() {
        self.init(name: "[No Planets]")
    }
}
let plName = Planet(name: "Mercury")
print("行星的名字是: \(plName.name)")

let noplName = Planet()
print("没有这个名字的行星: \(noplName.name)")

class planets: Planet {
    var count: Int
    
    init(name: String, count: Int) {
        self.count = count
        super.init(name: name)
    }
    
    override convenience init(name: String) {
        self.init(name: name, count: 1)
    }
}

위 프로그램 실행의 출력 결과는 다음과 같습니다.

行星的名字是: Mercury
没有这个名字的行星: [No Planets]

실패한 생성자 init!

일반적으로 말하면 init 키워드 정의 뒤에 전달합니다. 물음표(init?)를 추가하여 실패할 수 있는 초기화를 정의할 수도 있지만, init(init!) 뒤에 느낌표를 추가하여 실패할 수 있는 초기화를 정의할 수도 있습니다. 예는 다음과 같습니다.

struct StudRecord {
    let stname: String
    
    init!(stname: String) {
        if stname.isEmpty {return nil }
        self.stname = stname
    }
}

let stmark = StudRecord(stname: "php")
if let name = stmark {
    print("指定了学生名")
}

let blankname = StudRecord(stname: "")
if blankname == nil {
    print("学生名为空")
}

위 프로그램 실행의 출력 결과는 다음과 같습니다.

指定了学生名
学生名为空