swift构造过程

来源:互联网 发布:小米手环2怎么样 知乎 编辑:程序博客网 时间:2024/05/22 14:50


/**

1.存储型属性的初始赋值

2.定制化构造过程

3.默认构造器

4.值类型的构造代理

5.类的继承和构造过程

6.通过闭包和函数来设置属性的默认值

OC不同,swift的构造器无需返回值

*/


//存储型属性的初始赋值

/**

为存储型属性设置默认值或者在构造器中为其赋值时,它们的值是被直接设置的,不会触发任何属性观察器

*/

//构造器

struct Fahrenheit {

    var temperature: Double;

    init() {

        temperature = 32.0;

    }

}

var f = Fahrenheit();

print(f.temperature);

f.temperature = 10.0;

print(f.temperature);



//默认属性值

/**

可以在属性声明时设置默认值

如果一个属性总是使用同一个初始值,可以为其设置一个默认值。无论定义默认值还是在构造器中赋值,最终他们实现的效果是一样的,只不过默认值跟属性构造过程结合的更紧密。使用默认值能让你的造成器更简洁清晰,且能通过默认值自动推到出属性的类型,同时,也能充分利用默认构造器,构造器继承等特性

*/

struct Fahrenheit2 {

    var temperature = 24.0;

}

var f2 = Fahrenheit2();

print(f2.temperature);


//定制化构造过程

/**

可以通过输入参数和可选属性类型来定制构造过程,也可以在构造过程中修改常量属性

*/

//构造参数

struct Celsius {

    var temperatureInCelsius: Double = 0.0;

    init(fromFahrenheit fahrenheit: Double) {

        temperatureInCelsius = (fahrenheit - 32.0) / 1.8;

    }

    init(fromKelvin kelvin: Double) {

        temperatureInCelsius = kelvin - 273.15;

    }

}

let boilingPointOfWater = Celsius(fromFahrenheit: 212.0);

print(boilingPointOfWater.temperatureInCelsius);

let freezingPointOfWater = Celsius(fromKelvin: 273.15);

print(freezingPointOfWater.temperatureInCelsius);


//内部和外部参数名

/**

跟函数和方法参数相同,构造参数也存在一个在构造器内部使用的参数名字和一个在调用构造器时使用的外部参数名字

在定义时,没有提供参数的外部名字时,swift会为每个构造器的参数自动生成一个跟内部名字相同的外部名

乳沟不希望提供外部参数名,可以用_来覆盖默认行为

*/

struct Color {

    var red = 0.0, green =0.0, blue = 0.0;

    init(red: Double, green:Double, blue: Double) {

        self.red = red;

        self.green = green;

        self.blue = blue;

    }

}

let magenta = Color(red:1.0, green: 0.0, blue:1.0);


//可选属性类型

/**

如果定制的类型包含一个逻辑上允许取值为空的存储型属性,不管是因为它无法在初始化时赋值,还是因为它可以在之后某个时间点可以赋值为空,都需要定义为可选类型

*/

class SurveyQuestion {

    var text: String;

    var response: String?;

    init(text: String) {

        self.text = text;

    }

    func ask() {

        print(text);

    }

}

let cheeseQuestion = SurveyQuestion(text: "do you like cheese?");

cheeseQuestion.ask();

print(cheeseQuestion.response);

cheeseQuestion.response ="Yes, i do like cheese."

print(cheeseQuestion.response!);


//构造过程中常量属性的修改

/**

只要在构造过程结束前常量的值能确定,可以在构造过程中的任意时间点修改常量属性的值

对某个类实例来说,它的常量属性只能在定义它的类的构造过程中修改,不能在子类中修改

*/

class SurveyQuestion2 {

    let text: String;

    var response: String?;

    init(text: String) {

        self.text = text;

    }

    func ask() {

        print(self.text);

    }

}

let beetsQuestion = SurveyQuestion2(text: "how about beets?")

beetsQuestion.ask();

beetsQuestion.response ="i also like beets.";

print(beetsQuestion.response!);


//默认构造器

class ShoppingListItem {

    var name: String?;

    var quantity = 1;

    var purchased = false;

}

var item = ShoppingListItem();


//结构体的逐一成员构造器

struct Size {

    var width = 0.0, height =0.0;

}

let twoByTwo = Size(width:2.0, height: 2.0);



//值类型的构造器代理

/**

构造器可以通过调用其他构造器来完成实例的部分构造过程。这一过程称为构造器代理,能减少多个构造器间的代码重复

构造器代理的实现规则和形式在值类型和类类型中有所不同。

值类型(结构体和枚举类型)不支持继承,所以构造器代理的过程相对简单,因为它只能代理任务给本身提供的其他构造器,类则不同,它可以继承自其它类,这意味着类有责任保证所有继承的存储型属性在构造时也能正确的初始化

对于值类型,可以使用self.init在自定义的构造器中引用其他的属于相同值类型的构造器,并且只能在构造器内部调用self.init

如果某个值类型定义了一个定制的构造器,将无法访问到默认构造器,可以防止在为值类型定义了一个更复杂的,完成了重要准备构造器之后,别人还是错误使用了那个自动生成的构造器

*/

struct Size2 {

    var width = 0.0, height =0.0;

}

struct Point {

    var x = 0.0, y =0.0;

}

struct Rect {

    var origin = Point();

    var size = Size2();

    init() {};

    init(origin: Point, size:Size2) {

        self.origin = origin;

        self.size = size;

    }

    init(center: Point, size:Size2) {

        let originX = center.x - size.width /2;

        let originY = center.y - size.height /2;

        self.init(origin:Point(x: originX, y: originY), size: size);

    }

    func description() {

        print("origin is\(self.origin.x,self.origin.y), and size is\(self.size.width,self.size.height)");

    }

}

let basicRect = Rect();

basicRect.description();

let originRect = Rect(origin:Point(x: 2.0, y:2.0), size: Size2(width:5.0, height: 5.0));

originRect.description();

let centerRect = Rect(center:Point(x: 4.0, y:4.0), size: Size2(width:3.0, height: 3.0));

centerRect.description();



//类的继承和构造过程

/**

类里面的所有存储型属性,包括所有继承自父类的属性,都必须在构造过程中设置初始值

swift提供了两种类型的类构造器来确保所有类实例中存储属性都能获得初始值,分别是指定构造器和便利构造器

*/

//指定构造器和便利构造器

/**

指定构造器是类中最主要的构造器。一个指定构造器将初始化类中提供的所有属性,并根据父类链往上调用父类的构造器来实现父类的初始化

每一个类都必须拥有至少一个指定构造器,在某些情况下,许多通过继承了父类中的指定构造器而满足了这个条件

便利构造器是累中比较次要的,辅助性的构造器。可以定义便利构造器来调用同一个类中的指定构造器,并为其参数提供默认值。也可以定义便利构造器来创建一个特殊用途或特定输入发实例

在必要的时候为类提供便利构造器,能够节省更多开发时间并让类的构造过程更清晰明了

*/



//构造器链

/**

为了简化指定构造器和便利构造器之间的调用关系,swift采用以下三条规则来限制构造器之间的代理调用

    1.指定构造器必须调用其直接父类的指定构造器

    2.便利构造器必须调用同一类中定义的其它构造器

    3.便利构造器必须最终以调用一个指定构造器结束

即指定构造器必须总是向上代理,便利构造器必须总是横向代理

这些规则不会影响使用时,如何用类去创建实例,任何构造器都可以用来完整创建对应类的实例,这些规则只在实现类的定义时有影响

*/



//指定构造器语法

/**

init(parameters) {

   statements

}

*/

//便利构造器语法

/**

需要在init关键字之前放置convenience关键字

convenience init(parameters) {

   statements

}

*/

class Food {

    var name: String;

    init(name: String) {

    self.name = name;

    }

    convenience init() {

        self.init(name:"[Unnamed]");

    }

}

let name1 = Food();

print(name1.name);

let nameMeat = Food(name:"Bacon");

print(nameMeat.name);


class RecipeIngredient: Food {

    var quantity: Int;

    init(name: String, quantity:Int) {

    self.quantity = quantity;

    super.init(name:name);

    }

    override convenience init(name:String) {

        self.init(name: name, quantity:1);

    }

}

let oneMysteryItem = RecipeIngredient();

print(oneMysteryItem.name,oneMysteryItem.quantity);

let oneBacon = RecipeIngredient(name:"Bacon");

print(oneBacon.name,oneBacon.quantity);

let sixEggs = RecipeIngredient(name:"Eggs", quantity: 6);

print(sixEggs.name,sixEggs.quantity);


class ShoppingListItem2: RecipeIngredient {

    var purchased = false;

    var description: String {

    var output = "\(quantity) *\(name.lowercaseString)";

    output += purchased ? "Y" : "N";

    return output;

    }

}


var breakfastList = [ShoppingListItem2(),ShoppingListItem2(name: "Bacon"), ShoppingListItem2(name: "Eggs", quantity: 6)];

breakfastList[0].name ="orange juice";

breakfastList[0].purchased =true;

for item inbreakfastList {

    print(item.description);

}


//通过闭包和函数来设置属性的默认值

/**

如果某个存储型属性的默认值需要特别的定制或准备,你就可以使用闭包或全局函数来为其属性提供定制的默认值。每当某个属性所属的新类型实例创建时,对应的闭包或函数会被调用,而它们的返回值会当做默认值赋值给这个属性

这种类型的闭包或函数一般创建一个跟属性类型相同的临时变量,然后修改它的值以满足预期的初始状态,最后将这个临时变量的值作为属性的默认值进行返回

class SomeClass {

    let someProperty: SomeType = {

    }

    // 在这个闭包中给 someProperty创建一个默认值 // someValue必须和 SomeType 类型相同 return someValue

    }()

}

注意闭包结尾的大括号后面接了一个小括号,这是用来告诉swift需要立刻执行此闭包,如果忽略这对括号,相当于是将闭包本身作为值赋值给了属性,而不是将闭包的返回值赋值给属性

如果使用闭包来初始化属性的值,请记住在闭包执行时,实例的其它部分都还没有初始化,这意味着你不能够在闭包里访问其它的属性,就算这个属性有默认值也不允许。同样,也不能使用隐式的self属性,或者调用其它的实例方法

*/

struct Checkerboard {

        let boardColors: [Bool] = {

        var temporaryBoard = [Bool]();

        var isBlack = false;

        for i in1...10 {

            for j in 1...10 {

                temporaryBoard.append(isBlack);

                isBlack = !isBlack;

            }

            isBlack = !isBlack;

        }

        return temporaryBoard;

        }();

        

        func squareIsBlackAtRow(row: Int, colum: Int) -> Bool {

                    return boardColors[(row * 10) + colum];

        }

}

let board = Checkerboard();

print(board.squareIsBlackAtRow(0, colum: 1));

print(board.squareIsBlackAtRow(9, colum: 9));

0 0