Swift 学习笔记 - 03

来源:互联网 发布:mt4交易软件 编辑:程序博客网 时间:2024/05/21 17:58

1. Deinitialization 

1.在对象被销毁之前立即执行,不允许自己手动调用,只适用于Class.

2.一个类最多只有一个deinit方法 ,并且没有圆括号

    • deinit {
    •  // perform the deinitialization
    • }

3.父类的deinitializers会被它的子类们继承,而且父类的deinitializers会在子类的deinitializers实现的最后被调用.即使子类没有提供deinitializers,父类的deinitializers也会被调用.

4.由于Swift会自动帮你管理实例内存,一般情况下用不到deinitializers.但是有一些情景需要用到,比如:打开了一个文件,这时候需要自己手动关闭 释放内存.

2.Automatic Reference Counting (ARC)

1.怎么工作的? 其实就是引用计数

2.强引用循环解决方法:

1.weak references

1.当引用的对象可能nil,使用 weak 修饰,不强引用对象

2.weak修饰的引用必须是变量不能是常量.指示它们的值可以改变.

3.weak修饰的引用最好是optional的

4.当引用的对象的引用计数为0的时候,对象会被释放,然后reference会被置为nil

2.unowned reference

1.当引用对象永远都会有值(非nil)的时候,用unowned修饰,不强引用对象,

2.unowned修饰的引用必须是 non-optional的.

3.当引用的对象的引用计数为0的时候,对象会被释放,但是reference不会被置为nil.当用reference去访问被释放的对象时,会产生运行时错误,所以用unowned reference的时候请一定要保证unowned reference的时候 对象一定不会为nil

3.unowned reference和Implicitly Unwrapped Optional  (!) 一起使用   

当两边一定都有值(非nil),一边使用unowned一边使用

3. Closures的强引用循环解决

1.产生场景: 当闭包作为property被对象保存.但是在闭包的使用过程中,访问了对象属性,比如self. self.someProperty,调用了对象方法,比如self.someMethod().在这些情况下,闭包都会捕捉 self,造成了一个强引用循环.(闭包也是reference type)

注意:在这个产生情景中,如果闭包属性是在声明的时候就保存,闭包的property应该被声明为 lazy,否则无法访问self.由于它是lazy,直到它被真正调用,都不会被初始化,也就意味着在闭包属性初始化的时候,对象其他property一定已经初始化好了,而且self已经存在了.

2.用 capture list (捕捉列表) 解决

lazy var someClosure: (Int, String) -> String = {

            1.                                     [unowned self , weak delegate = self.delegate!] (index: Int, stringToProcess: String) -> String in
          1.                                     // closure body goes here
          2.                             }

可以使用unowned/weak来修饰,用逗号来分割.什么时候用unowned 什么时候用weak?和前面说的一样.

NOTE:Swift要求你在调用实例方法的时候,使用sef.xxxMethod().这样能让你意识到你引用了self.这帮助你意识到可能在闭包中意外地捕获了self.

3.Optional Chaining (这里感觉表达的不是很好,可以去看下官方文档.)

1当调用properties,methods和subscrips的时候,无论properties是否是optional,无论methods和subscrips返回的值是否是optional.Optional Chaining都会返回一个 optional的结果(type一样,只是会被包装成optional).一整个调用链条都会影响.

2.使用方法:用 ? 放在后面.

           class Person {

               var residence: Residence?

            }


           class Residence {

               var numberOfRooms = 1

            }

           let john = Person()


            let roomCount =john.residence?.numberOfRooms (返回的numberOfRooms会是Int?类型,结果:let roomCount nil)

           let roomCount = john.residence!.numberOfRooms(直接报出运行时错误)

Optional Chaining比 一般的 失败的时候更优雅.

3.可以使用Optional Chaining 来调用一个optional value身上的方法来检查这个方法是否调用成功,你可以这么做,即使这个方法并没有任何返回值.  实际上没有返回值的方法返回void,而在Optional Chaining中,返回void? 

           if john.residence?.printNumberOfRooms() !=nil {

                print("It was possible to print the number of rooms.")

            }else {

                print("It was not possible to print the number of rooms.")

            }

同理,设置property的时候, 其实setProperty. 也是可以检查是否设置属性成功

           if (john.residence?.address = someAddress) !=nil {

                print("It was possible to set the address.")

            }else {

                print("It was not possible to set the address.")

            }

4.john.residence?[0].name

5.注意: john.residence?.address?.buildingIdentifier()?.hasPrefix("The") ?在()后面,Optional Chaining链着的是方法的返回值,而不是方法本身.

4.Error Handling  (错误处理)

1.错误类型必须是 value types(errors are represented by values of types),并且必须要遵守ErorrType协议,一般是用枚举比较好

2.方法/函数可以抛出Error,用关键字throws

func canThrowErrors throws -> String{}

3.调用 可能会抛出异常的函数时 在前面必须加 try关键字

4.处理异常: 

do {

try XXXXXX()

XXXXXXXX

defer{

//defer的代码在外面代码块完成后执行

}

}catch XXXXX{

// TODO

}

5.可以用 try! 调用可能会抛出异常的函数,一旦函数抛出异常,直接产生运行时错误.

5.guard

1.guard的格式和if非常的像:

guard var a = inventory[name] else{

//当a为nil时,执行这段代码,可选择抛出异常.

}

guard a>b else{

//当a>b不成立时,执行这段代码,可选择抛出异常.

}

2.含义:守卫      使用guard,表示后面的条件一定为真/一定不为nil.

3.guard后面一定会跟else.当guard后面的条件为true/为nil 那么else里面的语句会被执行

4.guard后面若是一个声明赋值语句.那么声明的变量/常量可以在后面继续使用.相反,if中的只能在if的代码块里面执行.

6.defer

1.defer的代码延迟执行,直到当前所在的代码块结束才执行.

2.defer的代码不能包括break, return等transfer control.

3.在一个代码块中,如果有多个defer,先出现的defer后执行.

7.Type Casting

1.类型检查:用 is 关键字来判断某个对象是不是某个类的实例

2.向下转型: 用as?as! 关键字

1.as? 返回的是一个 optional value. 如果向下转型失败,value为nil

2.as! 返回的是一个 implicitly unwrapped value.如果向下转型失败,直接报运行时错误.

3.如: let movie = item as? Movie;

3.AnyObject : 可以表示 任何类的一个对象,意味着可以指向任何对象

1.为什么会有这东西?  调用Cocoa APIs的时候,经常会得到一个[AnyObject]的数组.这是因为在OC里面数组是没有类型的(存放的全是NSObject).

2.一般取出数组中的元素 然后用as向下转型.

3.当你确定一个数组里面全部都是某个类的对象.那么可以使用一个简单的方式直接把数组向下转型成有类型的数组:

for moviein someObjects as! [Movie] {

//TODO

}

4.Any : 

1.可以表示任何类型的实例 包括基本数据类型,枚举,结构体,函数,闭包等等. var things = [Any]() (things是一个数组)

2.可以用switch来安全地拿出数组中不同类型的元素进行不同的操作:

    •            var things = [Any]() //things是一个数组
    •            things.append(0)
    •            things.append(0.0)
    •            things.append(42)
    •            things.append(3.14159)
    •            things.append("hello")
    •            things.append((3.0,5.0))
    •            things.append(Movie(name: "Ghostbusters", director: "Ivan Reitman"))
    •            things.append({ (name:String) -> Stringin "Hello, \(name)" })
    •            for thing inthings {
    •                switch thing {
    •                case 0 as Int:
    •                    print("zero as an Int")
    •                case 0 as Double:
    •                    print("zero as a Double")
    •                case let someIntas Int:
    •                    print("an integer value of\(someInt)")
    •                case let someDoubleas Double where someDouble > 0:
    •                    print("a positive double value of\(someDouble)")
    •                case is Double:
    •                    print("some other double value that I don't want to print")
    •                case let someStringas String:
    •                    print("a string value of \"\(someString)\"")
    •                case let (x, y)as (Double,Double):
    •                    print("an (x, y) point at\(x),\(y)")
    •                case let movieas Movie:
    •                     print("a movie called '\(movie.name)', dir. \(movie.director)")
    •                case let stringConverteras String ->String:
    •                    print(stringConverter("Michael"))
    •                default:
    •                    print("something else")
    •                 }
    •             }

8. ?? (Nil Coalescing Operator)

形式 :let var c = a ?? b.

1.a必须是optional value

2.b必须和a的type相同

3.当a为nil,返回b.当a不为nil,返回a

4.当a不为nil,直接返回a,b不会执行!

5.这个式子是 let var c = a!=nil ? a : b 的简写! 

用处: 比如当a为nil的时候,可以给c赋值一个默认值b.

9.Nested Types 

Swift 允许你在 structure class enumeration的实现中嵌套structure class enumeration. 你可以嵌套无限层,没有限制

10.Extensions

1.Extensions可以添加新功能到已经存在的class,structure,enumeration,protocal.这能够让你扩展那些你并不能接触到源代码的types.Extensions很像OC中的Category,但并不是Category,因为Extension没有名字

2.定义 :   (后面的协议是可选的)

            extensionSomeType: SomeProtocol,AnotherProtocol {

                // implementation of protocol requirements goes here

            }

3.Extension能做到的:

1.添加computed properties 和 computed type properties (? : type嘛!! 就是 type properties......)

不能添加 stored properties和 property observers

2.定义instance method 和 type method (注意给enumeration和structure添加方法的时候要注意,如果方法中修改了self,或者修改了他们的property,要在方法前添加 mutating 关键字)

3.提供新的构造方法

4.定义下标方法

5.定义和使用新的嵌套类型(nested types)

6.让一个已经存在的type去遵守一个协议

注意:Extension并不能重写那些已经存在的功能,只能新增.

4.如果你给一个type定义了一个extension.那么这个type的实例将会拥有extension所提供的扩展功能.即使这个实例在extension被定义之前已经存在.

5.可以给class新增convenience initializer,但是不能新增designated initializers. designated和deinitializer必须是由源class提供. 

6.如果给value types提供一个新的initializer.并且这个type的每个stored properties都有默认值,type原来没有定义任何initializer,那么在这个新的initializer里面,可以调用type的 default initializer和memberwise initializer

11.Protocols

1.定义 .可以定义 methods,properties等等,并且默认是强制性要求遵守该协议的类型实现所有功能,也可以使用optional来定义可选的功能

2.使用:

1.应用到structure和enumeration 没什么好说的

2.应用到class的时候有点特殊,因为class可能继承自其他类.所以当class有父类的话,父类必须出现在protocol前面,用逗号隔开

3.定义property(或 type property):

1. 需定义 name 和 type 还有这个property是gettable还是gettable且settable.不要求 遵守该协议的类型 定义该property的时候一定是stored还是computed. 同样遵守只能大 不能小的规则(具体你懂的)

2.property必须是var. 并且至少带有一个gettable.

3.定义成type property的时候,必须使用 static 关键字而不是class

4.如: var mustBeSettable: Int{get set }

4.定义method

1.和普通的method定义相同,除了没有{}和方法体.并且形参不能带有default value.   inout形参可以.(提个醒:下标方法中,参数不能有默认值且inout形参也不行)

2.定义成type method的时候,必须使用 static 关键字而不是class

3.若方法中可能要修改了self,或者可能要修改他们的property,要在方法前添加 mutating 关键字.(主要针对value types.当class遵守协议实现方法时,无需在方法前添加mutating)

5.定义initalizer

1.和普通的initalizer定义相同,除了没有{}和方法体

2.可在initializer方法前加required关键字.加了这个关键字后,不但遵守协议的类必须实现这个构造方法,而且它的子类也同样需要实现.(当遵守协议的类是final class,那么它的这个构造方法前面不需加required关键字)

3.可定义 failable initializer .但是遵守协议的子类可以以failable initializer实现 也可以以non-failable initializer实现

定义的non-failable initializer,要求遵守协议的子类必须以non-failableinitializer实现 或者 implicitly unwrapped failable initializeer(init!)实现.

6.protocol可以作为类型在很多地方使用.也可以继承其它协议     (和Java中Interface一样)

7.(Extension相关)可以使用Extension让一个已经存在的type遵守一个新的协议

注意:如果此时,这个已经存在的type原来就已经完全实现了协议里的方法,那么Extension只需声明一下不需在里面写实现任何代码(因为已经实现了)

8.可以限制protocol只可以被class遵守. 只需将class 关键字放在protocol的继承列表中,并且必须是第一个

如:protocolSomeClassOnlyProtocol:class, SomeInheritedProtocol {}

9.Protocol Composition (可以实现多协议.注意作为参数和声明变量时的写法)

           protocol Named {

               var name: String {get }

            }

           protocol Aged {

               var age: Int {get }

            }

           struct Person: Named,Aged {

               var name: String

               var age: Int

            }

           func wishHappyBirthday(celebrator:protocol<Named,Aged>) {

               print("Happy birthday\(celebrator.name) - you're\(celebrator.age)!")

            }

      var person:protocol<Named,Aged> = Person(name: "", age:123);

10. is  as? as! 一样适用于Protocol


11.Optional Protocol Requirements

1.使用关键字optional 并且 protocol 关键字前面必须加 @objc 

           @objc protocol CounterDataSource {

               optional func incrementForCount(count: Int) -> Int

               optional var fixedIncrement: Int { get }

            }

2.@objc指示 这个协议应该暴露给OC代码,更多的描述在 Using Swift with Cocoa and Objective-C

3.有@objc属性的协议的必须是classes或从OC继承而来的类.structure和enumeration不能遵守该协议

4.一个可选的协议功能(属性)可以使用optional chaining来调用(引用).

如: someOptionalMethod?(someArgument)  注意:这里的?是在()前面,如果是在()后面,表示的是方法返回的值是optional的而不是方法本身

12.Protocol Extensions

1.可以对Protocol进行extension,添加新的扩展功能(method/property).这样所有遵守该协议的Type都拥有扩展的功能

如 : extension someProtocol {

func randomBool() -> Bool {

return random() > 0.5

}

    }

2.可以对Protocol进行extension,在扩展中提供协议里面的method或property的默认实现.

一旦遵守协议的type实现了该method/property,将会覆盖默认实现.

注意,虽然提供了默认实现,也不代表这个功能是optional的.因为调用/引用 这个功能的时候不需要使用optional chaining.

3.给Protocol Extensions 添加约束条件.只有满足该条件的type才能获得对Protocol的扩展功能

extension CollectionTypewhere Generator.Element : TextRepresentable {

func.......

}

注意: 一个遵守了该协议的type满足很多 实现了相同功能的constrained extensions.Swift会选择一个最相符的实现.(??????)





























0 0
原创粉丝点击