note for swift 3.0

在此处输入标题

标签(空格分隔): 未分类


1.类和结构体
• swift支持直接设置结构体中的子属性
• 所有结构体都有一个自动生成的成员逐一构造器方法,类没有
• swift中,所有的结构体和枚举类型都是值类型,那么意味着在代码中传递时,都会被复制。和基本类型类似,都是值类型
• 类是引用类型,可以使用恒等运算符 等价于 === 或者不等价于 !== 检测两个常量或者变量是否引用同一个实例。

总结:结构体实例总是通过值传递,类实例总是通过引用传递
按照通用的准则,当符合一条或多条以下条件时,请考虑构建结构体:
• 该数据结构的主要目的是用来封装少量相关简单数据值。
• 有理由预计该数据结构的实例在被赋值或传递时,封装的数据将会被拷贝而不是被引用。 • 该数据结构中储存的值类型属性,也应该被拷贝,而不是被引用。
• 该数据结构不需要去继承另一个既有类型的属性或者行为。

2.字符串、数组、和字典类型的赋值与复制行为:

Swift 中,许多基本类型,诸如 String , Array 和 Dictionary 类型均以结构体的形式实现。这意味着被赋值给 新的常量或变量,或者被传入函数或方法中时,它们的值会被拷贝。
Objective-C 中 NSString , NSArray 和 NSDictionary 类型均以类的形式实现,而并非结构体。它们在被赋值或 者被传入函数或方法时,不会发生值拷贝,而是传递现有实例的引用
以上是对字符串、数组、字典的“拷贝”行为的描述。在你的代码中,拷贝行为看起来似乎总会发生。然而,Sw ift 在幕后只在绝对必要时才执行实际的拷贝。Swift 管理所有的值拷贝以确保性能最优化,所以你没必要去回 避赋值来保证性能最优化

3.属性
如果创建了一个结构体的实例并将其赋值给一个常量,则无法修改该实例的任何属性,即使有属性被声明为变量也不行:这种行为是由于结构体(struct)属于值类型。当值类型的实例被声明为常量的时候,它的所有属性也就成了常 量。

延迟存储属性是指当第一次被调用的时候才会计算其初始值的属性。在属性声明前使用 lazy 来标示一个延迟存 储属性。使用 var 关键字

除存储属性外,类、结构体和枚举可以定义计算属性。计算属性 不直接存储值,而是提供一个 getter 和一个可 选的 setter,来间接获取和设置其他属性或变量的值。必须使用 关键字定义计算属性;只读计算属性的声明可以去掉 关键字和花括号

struct Rect {
    var origin = Point()
    var size = Size()
    var center: Point {
        get {
            let centerX = origin.x + (size.width / 2)
            let centerY = origin.y + (size.height / 2)
            return Point(x: centerX, y: centerY)
        }
        set(newCenter) {
            origin.x = newCenter.x - (size.width / 2)
            origin.y = newCenter.y - (size.height / 2)
        }
} }

可以为除了延迟存储属性之外的其他存储属性添加 属性观察器
• willSet 在新的值被设置之前调用
• didSet 在新的值被设置之后立即调用

  class StepCounter {
     var totalSteps: Int = 0 {
         willSet(newTotalSteps) {
             print("About to set totalSteps to \(newTotalSteps)")
         }
         didSet {
             if totalSteps > oldValue  {
                 print("Added \(totalSteps - oldValue) steps")
             } }
} }

全局的常量或变量都是延迟计算的,跟延迟存储属性 (页 0)相似,不同的地方在于,全局的常量或变量不需要 标记 lazy 修饰符。

类型属性用于定义某个类型所有实例共享的数据,比如所有实例都能用的一个常量(就像 C 语言中的静态常 量),或者所有实例都能访问的一个变量(就像 C 语言中的静态变量)。
使用关键字 static 来定义类型属性

跟实例的存储型属性不同,必须给存储型类型属性指定默认值,因为类型本身没有构造器,也就无法在初始化过 程中使用构造器给类型属性赋值。 存储型类型属性是延迟初始化的,它们只有在第一次被访问的时候才会被初始化。即使它们被多个线程同时访 问,系统也保证只会对其进行一次初始化,并且不需要对其使用 lazy 修饰符。

方法
结构体和枚举能够定义方法是 Swift 与 C/Objective-C 的主要区别之一。在 Objective-C 中,类是唯一能定义 方法的类型

参数名称与实例的某个属性名称相同的时候,参数名 称享有优先权,可以使用 self 属性来区分参数名称和属性 名称

在实例方法中修改值类型:
结构体和枚举是值类型。默认情况下,值类型的属性不能在它的实例方法中被修改,如果你确实需要在某个特定的方法中修改结构体或者枚举的属性,可以定义可变方法: 在方法前加关键字mutating,然后就可以从其方法内部改变它的属性。

注意,不能在结构体类型的常量(a constant of structure type)上调用可变方法,因为其属性不能被改 变,即使属性是变量属性

类方法:在方法的 func 关键字之前加上关键字 static ,来指定类型方法。类还可以用关键字 class 来允许子类重写 父类的方法实现。

下标:下标可以定义在类、结构体和枚举中,是访问集合,列表或序列中元素的快捷方式。定义下标使用 subscript 关键字,多下标参数用逗号分隔

subscript(index: Int) -> Int {
    get {
// 返回一个适当的 Int 类型的值 }
set(newValue) {
// 执行适当的赋值操作
} }
//可以不指定set的参数,会有默认参数:newValue;
如果只提供get 方法,那么可以省去get 关键字
其实下标语法其实是有对应的方法支撑的。和数组的下标用法一样。比常规数组的下标强大,类似重写。数组和字典在swift中已经默认实现了下标语法,所以我们可以直接使用。

继承:
在重写继承来的方法时,需要用 override 声明。该关键字声明保证编译器去检查超类或父类,否则编译会报错,因为方法名重复了。

重写属性: 你可以重写继承来的实例属性或类型属性,提供自己定制的 getter 和 setter,或添加属性观察器使重写的属性,可以观察属性值什么时候发生改变;你可以将一个继承来的只读属性重写为一个读写属性,只需要在重写版本的属性里提供 getter 和 setter 即 可。但是,你不可以将一个继承来的读写属性重写为一个只读属性,如果你在重写属性中提供了 setter,那么你也一定要提供 getter

此外还要注意,你不可以同时提供重写的 setter 和重写的属性观察器。如果你想观察属性值的变化,并且你已 经为那个属性提供了定制的 setter,那么你在 setter 中就可以观察到任何值变化了。

防止重写
你可以通过把方法,属性或下标标记为 来防止它们被重写,只需要在声明关键字前加上final修饰符即 可(例如:final var ,final func,final class func, final subscript )。
你可以通过在关键字 class前添加 final修饰符来将整个类标记为 final 的。这样的类是不可被继承的,试图继承这样的类会导致编译报错

构造过程
存储属性的初始赋值:类和结构体在创建实例时,必须为所有存储型属性设置合适的初始值。存储型属性的值不能处于一个未知的状态。你可以在构造器中为存储型属性赋初值,也可以在定义属性时为其设置默认值;
参数的内部名称和外部名称
构造过程中常量属性的修改。对于类的实例来说,它的常量属性只能在定义它的类的构造过程中修改;不能在子类中修改
结构体的逐一成员构造器:如果结构体没有提供自定义的构造器,它们将自动获得一个逐一成员构造器
假如你希望默认构造器、逐一成员构造器以及你自己的自定义构造器都能用来创建实例,可以将自定义的构造器写到扩展(extension)中,而不是写在值类型的原始定义中。

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

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)// 这里使用的就是构造器代理的方式
} }

类的继承和构造过程

类里面的所有存储型属性——包括所有继承自父类的属性——都必须在构造过程中设置初始值。指定构造器和便利 构造器
每一个类都必须拥有至少一个指定构造器;便利构造器是类中比较次要的、辅助型的构造器:快捷调用某个指定构造器,能够节省更多开发时间并让类的构造过程更清晰明了,便利构造器需要使用:convenience关键字修饰

init(parameters) {
    statements
}

便利构造器:
convenience init(parameters) {
    statements
}

类的构造器代理规则:指定构造器必须总是向上代理;便利构造器必须总是横向代理,便利构造器需要最终调用一个指定构造器。

构造器的继承和重写

  • 跟 Objective-C 中的子类不同,Swift中的子类默认情况下不会继承父类的构造器。Swift 的这种机制可以防止一个父类的简单构造器被一个更精细的子类继承,并被错误地用来创建子类的实例。注意父类的构造器仅会在安全和适当的情况下被继承,你在子类中“重写”一个父类便利构造器时,不需要加override前缀。子类可以在初始化时修改继承来的变量属性,但是不能修改继承来的常量属性

  • 子类在默认情况下不会继承父类的构造器。但是如果满足特定条件,父类构造器是可以被自动继承

  • 规则 1 如果子类没有定义任何指定构造器,它将自动继承所有父类的指定构造器。

  • 规则 2 如果子类提供了所有父类指定构造器的实现——无论是通过规则 1继承过来的,还是提供了自定义实现——它将自动继承所有父类的便利构造器。

可失败构造器
其语法为在 init 关键字后面添加问号( init? )。
你通过 return nil 语句来表明可失败构造器在何种 情况下应该“失败”。

严格来说,构造器都不支持返回值。因为构造器本身的作用,只是为了确保对象能被正确构造。因此你只是用 return nil 表明可失败构造器构造失败,而不要用关键字 return 来表明构造成功。

  • 带原始值的枚举类型会自带一个可失败构造器 init?(rawValue:) ,该可失败构造器有一个名为 rawValue 的参 数,其类型和枚举类型的原始值类型一致,如果该参数的值能够和某个枚举成员的原始值匹配,则该构造器会构 造相应的枚举成员,否则构造失败。
    构造失败的传递,可以横向代理到类型中的其他可失败构造器,类似的子类也可以代理到父类中的可失败构造器;

  • 重写一个可失败构造器:
    如同其它的构造器,你可以在子类中重写父类的可失败构造器。或者你也可以用子类的非可失败构造器重写一个父类的可失败构造器<强制对父类值解包>。这使你可以定义一个不会构造失败的子类,即使父类的构造器允许构造失败,你可以用非可失败构造器重写可失败构造器,但反过来却不行

  • 另外的一种可失败构造的方式是用惊叹号!代替问号?: (init!)
    该可失败构造器将会构建一个对应类型的隐式解 包可选类型的对象;
    你可以在 init? 中代理到 init! ,反之亦然。你也可以用 init? 重写 init! ,反之亦然。你还可以用 init 代理 到 init! ,不过,一旦 init! 构造失败,则会触发一个断言。

必要构造器

  • 在类的构造器前添加 required 修饰符表明所有该类的子类都必须实现该构造器:
class SomeClass {
    required init() {
// 构造器的实现代码
    } 
}

在子类重写父类的 必要构造器 时,必须在子类的构造器前也添加 required 修饰符,表明该构造器要求也应用于继承链后面的子类。在重写父类中必要的指定构造器时不需要添加 override 修饰符:

class SomeSubclass: SomeClass {
     required init() {
// 构造器的实现代码 }
}

如果子类继承的构造器能满足必要构造器的要求,则无须在子类中显式提供必要构造器的实现。《待理解》

你可能感兴趣的:(note for swift 3.0)