swift 學(xué)習(xí)筆記

Swift2.0

1.defer譯為延緩铁蹈、推遲之意類似棧

注意作用域,其次是調(diào)用順序——即一個(gè)作用域結(jié)束(注意)十绑,該作用域中的defer語(yǔ)句自下而上調(diào)用(相同作用域下后入先執(zhí)行)漱挎。

不是函數(shù)結(jié)束時(shí)開(kāi)始執(zhí)行defer棧推出操作廉涕,而是每當(dāng)一個(gè)作用域結(jié)束就進(jìn)行該作用域defer執(zhí)行

2.guard有控制典蝌、警戒之意切記else中一定需要有返回的語(yǔ)句曙砂,比如return、continue骏掀、break鸠澈、throw這種提早退出的關(guān)鍵字!截驮!

guard age >= 13 else{

return

}

if age >= 13 else{

return

}

*/

//MARK:/******************************讀王巍*******************************/

/*

1.柯里化Swift里可以將方法進(jìn)行柯里化(Currying)14,也就是把接受多個(gè)參數(shù)的方法變換成接受第一個(gè)參數(shù)的方法,返回接受余下的參數(shù)并且返回結(jié)果的新方法笑陈。舉個(gè)例子,Swift中我們可以這樣寫出多個(gè)括號(hào)的方法

func addTwoNumbers(a: Int)(num: Int) -> Int {

return a + num

}

let addToFour = addTwoNumbers(4) // addToFour是一個(gè)Int -> Int方法

let result = addToFour(num: 6) // result = 10

2.Sequence(序列化)

Swift的for...in可以用在所有實(shí)現(xiàn)了SequenceType的類型上,而為了實(shí)現(xiàn)SequenceType你首先需要實(shí)現(xiàn)一個(gè)GeneratorType(發(fā)動(dòng)機(jī)類型)

class ReverseGenerator: GeneratorType {

typealias Element = Int

var counter: Element

init(array: [T]) {

self.counter = array.count - 1

}

init(start: Int) {

self.counter = start

}

func next() -> Element? {

return self.counter < 0 ? nil : counter--

}

}

struct ReverseSequence: SequenceType {

var array: [T]

init (array: [T]) {

self.array = array

}

typealias Generator = ReverseGenerator

func generate() -> Generator {

return ReverseGenerator(array: array)

}

}

Sequence

let arr = [0,1,2,3,4]

//對(duì)SequenceType可以使用for...in來(lái)循環(huán)訪問(wèn)

for i in ReverseSequence(array: arr) {

print("Index \(i) is \(arr[i])")

}

3.@autoclosure:把一句表達(dá)式自動(dòng)地封裝成一個(gè)閉包(closure)作用是使其清晰

注意:@autoclosure并不支持帶有輸入?yún)?shù)的寫法,也就是說(shuō)只有形如() -> T的參數(shù)才能使用這個(gè)特性進(jìn)行簡(jiǎn)化

func logIfTrue(predicate: () -> Bool) {}

func logIfTrue(@autoclosure predicate: () -> Bool) {}

??:var currentLevel = level ?? startLevel level是否為nil是取右邊否則取左邊

4.字面量轉(zhuǎn)換(通過(guò)結(jié)構(gòu)體基本數(shù)據(jù)類型生成對(duì)象)

所謂字面量,就是指像特定的數(shù)字,字符串或者是布爾值這樣,能夠直接了當(dāng)?shù)刂赋鲎约旱念愋筒樽兞窟M(jìn)行賦值的值

例如Person類String賦值來(lái)生成Person對(duì)象的話

Person類實(shí)現(xiàn)StringLiteralConvertible協(xié)議后可以直接初始化對(duì)象

let p: Person = "xiaoMing"

一.需要實(shí)現(xiàn)以下協(xié)議

? ArrayLiteralConvertible

? BooleanLiteralConvertible

? DictionaryLiteralConvertible

? FloatLiteralConvertible

? NilLiteralConvertible

? IntegerLiteralConvertible

? StringLiteralConvertible

class Person: StringLiteralConvertible {

//typealias StringLiteralType

typealias StringLiteralType = String

let name: StringLiteralType

init(name value: String) {

self.name = value

}

required convenience init(stringLiteral value: String) {

self.init(name:value)

}

required convenience init(extendedGraphemeClusterLiteral value: String) {

self.init(name:value)

}

required convenience init(unicodeScalarLiteral value: String) {

self.init(name:value)

}

}

func testPerson(){

let p : Person = Person(stringLiteral: "zzq")

print(p.name)

//直接通過(guò)string可以初始化對(duì)象

let p2 :Person = "ccc"

print(p2.name)

}

//在Swift中自定義下標(biāo)(subscript)可以給類結(jié)構(gòu)體(基本數(shù)據(jù)是結(jié)構(gòu)體)定義下標(biāo)[]

extension Int {

//定義下標(biāo)是Int類型

subscript(digitIndex: Int) -> Int {

var decimalBase = 1

for _ in 1...digitIndex {

decimalBase *= 10

}

return self * decimalBase * 2

}

}

class DailyMeal{

enum MealTime{

case Breakfast

case Lunch

case Dinner

}

var meals: [MealTime : String] = [:]

//定義下標(biāo)是MealTime類型

subscript(requestedMeal : MealTime) -> String{

get{

if let thisMeal = meals[requestedMeal]{

return thisMeal

}else{

return "Ramen"

}

}

//只讀下標(biāo)下面則省略神州省略get

set(newMealName){

meals[requestedMeal] = newMealName

}

}

}

func testSubscript(){

let a:Int = 123

print("i love \(a),\(a[5])")

var monday = DailyMeal()

monday[.Lunch] = "Pizza"

print(monday[.Lunch])//Output:"Pizza"

print(monday[.Dinner])//Output:"Ramen"

}

5.實(shí)例方法的動(dòng)態(tài)調(diào)用

class MyClass {

func method(number: Int) -> Int {

return number + 1

}

class func come(){

print("class fun")

}

//注意!當(dāng)存在和實(shí)例方法相同名的方法時(shí)候默認(rèn)通過(guò)類名點(diǎn)方法生成的是類方法的柯里化方法所以此時(shí)加類型參數(shù)區(qū)分

class func method(number: Int) -> Int {

return number

}

//區(qū)分如下:

/*這種方式不僅在這里有效,在其他大多數(shù)名字有歧義的情況下,都能很好地解決問(wèn)題

let f1 = MyClass.method // class func method的版本(由于實(shí)例和類方法相同名所以默認(rèn)是類方法)

let f2: Int -> Int = MyClass.method //和f1相同(所以定義Int->Int是默認(rèn)類方法)

let f3: MyClass -> Int -> Int = MyClass.method // func method的柯里化版本實(shí)例方法

*/

}

func testMyClass(){

//f:MyClass -> (Int) -> Int通過(guò)類名點(diǎn)方法生成一個(gè)可以"柯里化"的方法

let f = MyClass.method// MyClass.come()注意和類方法調(diào)用是不同的勿混淆

//實(shí)例化對(duì)象

let object = MyClass()

//調(diào)用方法

let result:Int = f(object)(1)

print(result)

}

6.命名空間

通過(guò)框架framework.類名調(diào)用不同的類以區(qū)分相同命名的類

通過(guò)結(jié)構(gòu)體名.類名或者類名.類名區(qū)分相同命名的類

7.Any和AnyObject

AnyObject(是個(gè)協(xié)議protocol)可以代表任何class類型的實(shí)例

Any(protocol<>)可以表示任意類型,甚至包括方法(func)類型

對(duì)于OC返回id類型擇對(duì)于swift返回->AnyObject?

所有的class都隱式地實(shí)現(xiàn)了這個(gè)接口AnyObject接口

protocol<>:需要實(shí)現(xiàn)空接口的接口”,其實(shí)就是任意類型的意思了葵袭。

8.typedef(OC)和typealias(swift)

有點(diǎn)特殊在swift中typealias對(duì)接口定義一個(gè)必須實(shí)現(xiàn)的別名涵妥。比如在GeneratorType和SequenceType這兩個(gè)接口中,Swift都用到了這個(gè)技巧

protocol GeneratorType {

typealias Element

mutating func next() -> Element?

}

9.@UIApplicationMain

swift不象Objective-C時(shí)那樣的main文件,也不存在main函數(shù)AppDelegate類的聲明上方有一個(gè)@UIApplicationMain的標(biāo)簽

10.初始化方法順序

與Objective-C不同,Swift的初始化方法需要保證類型的所有屬性都被初始化。所以初始化方法的調(diào)用順序就很有講究眶熬。在某個(gè)類的子類中,初始化方法里語(yǔ)句的順序并不是隨意的,我們需要保證在當(dāng)前子類實(shí)例的成員初始化完成后才能調(diào)用父類的初始化方法

class Cat {

var name: String

init() {

name = "cat"

}

}

class Tiger: Cat {

let power: Int

override init() {

power = 10

super.init()

name = "tiger"

}

}

一般來(lái)說(shuō),子類的初始化順序是:

1.設(shè)置子類自己需要初始化的參數(shù),power = 10

2.調(diào)用父類的相應(yīng)的初始化方法,super.init()

3.對(duì)父類中的需要改變的成員進(jìn)行設(shè)定,name = "tiger"

其中第三步是根據(jù)具體情況決定的,如果我們?cè)谧宇愔胁恍枰獙?duì)父類的成員做出改變的話,就不存在第3步妹笆。而在這種情況下,Swift會(huì)自動(dòng)地對(duì)父類的對(duì)應(yīng)init方法進(jìn)行調(diào)用,也就是說(shuō),第2步的super.init()也是可以不用寫的(但是實(shí)際上還是調(diào)用的,只不過(guò)是為了簡(jiǎn)便Swift幫我們完成了)块请。這種情況下的初始化方法看起來(lái)就很簡(jiǎn)單:

初始化方法順序

class Cat {

var name: String

init() {

name = "cat"

}

}

class Tiger: Cat {

let power: Int

override init() {

power = 10

}

//雖然我們沒(méi)有顯式地對(duì)super.init()進(jìn)行調(diào)用

//不過(guò)由于這是初始化的最后了,Swift替我們完成了

}

11. as?娜氏,as!,as墩新,is四者用法

as?:返回一個(gè)可選值贸弥,當(dāng)實(shí)例遵循協(xié)議時(shí),返回該協(xié)議類型海渊;否則返回nil

as!:用以強(qiáng)制向下轉(zhuǎn)換型绵疲,如子類實(shí)例父類引用時(shí)候該實(shí)例的向下轉(zhuǎn)型哲鸳,當(dāng)轉(zhuǎn)型失敗則報(bào)錯(cuò)異常。

as :將某實(shí)例(實(shí)現(xiàn)該協(xié)議)強(qiáng)轉(zhuǎn)為該協(xié)議調(diào)用協(xié)議的方法以此區(qū)分不同協(xié)議的同名方法

is :判斷某一個(gè)對(duì)象是否是某一個(gè)特定的類(OC isKindOfClass)盔憨。

12.static和class

static一般在struct和enum中使用可以修飾方法(靜態(tài)方法)存儲(chǔ)變量(靜態(tài)變量)和計(jì)算變量

class在class中可以修飾方法(類方法)計(jì)算變量徙菠,注意不能修飾存儲(chǔ)變量

注意:1.如果在類中要使用靜態(tài)變量只能使用static來(lái)修飾存儲(chǔ)變量

2.在class被static修飾的存儲(chǔ)變量,被class修飾計(jì)算變量郁岩,方法子類和父類都是公用的(OC也是如)

3.被class修飾的方法不能被子類重寫但是OC的類方法可以被子類重寫的

如果我們想在protocol里定義一個(gè)類型域上的方法或者計(jì)算屬性的話,應(yīng)該用哪個(gè)關(guān)鍵字呢?答案是使用class進(jìn)行定義

13.@objc和dynamic

在swift中對(duì)于非繼承NSObject類的在OC使用swift會(huì)因?yàn)镺C是運(yùn)行時(shí)機(jī)制{(KVC和動(dòng)態(tài)派發(fā)Dynamic)婿奔,在運(yùn)行時(shí)決定實(shí)際調(diào)用的具體實(shí)現(xiàn)},而找不到所需要的這些運(yùn)行時(shí)信息问慎,所以@objc關(guān)鍵字將類,屬性和方法暴露給OC萍摊。

注意:如果是繼承NSObject ,swift則會(huì)默認(rèn)自動(dòng)為所有的非private的類和成員加上@objc

添加@objc修飾符并不意味著這個(gè)方法或者屬性會(huì)變成動(dòng)態(tài)派發(fā),Swift依然可能會(huì)將其優(yōu)化為靜態(tài)調(diào)用。如果你需要和Objective-C里動(dòng)態(tài)調(diào)用時(shí)相同的運(yùn)行時(shí)特性的話,你需要使用的修飾符是dynamic如叼。一般情況下在做app開(kāi)發(fā)時(shí)應(yīng)該用不上,但是在施展一些像動(dòng)態(tài)替換方法或者運(yùn)行時(shí)再?zèng)Q定實(shí)現(xiàn)這樣的“黑魔法”的時(shí)候,我們就需要用到dynamic修飾符了冰木。

//需加上@objc來(lái)使用optional可選借接口方法實(shí)現(xiàn)否則swift的接口都必須實(shí)現(xiàn)所有的接口方法

@objc protocol OptionalProtocol {

optional func optionalMethod() //可選

func necessaryMethod() //必須optional func anotherOptionalMethod() //可選

}

14.內(nèi)存管理,weak和unowned

weak就是以前的weak,unowned更像以前的unsafe_unretained

class Person {

let name: String

//lazy var printName: ()->() = {

//print("The name is \(self.name)")

//}

//需改成以下[weak self]來(lái)避免閉包的循環(huán)引用

lazy var printName: ()->() = {

[weak self] in

if let strongSelf = self {

println("The name is \(strongSelf.name)")

}

}

init(personName: String) {

name = personName

}

deinit {

print("Person deinit \(self.name)")

}

}

func testFUN(){

let xiaoMing: Person = Person(personName: "XiaoMing")

xiaoMing.printName();

}

printName是self的屬性,會(huì)被self持有,而它本身又在閉包內(nèi)持有self,這導(dǎo)致了xiaoMing的deinit在自身超過(guò)作用域后還是沒(méi)有被調(diào)用,也就是沒(méi)有被釋放。為了解決這種閉包內(nèi)的循環(huán)引用,我們需要在閉包開(kāi)始的時(shí)候添加一個(gè)標(biāo)注,來(lái)表示這個(gè)閉包內(nèi)的某些要素應(yīng)該以何種特定的方式來(lái)使用笼恰。

如果我們可以確定在整個(gè)過(guò)程中self不會(huì)被釋放的話,我們可以將上面的weak改為unowned,這樣就不再需要strongSelf的判斷踊沸。但是如果在過(guò)程中self被釋放了而printName這個(gè)閉包沒(méi)有被釋放的話(比如生成Person后,某個(gè)外部變量持有了printName,隨后這個(gè)Persone對(duì)象被釋放了,但是printName已然存在并可能被調(diào)用),使用unowned將造成崩潰。在這里我們需要根據(jù)實(shí)際的需求來(lái)決定是使用weak還是unowned社证。

lazy懶加載

15.@autoreleasepool

16.值類型和引用類型

Swift中的struct和enum定義的類型是值類型,使用class定義的為引用類型雕沿。很有意思的是,Swift中的所有的內(nèi)建類型都是值類型,不僅包括了傳統(tǒng)意義像Int,Bool這些,甚至連String,Array以及Dictionary都是值類型的

在需要處理大量數(shù)據(jù)并且頻繁操作(增減)其中元素時(shí),選擇NSMutableArray和NSMutableDictionary會(huì)更好,而對(duì)于容器內(nèi)條目小而容器本身數(shù)目多的情況,應(yīng)該使用Swift語(yǔ)言內(nèi)建的Array和Dictionary。

17.Foundation框架

如果我們出于某種原因,確實(shí)需要NSString以及NSArray的話,我們需要顯式的轉(zhuǎn)換:

import Foundation

let string = "/var/controller_driver/secret_photo.png" as NSString

let fileName = components.lastObject as NSString

let fileName = components.lastObject as NSString

Swift的容器類型是可以裝任意其他類型的,包括各種enum和struct,而NSArray和NSDictionary只能放NSObject的子類對(duì)象猴仑。所以在Array和Dictionary中如果裝有非AnyObject或者不能轉(zhuǎn)為AnyObject的內(nèi)容的話,做強(qiáng)制的轉(zhuǎn)換將會(huì)拋出編譯錯(cuò)誤

18 lazy懶加載

//簡(jiǎn)單表達(dá)式

lazy var first = NSArray(objects: "1","2")

//閉包

lazy var name:String = {

return "second"

}()

//不要忘記最后的小括號(hào)审轮,只有加了小括號(hào),閉包才會(huì)在掉用的時(shí)候立刻執(zhí)行辽俗。

19.(指針)UnsafePointer

Swift定義了一套指針的訪問(wèn)和轉(zhuǎn)換方法,那就是UnsafePointer和它的一系列變體疾渣。對(duì)于使用C API時(shí)如果遇到接受內(nèi)存地址作為參數(shù),或者返回是內(nèi)存地址的情況,在Swift里會(huì)將它們轉(zhuǎn)為UnsafePointer的類型

void method(const int *num) { printf("%d",*num);}

其對(duì)應(yīng)的Swift方法應(yīng)該是:

func method(num: UnsafePointer) {

print(num.memory)//memory屬性讀取存儲(chǔ)的內(nèi)容C語(yǔ)言中使用*

}

var a: CInt = 123

method(&a)//取地址都是&

注意對(duì)于C語(yǔ)言的基本數(shù)據(jù)和swift區(qū)別是在前面加CCInt,CBool和CChar

C APIconst Type *Type *

Swift APIUnsafePointerUnsafeMutablePointer//可變指針

說(shuō)明:Swift不可變指針UnsafePointer ;可變指針UnsafeMutablePointer<>;

連續(xù)數(shù)據(jù)指針UnsafeBufferPointer;不透明指針COpaquePointer;方法指針CFunctionPointer

注意開(kāi)辟指針需要自己釋放

var pointer: UnsafeMutablePointer!

pointer = UnsafeMutablePointer.alloc(1)

pointer.initialize(MyClass())

println(pointer.memory.a)

pointer.destroy()

pointer.dealloc(1)

pointer = nil

malloc或者calloc開(kāi)辟的指針需要使用free而不是dealloc

//

func CFArrayGetValueAtIndex(theArray: CFArray!, idx: CFIndex)->UnsafePointer{

}

20 ...和..<

for i in 0...3 { print(i) }

let test = "helLo"

let interval = "a"..."z"

for c in test {

if !interval.contains(String(c)) {

println("\(c)不是小寫字母")

}

}

21.獲取對(duì)象類型

OC:

NSDate *date = [NSDate date]; NSLog(@"%@",NSStringFromClass([date class])); //輸出:__NSDate

[date class]與([NSDate class]區(qū)別輸出:NSDate)

Swift:

let date = NSDate()

let name = NSStringFromClass(date.dynamicType)//結(jié)果__NSDate

//注意與下面區(qū)別

NSStringFromClass(NSDate.self)//結(jié)果NSDate

不能使用NSStringFromClass(NSDate.class)

在OC中使用

NSStringFromClass(NSDate.class) NSStringFromClass(NSDate.self)

注意:對(duì)于String結(jié)構(gòu)體類型的無(wú)法使用上面的方法因?yàn)闆](méi)有實(shí)現(xiàn)AnyObject接口

這里使用_stdlib_getTypeName和_stdlib_getDemangledTypeName?崖飘?

22.AnyClass,元類型和.self

.self :.self可以用在類型后面取得類型本身,也可以用在某個(gè)實(shí)例后面取得這個(gè)實(shí)例本身

.Type :.Type表示的是某個(gè)類型的元類型

class A {

static var name: String = "zzzq"

class func testMethod(){

print("hello")

}

}

let typeA: A.Type = A.self//獲得是該元類只能調(diào)用類方法或者靜態(tài)屬性

typeA.testMethod()

print(typeA.name)

.Type表示的是某個(gè)類型的元類型,而在Swift中,除了class,struct和enum這三個(gè)類型外,我們還可以定義protocol榴捡。對(duì)于protocol來(lái)說(shuō),有時(shí)候我們也會(huì)想取得接口的元類型。這時(shí)我們可以在某個(gè)protocol的名字后面使用.Protocol來(lái)獲取,使用的方法和.Type是類似的

元類(metaclass):就是類對(duì)象不是實(shí)例對(duì)象

OC中:isa,實(shí)例對(duì)象的isa指向該類(存儲(chǔ)實(shí)例方法和實(shí)例變量)該類的isa指向元類(存儲(chǔ)類方法和靜態(tài)變量)

23.接口和類方法中的Self L

//定義接口返回接口的定義時(shí)

在OC中接口寫返回是instancetype類型來(lái)返回自己在swift中使用Self

protocol Copyable {

//應(yīng)該做的是創(chuàng)建一個(gè)和接受這個(gè)方法的對(duì)象同樣的東西,然后將其返回,返回的類型不應(yīng)該發(fā)生改變,所以寫為Self朱浴。然后開(kāi)始嘗試實(shí)現(xiàn)一個(gè)MyClass來(lái)滿足這個(gè)接口:

func copy() -> Self

}

class CopyClass: Copyable {

var num = 1

func copy()-> Self{

/*錯(cuò)誤代碼=> let result = MyClass() result.num = num return result*/

//正確如下

let result = self.dynamicType.init()

return result

}

/* required關(guān)鍵字修飾的初始化方法

這是因?yàn)镾wift必須保證當(dāng)前類和其子類都能響應(yīng)這個(gè)init方法*/

required init() {

}

}

24.自省

OC :

[obj1 isKindOfClass:[ClassA class]];

[obj2 isMemberOfClass:[ClassB class]];

swift :前提是NSObject子類

obj1.isKindOfClass(ClassA.self)

obj2.isMemberOfClass(ClassA.self)

使用is在功能上相當(dāng)于原來(lái)的isKindOfClass

class,struct或enum類型都可以使用is判斷

注意:編譯器將對(duì)這種檢查進(jìn)行必要性的判斷:如果編譯器能夠唯一確定類型,那么is的判斷就沒(méi)有必要,編譯器將會(huì)拋出一個(gè)錯(cuò)誤

25.動(dòng)態(tài)類型和多方法

Swift中我們雖然可以通過(guò)dynamicType來(lái)獲取一個(gè)對(duì)象的動(dòng)態(tài)類型(也就是運(yùn)行時(shí)的實(shí)際類型,而非代碼指定或編譯器看到的類型)但是在使用中,Swift現(xiàn)在卻是不支持多方法的,也就是說(shuō),不能根據(jù)對(duì)象在動(dòng)態(tài)時(shí)的類型進(jìn)行合適的重載方法調(diào)用吊圾。

OC在同類中是不支持同名不同參數(shù)的重載但是在swift中是支持

26.局部

在OC中使用{}將代碼局部區(qū)分局部有限

self.titleLabel = ({

UILabel *label = [[UILabel alloc]initWithFrame:CGRectMake(150, 30, 20, 40)];

label.textColor = [UIColor redColor];

label.text = @"Title";

[view addSubview:label];

label;

});

swift中使用()

let titleLabel:UILabel = {

let label = UILabel(frame: CGRectMake(150, 30, 20, 40))

label.textColor = UIColor.redColor()

label.text = "Title"

self.view.addSubview(label)

return label

}()

對(duì)于OC使用{}局部區(qū)分swift自定義local方法

func local(closure: ()->()) {

closure()

}

local {

let titleLabel = UILabel(frame: CGRectMake(150, 30, 20, 40))

titleLabel.textColor = UIColor.redColor()

titleLabel.text = "Title"

}

27.Printable (2.0被CustomStringConvertible取代)和DebugPrintable (2.0被CustomDebugStringConvertible)

Swift中,大多數(shù)基礎(chǔ)對(duì)象都遵循了CustomStringConvertible協(xié)議翰蠢,比如Array项乒、Dictionary(Swift 1.0中的Printable協(xié)議),該協(xié)議定義了description方法梁沧,用于print方法打印對(duì)象

通過(guò)extension擴(kuò)展CustomStringConvertible實(shí)現(xiàn)description

28.訪問(wèn)級(jí)別

1.public:可以訪問(wèn)自己模塊或應(yīng)用中源文件里的任何實(shí)體檀何,別人也可以訪問(wèn)引入該模塊中源文件里的所有實(shí)體。通常情況下,某個(gè)接口或Framework是可以被任何人使用時(shí)频鉴,你可以將其設(shè)置為public級(jí)別栓辜。

2.internal(默認(rèn)級(jí)別):可以訪問(wèn)自己模塊或應(yīng)用中源文件里的任何實(shí)體,但是別人不能訪問(wèn)該模塊中源文件里的實(shí)體垛孔。通常情況下藕甩,某個(gè)接口或Framework作為內(nèi)部結(jié)構(gòu)使用時(shí),你可以將其設(shè)置為internal級(jí)別周荐。

3.private:只能在當(dāng)前源文件中使用的實(shí)體辛萍,稱為私有實(shí)體。使用private級(jí)別羡藐,可以用作隱藏某些功能的實(shí)現(xiàn)細(xì)節(jié)贩毕。

注意:1.Framework的內(nèi)部實(shí)現(xiàn)細(xì)節(jié)依然可以使用默認(rèn)的internal級(jí)別,或者也可以定義為private級(jí)別仆嗦。只有你想將它作為API的實(shí)體辉阶,才將其定義為public級(jí)別。

2.一個(gè)public類的所有成員的訪問(wèn)級(jí)別默認(rèn)為internal級(jí)別瘩扼。

3.元組的訪問(wèn)級(jí)別遵循它里面元組中最低級(jí)的訪問(wèn)級(jí)別谆甜。

4.枚舉中成員的訪問(wèn)級(jí)別繼承自該枚舉。public enum CompassPoint {}該類型public前定義集绰。

5.子類的訪問(wèn)級(jí)別不得高于父類的訪問(wèn)級(jí)別规辱。比如說(shuō),父類的訪問(wèn)級(jí)別是internal栽燕,子類的訪問(wèn)級(jí)別就不能聲明為public罕袋。

29.判等Equatable協(xié)議

swift中使用==判斷字符串內(nèi)容是否相同默認(rèn)字符串實(shí)現(xiàn)Equatable協(xié)議可以重寫該協(xié)議改變

注意這個(gè)協(xié)議在func == (lhs: String, rhs: String) -> Bool無(wú)需在實(shí)現(xiàn)協(xié)議中寫應(yīng)該放在全局

對(duì)于==的實(shí)現(xiàn)我們并沒(méi)有像實(shí)現(xiàn)其他一些接口一樣將其放在對(duì)應(yīng)的extension里,而是放在了全局的scope中。這是合理的做法,因?yàn)槟銘?yīng)該需要在全局范圍內(nèi)都能使用==碍岔。事實(shí)上,Swift的操作符都是全局的,關(guān)于操作符的更多信息,可以參看操作符浴讯。

class TodoItem {

let uuid: String

var title: String

init(uuid: String, title: String) {

self.uuid = uuid

self.title = title

}

}

extension TodoItem: Equatable {

}

//比較兩個(gè)對(duì)象

func == (lhs: TodoItem, rhs: TodoItem) -> Bool {

return lhs.uuid == rhs.uuid

}

//比較字符串

func == (lhs: String, rhs: String) -> Bool {

return true

}

補(bǔ):操作符(自定義運(yùn)算符)支持重載操作符這樣的特性

func +* (left: Vector2D, right: Vector2D) -> Double {

return left.x * right.x + left.y * right.y

}

注意:重載操作符時(shí)操作符是不能定義在局部域中的

要新加操作符的話,需要先對(duì)其進(jìn)行聲明,告訴編譯器這個(gè)符號(hào)其實(shí)是一個(gè)操作符。添加如下代碼

結(jié)合性(associativity)的值默認(rèn)為none(left蔼啦,right和none)榆纽,優(yōu)先級(jí)(precedence)默認(rèn)為100。

表達(dá):左結(jié)合的left捏肢,優(yōu)先級(jí)為140 :associativity left precedence 140

infix operator +* {

associativity none precedence 160

}

infix

表示要定義的是一個(gè)中位操作符,即前后都是輸入;其他的修飾子還包括prefix和postfix,不再贅述;

associativity

定義了結(jié)合律,即如果多個(gè)同類的操作符順序出現(xiàn)的計(jì)算順序奈籽。比如常見(jiàn)的加法和減法都是left,就是說(shuō)多個(gè)加法同時(shí)出現(xiàn)時(shí)按照從左往右的順序計(jì)算(因?yàn)榧臃M足交換律,所以這個(gè)順序無(wú)所謂,但是減法的話計(jì)算順序就很重要了)。點(diǎn)乘的結(jié)果是一個(gè)Double,不再會(huì)和其他點(diǎn)乘結(jié)合使用,所以這里寫成none;

precedence

運(yùn)算的優(yōu)先級(jí),越高的話越優(yōu)先進(jìn)行運(yùn)算鸵赫。Swift中乘法和除法的優(yōu)先級(jí)是150,加法和減法是140,這里我們定義點(diǎn)積優(yōu)先級(jí)160,就是說(shuō)應(yīng)該早于普通的乘除進(jìn)行運(yùn)算衣屏。

注意:Swift中對(duì)NSObject子類對(duì)象使用==時(shí)要是該子類沒(méi)有實(shí)現(xiàn)這個(gè)操作符重載的話將回滾到-isEqual:方法

30.哈希Hashable協(xié)議

在Objective-C中NSObject中有一個(gè)-hash方法。當(dāng)我們對(duì)一個(gè)NSObject的子類的-isEqual:進(jìn)行重寫的時(shí)候,我們一般也需要將-hash方法重寫奉瘤。

在Swift中,NSObject也默認(rèn)就實(shí)現(xiàn)了Hashable,而且和判等的時(shí)候情況類似,NSObject對(duì)象的hashValue屬性的訪問(wèn)將返回其對(duì)應(yīng)的-hash的值勾拉。對(duì)于非NSObject的類,我們需要遵守Hashable并根據(jù)==操作符的內(nèi)容給出哈希算法;而對(duì)于NSObject子類,需要根據(jù)是否需要在Objective-C中訪問(wèn)而選擇合適的重寫方式,去實(shí)現(xiàn)Hashable的hashValue或者直接重寫NSObject的-hash方法

31.斷言

注意:斷言只會(huì)在Debug環(huán)境中有效,而在Release編譯中所有的斷言都將被禁用

/*當(dāng)條件滿足條件的時(shí)候break同時(shí)打印出自己的定義內(nèi)容*/

assert(name == "zzqS", "it is zzq")

//OC中都是宏

/*當(dāng)條件滿足條件的時(shí)候break*/

assert(YES)

/*當(dāng)條件不滿足條件的時(shí)候break同時(shí)打印出自己的定義內(nèi)容*/

NSAssert(NO, @"Unimplemented JSBadgeAligment type %@", @break");

32.fatalError

@noreturn:不再需要返回值

@noreturn func fatalError(message: StaticString,file: StaticString = default,line: UWord = default)

fatalError(@"遇到我會(huì)強(qiáng)制退出程序...")

在父類方法中寫調(diào)用fatalError("這個(gè)方法必須在子類中被重寫")子類重寫覆蓋該方法則不會(huì)調(diào)用父類fatalError方法

//父類標(biāo)明了某個(gè)init方法是required的,但是你的子類永遠(yuǎn)不會(huì)使用這個(gè)方法來(lái)初始化時(shí),就可以采用類似的方式,被廣泛使用(以被廣泛討厭的) init(coder: NSCoder)就是一個(gè)例子

required init(coder: NSCoder) {

fatalError("NSCoding not supported")

}

32.final:final關(guān)鍵字可以用在class,func或者var前面進(jìn)行修飾,表示不允許對(duì)該內(nèi)容進(jìn)行繼承或者重寫操作

33.Swizzle

OC:

+ (void)load {

static dispatch_once_t onceToken;

dispatch_once(&onceToken, ^{

Method originalSelector = class_getInstanceMethod([UIButton class], @selector(sendAction:to:forEvent:));

Method swizzledSelector = class_getInstanceMethod([UIButton class], @selector(xxx_sendAction:to:forEvent:));

method_exchangeImplementations(originalSelector, swizzledSelector);

});

}

swift使用黑魔法替換UIButton的點(diǎn)擊事件統(tǒng)計(jì)所有按鈕被點(diǎn)擊數(shù)目

extension UIButton {

class func xxx_swizzleSendAction() {

struct xxx_swizzleToken {

static var onceToken : dispatch_once_t = 0

}

dispatch_once(&xxx_swizzleToken.onceToken) {

let cls: AnyClass! = UIButton.self

let originalSelector = Selector("sendAction:to:forEvent:")

let swizzledSelector = Selector("xxx_sendAction:to:forEvent:")

let originalMethod =

class_getInstanceMethod(cls, originalSelector)

let swizzledMethod =

class_getInstanceMethod(cls, swizzledSelector)

method_exchangeImplementations(originalMethod, swizzledMethod)

}

}

public func xxx_sendAction(action: Selector,

to: AnyObject!,

forEvent: UIEvent!)

{

struct xxx_buttonTapCounter {

static var count: Int = 0

}

xxx_buttonTapCounter.count += 1

print(xxx_buttonTapCounter.count)

xxx_sendAction(action, to: to, forEvent: forEvent)

}

}

注意:在Objective-C中我們一般在category的+load中完成,但是Swift的extension和Objective-C的category略有不同,extension并不是運(yùn)行時(shí)加載的,因此也沒(méi)有加載時(shí)候就會(huì)被調(diào)用的類似load的方法煮甥。另外,extension中也不應(yīng)該做方法重寫去覆蓋load (其實(shí)重寫也是無(wú)效的)最后我們看起來(lái)是在這個(gè)方法中調(diào)用了自己,似乎會(huì)形成一個(gè)死循環(huán)盗温。但是因?yàn)槲覀儗?shí)際上已經(jīng)交換了sendAction:to:forEvent:和xxx_sendAction:to:forEvent:的實(shí)現(xiàn),所以在做這個(gè)調(diào)用時(shí)恰好調(diào)用到的是原來(lái)的那個(gè)方法的實(shí)現(xiàn)藕赞。同理,在外部使用sendAction:to:forEvent:的時(shí)候(也就是點(diǎn)擊按鈕的時(shí)候),實(shí)際調(diào)用的實(shí)現(xiàn)會(huì)是我們?cè)谶@里定義的帶有計(jì)數(shù)器累加的實(shí)現(xiàn)

class Swizzler: NSObject {

override class func initialize() {

var onceToken : dispatch_once_t = 0;

dispatch_once(&onceToken) {

UIButton.xxx_swizzleSendAction()

}

}

}

Swizzle使用了Objective-C的動(dòng)態(tài)派發(fā),對(duì)于NSObject的子類是可以直接使用的,但是對(duì)于Swift的類,因?yàn)槟J(rèn)并沒(méi)有使用Objective-C運(yùn)行時(shí),因此也沒(méi)有動(dòng)態(tài)派發(fā)的方法列表,所以如果要Swizzle的是Swift類型的方法的話,我們需要將原方法和替換方法都加上dynamic標(biāo)記,以指明它們需要使用動(dòng)態(tài)派發(fā)機(jī)制。關(guān)于這方面的知識(shí),可以參看@objc和dynamic的內(nèi)容

34.lazy修飾符和lazy方法:

Swift中我們使用在變量屬性前加lazy關(guān)鍵字的方式來(lái)簡(jiǎn)單地指定延時(shí)加載

class ClassA {

lazy var str: String = {

let str = "Hello"

print("只在首次訪問(wèn)輸出")

return str

}() //注意有個(gè)()

}

簡(jiǎn)化:lazy var str: String = "Hello"

注意:1.只能聲明屬性是變量2.顯式地指定屬性類型

35.性能

在Objective-C對(duì)于NSObject的方法調(diào)用在編譯是會(huì)被轉(zhuǎn)為objc_megSend方法卖局。運(yùn)用OC運(yùn)行時(shí)特性,使用動(dòng)態(tài)派發(fā)的方式在運(yùn)行時(shí)對(duì)方法進(jìn)行查找斧蜕。

個(gè)人認(rèn)為最為靠近實(shí)際使用的標(biāo)志性特性就是它的消息機(jī)制了,能到比較容易的做到很多靜態(tài)語(yǔ)言很難做到的事情. Objective-C簡(jiǎn)單的運(yùn)行時(shí)知識(shí):

1.類和對(duì)象都是id,在給你一個(gè)id的前提下無(wú)法直觀的知道這個(gè)對(duì)象是類對(duì)象還是類本身.簡(jiǎn)單的可以簡(jiǎn)化成runtime管理的都是id (id的本質(zhì)其實(shí)是objc_object, objc_class頭部其實(shí)就是id,也就是isa).

2. Class在objc中是動(dòng)態(tài)創(chuàng)建的, selector, method, imp, protocol等都是隨后綁定上去的(即所謂的運(yùn)行時(shí)綁定).

3.通過(guò)runtime能夠查出當(dāng)前運(yùn)行時(shí)環(huán)境中所有的類,每個(gè)類中的方法,每個(gè)類消息的綁定,每個(gè)類的實(shí)現(xiàn)的協(xié)議,每個(gè)協(xié)議的定義,每個(gè)類當(dāng)前的消息緩存等一切你想知道的東西.

4.類的方法(消息)調(diào)用是間接的.

swift(靜態(tài)語(yǔ)言)和objective-c(具有動(dòng)態(tài)特性的靜態(tài)語(yǔ)言)都是(編譯語(yǔ)言)編譯執(zhí)行砚偶,swift比objective-c快的原因是批销,objective-c的方法是在運(yùn)行時(shí)確定函數(shù)地址,編譯時(shí)只記錄方法名,運(yùn)行時(shí)調(diào)用方法是根據(jù)方法名從哈希表中查找函數(shù)地址并跳躍到該地址執(zhí)行代碼,函數(shù)訪問(wèn)機(jī)制類似于C++的虛函數(shù),大量時(shí)間浪費(fèi)到查表上了。而swift的函數(shù)是在編譯時(shí)確定函數(shù)地址侨颈,運(yùn)行中直接跳躍到函數(shù)地址執(zhí)行,無(wú)須查表芯义,所以速度比objective-c快

但是swift使用繼承NSObjct的類是具有動(dòng)態(tài)特性的

36.Log輸出

FILE String包含這個(gè)符號(hào)的文件的路徑

LINE Int符號(hào)出現(xiàn)處的行號(hào)

COLUMN Int符號(hào)出現(xiàn)處的列

FUNCTION String包含這個(gè)符號(hào)的方法名字

func printLog(message: T,file: String = __FILE__,method: String = __FUNCTION__, line: Int = __LINE__){

print("\(file.lastPathComponent)[\(line)], \(method): \(message)")

}

37.Associated Object

swift中使用

private var key: Void

extension Class {

var title: String? {

get {

return objc_getAssociatedObject(self, &key) as? String

}

set {

objc_setAssociatedObject(self,&key, newValue,

.OBJC_ASSOCIATION_RETAIN_NONATOMIC)

}

}

}

38.@asmname

無(wú)需通過(guò)c的h文件和-Bridging-Header.h文件導(dǎo)入C函數(shù)

@asmname("testCFun") funcctestCFun() -> Void

ctestCFun()直接調(diào)用

39.sizeofValue替換sizeof

sizeofValue(String)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末肛搬,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子毕贼,更是在濱河造成了極大的恐慌温赔,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,968評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件鬼癣,死亡現(xiàn)場(chǎng)離奇詭異陶贼,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)待秃,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門拜秧,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人章郁,你說(shuō)我怎么就攤上這事枉氮≈狙埽” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 153,220評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵聊替,是天一觀的道長(zhǎng)楼肪。 經(jīng)常有香客問(wèn)我,道長(zhǎng)惹悄,這世上最難降的妖魔是什么春叫? 我笑而不...
    開(kāi)封第一講書人閱讀 55,416評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮泣港,結(jié)果婚禮上暂殖,老公的妹妹穿的比我還像新娘。我一直安慰自己当纱,他們只是感情好呛每,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著坡氯,像睡著了一般晨横。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上廉沮,一...
    開(kāi)封第一講書人閱讀 49,144評(píng)論 1 285
  • 那天颓遏,我揣著相機(jī)與錄音,去河邊找鬼滞时。 笑死叁幢,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的坪稽。 我是一名探鬼主播曼玩,決...
    沈念sama閱讀 38,432評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼窒百!你這毒婦竟也來(lái)了黍判?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 37,088評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤篙梢,失蹤者是張志新(化名)和其女友劉穎顷帖,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體渤滞,經(jīng)...
    沈念sama閱讀 43,586評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡贬墩,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了妄呕。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片陶舞。...
    茶點(diǎn)故事閱讀 38,137評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖绪励,靈堂內(nèi)的尸體忽然破棺而出肿孵,到底是詐尸還是另有隱情唠粥,我是刑警寧澤,帶...
    沈念sama閱讀 33,783評(píng)論 4 324
  • 正文 年R本政府宣布停做,位于F島的核電站晤愧,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏雅宾。R本人自食惡果不足惜养涮,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評(píng)論 3 307
  • 文/蒙蒙 一葵硕、第九天 我趴在偏房一處隱蔽的房頂上張望眉抬。 院中可真熱鬧,春花似錦懈凹、人聲如沸蜀变。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,333評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)库北。三九已至,卻和暖如春们陆,著一層夾襖步出監(jiān)牢的瞬間寒瓦,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,559評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工坪仇, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留杂腰,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,595評(píng)論 2 355
  • 正文 我出身青樓椅文,卻偏偏與公主長(zhǎng)得像喂很,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子皆刺,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容