Swift 学习笔记 - 02

1.函数可以返回一个函数. 也可以将一个函数以参数的形式传入

2.nil  代表的含义和OC中的nil不太一样了. 

1.在Swift中.nil可以赋值给任何声明为optional的变量,而不仅仅只是对象变量了(未声明为optional的变量不能赋值为nil).

注意.若对象变量不被显示地声明为optional,它也不能设置nil......

2.在OC中nil代表的是一个指向空的指针,而在Swift中nil代表的是缺值. 

3.好处: 和OC一样,方法返回的对象为空,代表着出了问题. 但是在OC中,一旦一些基本数据类型(如int)出了问题,必须要定义一个整形常量来表示.现在在Swift中,nil也可以给基本数据类型赋值代表出了问题了

4.var修饰的变量若是optional. 如果在声明的时候没有赋值,那么默认的值会被设置为nil.

  let修饰的常量若是optional. 如果在声明的时候没有赋值,那么默认什么都不做(在旧版本的Swift中,默认的值也会被设置为nil)

3.排序方法.  return s1>s2 代表s1要出现在s2的前面(排序后的位置). 并且如果是字符串. 字母B比A大

4.closure (闭包)

{

(parameters) -> return type in

    statements

}

1.closure内的参数可以是变参,固参,inout参,但是不能有默认参数.只要给多参命名,多参也是可以的(多参必须放在参数列表的最后).

2.closure可捕捉那些定义在闭包外的变量(常量).

1.若捕捉的值在闭包中用到时会被修改,那么闭包会引用那个值( captures a reference to the variable),使得即使定义值的函数调用结束了,闭包也能够继续使用.

2.若捕捉的值在闭包中用到时不会被修改,那么闭包会拷贝那个值.

3.其实不用在意闭包是去拷贝还是去引用,因为这些工作都由Swift帮你完成了,而且内存的管理也完全交给Swift去实现,不用担心.

4.如果把一个闭包赋值给一个对象的property,并且闭包引用了对象或者对象的members,那么会产生一个强引用循环.Swift uses capture lists to break these strong reference cycles,For more information, see Strong Reference Cycles for Closures  (在学习笔记中 Swift-03 中有写)

5.Enumeration

1.Swift中,枚举的成员不会被赋予一个默认的Integer.

2.Associated Values

1.定义

enum Barcode {

    case UPCA(Int, Int, Int, Int)

    case QRCode(String)

}

2.在赋值的时候给值

var productBarcode = Barcode.UPCA(8, 85909, 51226, 3)

productBarcode = .QRCode("ABCDEFGHIJKLMNOP")

3.什么时候用

switch productBarcode {

case .UPCA(let numberSystem, let manufacturer, let product, let check):

    println("UPC-A: \(numberSystem), \(manufacturer), \(product), \(check).")

case .QRCode(let productCode):

    println("QR code: \(productCode).")

}

注意如果Associated Values的值全部都是let/全部都是var. 在前面写let/var就可以了

如: case let .UPCA(numberSystem, manufacturer, product, check):

4.注意一个已经被赋值枚举的变量同一时间只能持有一个Associated Values.

3.Raw Values

1.不能和Associated Values一起使用

2.定义enum Planet: Int {

    case Mercury = 1, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune

}

注意 Raw values can be strings, characters, or any of the integer or floating-point number types

每一个Raw values在枚举的声明中是一个唯一的值.

当Integer被用于Raw values,可以自动加,如同上面程序中写的

3.可以通过let earthsOrder = Planet.Earth.rawValue 的 rawValue属性来访问.

4.创建枚举变量的时候.可以通过rawValue来创建

如:let possiblePlanet = Planet(rawValue: 7) 注意:possiblePlanet是 Planet? 因为不一定能够通过rawValue一定能找到Planet

5.可以在枚举声明中声明方法.

6.Class和structures

1.共同特点:

1.可定义属性来储存values

2.可定义方法

3.可用下标(下标语法)访问成员属性

4.可用构造器来设置初始状态

5.通过在一个默认的实现上拓展来扩展他们的功能(使用extension)

6.都可以遵守协议protocols

2.Class有但是structures没有的特性

1.继承

2.在运行时可以通过类型转换(type casting)可以检查和解释一个类的实例

3.析构器Deinitializers可以释放一个类的实例的任何资源.

4.引用计数使得可以有多个引用指向同一个类的实例

注意:结构体在传输时是被拷贝的 而不是像类的实例对象一样通过引用计数

3.什么时候用结构体?

1.结构体的最初目的是包含一些相近的简单的data values

2.当传递的时候 希望是被拷贝 而不是 被引用

3.当设计 形状(比如有width height等) 范围(比如有start length等) 3D坐标系(比如 x,y,z等) 可以使用结构体

官方推荐除此以外都应该使用Class

7.Class

1.Swift不会给类自动生成memberwise initializer.

2.Structures and Enumerations Are Value Types.

reference types are not copied when they are assigned to a variable or constant, or when they are passed to a function. Rather than a copy, a reference to the same existing instance is used instead.

3.可用 ===/!=== 来判断两个对象是否是同一个对象. (对于结构体和枚举行不通,因为它们传递的时候一定是拷贝)

注意 === 不同于 == .   ===仅仅是判断2个对象(指针)是否引用同一个对象.

8.Structure

1.当设置一个对象的结构体的一个属性时,现在可以直接设置了(再也不用像在OC里面那样 需要设置整个结构体)

2.Swift会给结构体自动生成memberwise initializer.

如: let vga = Resolution(width: 640, height: 480)

3.Structures and Enumerations Are Value Types.

Value Types 是指这个类型的值当它被赋值给一个变量/常量,或者通过函数/方法传递的时候 是被拷贝

integers, floating-point numbers, Booleans, strings, arrays and dictionaries—are value types

4.在Swift中,String,Array,Dictionary都是通过结构体实现的.因此它们赋值或者被函数/方法传递时,都是拷贝

当然, Foundation的 NSString, NSArray, and NSDictionary还是以classes实现的.所以传递的还是引用.

5.如果结构体被赋值给了一个constant value.那么不能修改结构体的属性值.即使这个结构体定义的属性是变量.

9.Property

1.Lazy Stored Properties:

1.被设置为lazy的属性直到被用到时才会真正初始化

2.变量最好都用 lazy. 常量不能使用lazy

2.Computed Properties

1.classes, structures, and enumerations都可以定义Computed Properties

2.并不存储值,相反,它提供一个getter来间接地获取其他properties和values,还可以选择性地提供一个setter来间接地设置properties和values

3.只能是变量,不能是常量

3.Property Observers

1.每当属性的值被修改,即使新值和旧值相同,Property observers都会被调用

2.观察者可以设置给 stored property,lazy stored property. computed property不可以,但是可以设置给继承下来的property(无论是stored还是computed)

3.willSet 

1.当值被设置之前调用

2.可以给新值起一个名字 也可以不起 ,不起的话 默认新值是 newValue

如 willSet(abc){    }     abc就是新值的名字

4.didSet 

1.当值被设置之后调用

2.可以给旧值起一个名字 也可以不起 ,不起的话 默认旧值是 oldValue

3.如果在didSet中再设置一个值给property.这个值将会代替之前刚刚设置的值.

注意:willSet and didSet observers are not called when a property is set in an initializer before delegation takes place.For more information about initializer delegation, see Initializer Delegation for Value Types and Initializer Delegation for Class Types.

4.type properties : 

1.一般的properties,每个实例都有一份,但是有一种properties是属于类/结构体的,所有实例共享一份,这种properties叫做 type properties

2.对于value types(也就是枚举和结构体) 可以定义stored and computed type properties.但是对于classes,只能定义computed type properties (在新版本中,classes也可以定义 stored property了 不过需要使用static关键字,在classes里面 static 代表着 class final )

3.对于结构体和枚举 定义type property的关键字是 static.

  对于类 定义type property的关键字是class (新版本中,static也可以在类中使用了 相当于 class final.)

10.全局变量和局部变量

1.定义在方法,函数,闭包, type context以外的是全局变量,以内的是局部变量

2.无论是全局还是局部变量,都可以给定义为 computed ,都可以设置观察者

3.全局变量/常量一定是设置为lazy的. 局部变量/常量 一定不是lazy

11.Method

1.对于value types(枚举和结构体) 默认情况下,内部的方法是不能修改property的值的.要想修改 必须在 func 前面加上mutating关键字.  

如果结构体实例是constant.它不能够调用mutating method

mutating func 可以赋值self.

2.Type Method

1.对于value types,关键字是 static 对于classes 关键字是class (新版本中 classes也可以用static,但是static的含义变了,变成 class final)

2.在Type Method内部, self 指向的是 type.(这和OC是一样的.)

12. Subscripts

1.classes,structures, and enumerations都可以定义下标

2.定义

subscript(index: Int) -> Int {

  •     get {
  •         // return an appropriate subscript value here
  •     }
  •     set(newValue) {
  •         // perform a suitable setting action here
  •     }
  • }

可以和computed property一样简写 read-only的下标:

  1. subscript(index: Int) -> Int{
  2.     // return an appropriate subscript value here
  3. }

3.下标的参数可以是多个 而且可以是任意类型 也可以返回任何类型.下标的参数可以是变量(var) 也可以是多参(variadic),但是不能是 in-out参数 和 提供default value的参数

4.Swift的dictionary就是用的Subscripts

13. Inheritance(继承)

1.Swift的classes并没有继承一个共有的类(不像OC一样所有类继承自NSObject Java中所有类继承自Object)

2.override property

1.不管父类的property是stored还是computed的,都可以提供一个自定义的getter(和setter,如果需要的话)来重写.只要名称和类型相同就行.

1.stored ->computed 可以

stored property 必须是var 因为重写后的computed的property不能用let来修饰.

重写的computed property必须提供getter和setter.因为原本的property是可修改的(read-write)

2.stored - > stored   不可以

3.computed -> stored 不可以

4.computed -> computed 可以

read-only property -> read-write property  可以

read-write property -> read-only property 不可以

总结:只能多 不能少

注意:不能仅仅提供setter.如果不想修改父类的getter的方法,只需简单地重写getter方法 在里面返回 super.XXX 就行了.

2.Override Property Observers 

1.不能在constant stored properties或者read-only computed properties上override添加Observers .因为他们都是不可修改的,监听修改并没有什么意义

2.不能同时添加setter和observers.如果实在是想监听,直接在setter的方法里面写就可以了(设置前,设置后)

3.可用final 阻止继承/重写

14. Initialization

1.初始化properties的时候,不会调用observers的方法

2.默认情况下 调用构造方法的时候.必须使用外部参数名(external parameter name).

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

let veryGreen = Color(0.0, 1.0, 0.0)

  要想不使用外部参数名,必须在构造方法的参数前面加 _ 

3. Constant Property 可以在initialization完成之前随便修改!(新版本不是这样了!let 修饰的属性只能被初始化一次! let修饰的常量不需要立即赋值,只要求在使用前赋过值)

(新版本中,下面这句话已经没有意义)注意:对于Class来说.子类初始化的时候 无权修改父类的常量属性.(为什么说对于Class来说呢?因为其它的type根本没有继承关系!)

4.默认构造方法

1.对Class来说 只要没有提供自定义的构造方法,系统会为你自动生成一个默认的构造方法.

2.对Structure来说, 只要没有提供自定义的构造方法,系统会生成一个memberwise initializer 和 什么都不做的 initializer

3.若想要自定义的构造方法,又想要系统提供的默认构造方法.官方推荐 最好将自定义的构造方法放在 extension中而不是直接放在原实现中.

5.Initializer Delegation : 一个构造方法可以调用其它构造方法来帮助它完成初始化,这样能防止产生重复代码.

1.对value types来说,由于没有继承,所以只需要调用self.init来调用其它构造方法即可

2.对classes来说,由于继承,有更多的职责去完成那些继承而来的属性的初始化(这些职责在下面描述)

15.Class Initializer

0.Designated initializers must always delegate up.

  Convenience initializers must always delegate across.

1.Designated initializers 

1.是一个class主要的构造方法.一个class至少要有一个Designated initializer.

2.定义

    • init(parameters) {
    •     statements
    • }

3.必须调用 直接父类的designated initializer

2.Convenience initializers 

1.是class次要的构造方法,Convenience initializer不是一定要提供的.

2.Convenience initializer可以调用Designated initializer.

3.定义

    • convenience init(parameters) {
    •     statements
    • }

4.必须调用另外一个来自本class的initializer

5.必须最终调用一个designated initializer (可以不直接调用,但是一定最后要调用到)

6.不能调用父类的Convenience initializer

3.初始化分2个阶段

1.第一阶段:每个stored property被声明它的类分配初始值.一旦每个stored property都被初始化完毕,第二阶段开始了

1.一个designated 或 convenience initializer 被调用

2.分配内存给新实例,但是这些内存并没有被初始化

3.designated initializer必须确保这个类声明的属性全部都有值,这个部分的内存现在被初始化了.

4.designated initializer委托给它的父类的designated initializer去完成相同的初始化任务

5.重复3,4步骤,直到到达这条继承链的顶部

6.一旦到达这条继承链的顶部,最后的类也确保了它声明的属性被初始化了,这个时候整个实例的内存被完全初始化了,第一阶段完成.

2.第二阶段:在新实例被使用前,每一个类都有机会修改它的stored properties

1.从继承链的顶部的类开始,每一个类的designated initializer都能自定义它的实例(比如修改propert ,调用 实例方法,访问self等等)

2.所有的在这条链上的convenience initializers都得到机会自定义它的实例.

总结: 第一阶段 从下到上初始化

第二阶段 从上到下自定义(初始化)

3.好处: 

1.能阻止属性的值被初始化之前访问

2.能阻止属性的值意外地被另外一个构造方法修改.(为什么能阻止? 想象一下一个情节:如果不是严格的分成这2个阶段.子类在初始化的时候 修改了继承而来的某个属性,但是之后由于父类的初始化 导致之前修改的属性的值被覆盖了! 所以说这个阶段的顺序非常的重要!!)

4.Swift的编译器通过4步安全检查来确保2个阶段的初始化顺利完成没有差错.(这些是程序员需要实现(保证)的)

1.在 delegates up to a superclass initializer之前designated initializer必须确保所以本类声明的property被初始化了 

2.designated initializer 在自己赋值给继承的property之前,必须先delegate up to a superclass initializer.防止子类中的赋值被父类的初始化覆盖.

3.convenience initializer在自己赋值之前 必须delegate to(委托给)另外一个initializer.理由同样如上,可能会被覆盖

4.在第一阶段结束之前, initializer方法不能访问任何 方法,属性和self.

16.Class Initializer Inheritance and Overriding

1.不同于OC,Swift的子类默认不会继承父类的构造方法,但是在一些情况下,子类会继承父类的构造方法

情况一:子类没有定义任何designated initializer,那么子类会继承父类全部的的designated initializers

情况二:如果子类提供了父类的designated initializer的实现:继承他们(通过情况一)或自己重写父类的某个designated initializer的实现  那么子类会自动继承所有它父类的 convenience initializers.

补充情况二: 注意:自己重写后的intializer可以是designated initializer 也可以是convenience initializer,也就是说如果子类中有一个convenience initializer并且override了父类的designated initializer,那么满足情况二,该子类会继承父类所有的 convenience initializers.

2.若要override父类的designated initializer.必须加override关键字.  即使是父类的默认构造方法

3.当提供一个和父类 convenience initializer匹配(相同)的convenience initializer的时候,不需要写override,因为它无法调用父类的convenience initializer.但是如果与父类的designated initializer同名时,还是要加override

17.可能失败的构造方法(Failable Initializers)

1.定义 (关键是问号和返回nil)

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

2.严格地说,构造方法并不返回一个实例,它们的职责是确保实例完全初始化. return nil表示的是初始化失败.当初始化成功时,不需return

3.对于value types来说.触发一个初始化错误(返回nil)可以发生在构造方法的任何地方.

  但是对于classes来说.只能在所有本类中声明的stored properties被初始化后 而且其他initializer delegation也发生后,才能触发初始化错误. 

4.failable initializer可调用本类的其他initializer.也可以调用父类的initializer.无论是failable还是nonfailable.当failable initializer调用其他failable initializer,并且引起初始化失败,初始化过程立刻停止.

5.failable initializer可以override.子类的nonfailable initializer可以override父类的failable initializer.也就是说 子类重写后子类可以产生不会出错的构造方法.

6.nonfailable initializer不能delegate to failable initializer

18.可以用Closure or Function给stored property设置默认值

1.使用方法: 

    •     let someProperty: SomeType {
    •         // create a default value for someProperty inside this closure
    •         // someValue must be of the same type as SomeType
    •         return someValue
    •         }()

注意到大括号后面的()非常的关键.它告诉Swift立刻执行这个闭包.如果删除这个(),意味着将这个闭包赋值给这个属性,而不是闭包执行的返回值

2.当用闭包去初始化property的时候,一定要记住在这个闭包执行的过程中其它部分(属性,方法,self)都没有被初始化.这意味着,在闭包的执行过程中,在闭包里面不能访问property,即使这些property已经有默认值了,也不能使用self也不能调用任何实例方法.

3.可以利用这个实现懒加载. 必须使用关键字 lazy 它使得闭包在执行的过程中可以访问属性,方法,self(不知道为什么的话去看swift-03) .而且请注意若在里面访问了属性,方法,self.请记得使用 capture list .






























  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值