Swift 編程語言學習

Hello World:html

print(Hello World)

本文已使用Swift3更新。v3的主要更新見Swift 3 更新ios

快速上手

// 常量變量
let constVar = "100"
var value = 0
var red, green, blue: Double

// 數組
var str1 = "AAA"
var str2 = "BBB"
var array:[String] = [str1, str2]
array.append("CCC")
for str in array {
    print("str: \(str)")
}
var myStr = array[2]

// 字典
var dict:[String: String] = ["Key1":"Val1", "Key2":"Val2"]
dict["Key3"] = "Val3"
dict["Key2"] = nil // delete Key2
for (key, val) in dict {
    print("key: \(key), value:\(val)")
}

// 枚舉
enum CollisionType: Int {
    case Player = 1
    case Enemy = 2
}
var type = CollisionType.Player

// 函數
func doIt() -> Int {
    return 0
}
func doIt(a:Int, b:Int) -> Int {
    return a+b
}

// 類
class Shape {
    var numberOfSides: Int = 0
    var name: String

    init(name: String) {
        self.name = name
    }
    deinit {  // 析構函數,若是你須要
    }

    func simpleDescription() -> String {
        return "\(self.name) with \(numberOfSides) sides."
    }
}
var shape = Shape(name: "Box")
shape.numberOfSides = 7
var shapeDescription = shape.simpleDescription()
print(shapeDescription)  // Box with 7 sides.

類型

基本類型: nil, Int, Float/Double, Bool, String, Optionalobjective-c

集合類型: Array, Set, Dictionaryswift

複合類型: Tuple, Functionsegmentfault

命名類型: Class, Struct, Enum, Protocol數組

Int(UInt, Int, UInt8(16,32,64), Int8(16,32,64), UInt8.min, UInt8.max), 32位平臺Int爲Int32, 64爲Int64, UInt同理閉包

String類型支持Unicode. Unicode標量寫成u{n} ("u{24}","u{1F496}")app

Double(64位浮點)、Float(32位浮點)框架

類型別名(type aliases)

typealias AudioSample = UInt16
var maxAmplitudeFound = AudioSample.min  // maxAmplitudeFound如今是0

元組

元組類型使用逗號隔開並使用括號括起來的0個或多個類型組成的列表less

var a = (1,2,」haha」)

集合類型

Swift的Array類型被橋接到Foundation中的NSArray類

var someInts = [Int]()  // 空數組
var threeDoubles = [Double](repeating:0.0, count: 3)  // [0.0, 0.0, 0.0]
var sixDoubles = threeDoubles + [0.1, 0.2, 0.3] // [0, 0, 0, 0.1, 0.2, 0.3]
var talkList = ["ha", "xi", "mi", "ga", "he", "wa"]
talkList[2...4] = ["hehe", "yoyo"]  // 利用下標來一次改變一系列數據值
talkList // ["ha", "xi", "hehe", "yoyo", "wa"]
talkList.insert("kao", at: 0) // ["kao", "ha", "xi", "hehe", "yoyo", "wa"]

Swift的Set類型被橋接到Foundation中的NSSet類

var letters = Set<Character>()
print("letters is of type Set<Character> with \(letters.count) items.")
letters.insert("a")
letters = []  // letters 如今是一個空的 Set, 可是它依然是 Set<Character> 類型
// 使用數組字面量來構造集合
var favoriteGenres: Set<String> = ["Rock", "Classical", "Hip hop"]

集合類型的哈希值,好比a==b,所以必須a.hashValue == b.hashValue,Swift 的全部基本類型(好比String,Int,Double和Bool)默認都是可哈希化的

Swift的Dictionary類型被橋接到Foundation的NSDictionary類。

let airports = ["YYZ": "Toronto Pearson", "LHR": "London Heathrow"]
let airportCodes = [String](airports.keys) // ["LHR", "YYZ"]
let airportNames = [String](airports.values) // ["London Heathrow", "Toronto Pearson"]

運算符

Swift 支持 C 語言中的所有位運算符

Swift 中是能夠對浮點數進行求餘的

8 % 2.5   // Swift3不在支持
8.truncatingRemainder(dividingBy: 2.5) // Swift3

Swift 提供恆等===和不恆等!==

請注意,「等價於」(用三個等號表示,===)與「等於」(用兩個等號表示,==)的不一樣:

  • 「等價於」表示兩個類類型(class type)的常量或者變量引用同一個類實例。

  • 「等於」表示兩個實例的值「相等」或「相同」,斷定時要遵守設計者定義的評判標準,所以相對於「相等」來講,這是一種更加合適的叫法。

空合運算符(a ?? b): 表達式a必須是Optional類型默認值,b的類型必需要和a存儲值的類型保持一致, 是對如下代碼的簡短表達方法

a != nil ? a! : b

與C語言中的算術運算符不一樣,Swift中的算術運算符默認是不會溢出的,若是容許溢出行爲,使用溢出運算符(&+,&-,&*)

Optional類型

當基礎類型(整形、浮點、布爾等)沒有值時,是不能使用的。一個Optional值未經初始化時爲nil。

var str: String?      //未被初始化,nil
var nIndex: Int? = 2  //初始化爲2,Optional(2)

強制解析(forced unwrapping)

使用!來獲取一個不存在的可選值會致使運行時錯誤。使用!來強制解析值以前,必定要肯定可選包含一個非nil的值。

if convertedNumber != nil {
    // 輸出 "convertedNumber has an integer value of 123."
    print("convertedNumber has an integer value of \(convertedNumber!).")
}

隱式解析

let possibleString: String? = "An optional string."
let forcedString: String = possibleString! // 須要驚歎號來獲取值
let assumedString: String! = "An implicitly unwrapped optional string."
let implicitString: String = assumedString  // 不須要感嘆號

if assumedString != nil {
    print(assumedString)  // 輸出 "An implicitly unwrapped optional string."
}
if let definiteString = assumedString {
    print(definiteString)  // 輸出 "An implicitly unwrapped optional string."
}

可選鏈式調用

// residence爲optional類型,不管numberOfRooms屬性是否爲optional類型,roomCount將爲Int?
if let roomCount = john.residence?.numberOfRooms {
    print("John's residence has \(roomCount) room(s).")
} else {
    print("Unable to retrieve the number of rooms.")
}

可選鏈式調用提供了另外一種訪問numberOfRooms的方式,使用問號(?)來替代原來的歎號(!),在residence後面添加問號以後,Swift 就會在residence不爲nil的狀況下訪問numberOfRooms.

注意,Dictionary類型的鍵的下標返回可選類型值,故能夠用可選鏈式調用

var testScores = ["key1": [86, 82, 84], "key2": [79, 94, 81]]
testScores["key2"]?[0]++

流程控制

條件和循環變量的括號能夠省略,語句體的大括號是必須的

if語句

條件必須是一個布爾表達式, if a {...}將報錯,a不會隱形地與 0 作對比

guard的執行取決於一個表達式的布爾值。咱們可使用guard語句來要求條件必須爲真時,以執行guard語句後的代碼。不一樣於if語句,一個guard語句老是有一個else分句,若是條件不爲真則執行else分句中的代碼。

Switch-Case

switch中匹配到的case子句以後,程序會退出switch語句,並不會繼續向下運行,因此不須要在每一個子句結尾寫break, 若是須要貫穿能夠用 fallthrough

let vegetable = "red pepper"
switch vegetable {  // Is it a spicy red pepper?
case "celery":
    print("Add some raisins and make ants on a log.")
case "cucumber", "watercress":
    print("That would make a good tea sandwich.")
case let x where x.hasSuffix("pepper"):
    print("Is it a spicy \(x)?")
default:
    print("Everything tastes good in soup.")
}

while循環 (while,repeat-while)

var n = 2
while n < 100 {
    n = n * 2
}
print(n)  // 128

var m = 2
repeat {
    m = m * 2
} while m < 100
print(m)  // 128

for循環

你能夠在循環中使用 「..<」,「...」 來表示範圍,也可使用傳統的寫法,二者是等價的

var nLoop1 = 0
for var i = 0; i <= 3; ++i { // Swift3中已移除這種C風格的for,且移除了++操做符
    nLoop1 += i
}
var nLoop2 = 0
for i in 0...3 {  // 包含3,若是用..<就不包含3
    nLoop2 += i
}

函數

用func聲明函數, swift中函數爲一級類型

// ->後爲返回值
func greet(name: String, day: String) -> String {
    return "Hello \(name), today is \(day)."
}

// 使用元組能夠返回多個返回值
func getGasPrices() -> (Double, Double, Double) {
    return (3.59, 3.69, 3.79)
}

// 可變形參
func sumOf(numbers: Int...) -> Int {
    var sum = 0
    for number in numbers {
        sum += number
    }
    return sum
}
print(sumOf(numbers: 2, 3, 1))  // 6

// 函數是一級類型,這意味着能夠做爲參數傳遞
func hasAnyMatches(list: [Int], condition: (Int) -> Bool) -> Bool {
    for item in list {
        if condition(item) {
            return true
        }
    }
    return false
}
func lessThanTen(number: Int) -> Bool {
    return number < 10
}
var numbers = [20, 19, 7, 12]
hasAnyMatches(list: numbers, condition: lessThanTen)  // true

// 指定外部參數名
func sayHello(to person: String, and anotherPerson: String) -> String {
    return "Hello \(person) and \(anotherPerson)!"
}
print(sayHello(to: "Bill", and: "Ted"))  // prints "Hello Bill and Ted!"

// 若是你不想爲參數設置外部參數名,用一個下劃線(_)代替一個明確的參數名。
// 注意,由於第一個參數默認忽略其外部參數名稱,顯式地寫下劃線是多餘的。
func someFunction(_ firstParameterName: Int, _ secondParameterName: Int) {
}
someFunction(1, 3)

注意,沒有返回值的函數具備隱式的返回類型Void(或者說是空元組)

運算符函數

類和結構體能夠爲現有的運算符提供自定義的實現,這一般被稱爲運算符重載。

struct Vector2D {
    var x = 0.0, y = 0.0
}
func + (left: Vector2D, right: Vector2D) -> Vector2D {
    return Vector2D(x: left.x + right.x, y: left.y + right.y)
}
let vector = Vector2D(x: 3.0, y: 1.0)
let anotherVector = Vector2D(x: 2.0, y: 4.0)
let combinedVector = vector + anotherVector
// combinedVector 是一個新的 Vector2D 實例,值爲 (5.0, 5.0)

前綴和後綴運算符: func關鍵字以前指定 prefix 或者 postfix 修飾符

prefix func - (vector: Vector2D) -> Vector2D {
    return Vector2D(x: -vector.x, y: -vector.y)
}

複合賦值運算符: 複合賦值運算符將賦值運算符(=)與其它運算符進行結合(如+=)。在實現的時候,須要把運算符的左參數設置成inout類型,由於這個參數的值會在運算符函數內直接被修改。

func += (inout left: Vector2D, right: Vector2D) {
    left = left + right
}

注意,不能對默認的賦值運算符(=)進行重載。只有組合賦值運算符能夠被重載。一樣地,也沒法對三目條件運算符 (a ? b : c) 進行重載。

自定義運算符: 新的運算符要使用 operator 關鍵字在全局做用域內進行定義,同時還要指定 prefix、infix 或者 postfix 修飾符:

prefix operator +++ {}

結合性的默認值是 none,優先級的默認值 100。參考

閉包

函數是一個特殊的閉包,swift的閉包能夠理解爲其餘語言的相似lambda表達式,形式:

{(parameters) -> returnType in
    statements
}
// closure
var numbers = [2,3,4,5]
var a = numbers.map({
    (number: Int) -> Int in
    let result = 3 * number
    return result
})
print(a)  // [6, 9, 12, 15]
// 更簡單的方式: 閉包參數類型已知
var b = numbers.map({ number in 3 * number })
// 根據參數位置
let sortedNumbers = numbers.sort { $0 > $1 }
print(sortedNumbers)  // [5, 4, 3, 2]

構造函數爲init,若是須要,用self來區分屬性

若是你須要在刪除對象以前進行一些清理工做,使用deinit建立一個析構函數

屬性裏能夠添加get/set,新值名默認爲newValue

若是你不須要計算屬性,可是仍然須要在設置一個新值以前或者以後運行代碼,使用willSet和didSet

繼承:class Square: NamedShape {},調用父類屬性或方法使用super.XXX

子類若是要重寫父類的方法的話,必須用override標記

延遲存儲屬性來避免複雜類中沒必要要的初始化: lazy

標記爲final來防止它們被重寫

下標腳本

struct TimesTable {
    let multiplier: Int
    subscript(index: Int) -> Int {
        return multiplier * index
    }
}
let threeTimesTable = TimesTable(multiplier: 3)
print("six times three is \(threeTimesTable[6])")
// 輸出 "six times three is 18"

處理變量的可選值時,你能夠在操做(好比方法、屬性和子腳本)以前加?。若是?以前的值是nil,?後面的東西都會被忽略,而且整個表達式返回nil。不然,?以後的東西都會被運行。在這兩種狀況下,整個表達式的值也是一個可選值。

let optionalSquare: Square? = Square(sideLength: 2.5, name: "optional Square")
let sideLength = optionalSquare?.sideLength

類型轉化

檢查類型:用 is

向下轉型:用類型轉換操做符(as? 或 as!)

AnyObject 能夠表示任何類類型的實例

Any 能夠表示任何類型,包括函數類型

訪問控制

對類、結構體、枚舉能夠設置訪問級別。

  • public:能夠訪問同一模塊源文件中的任何實體,在模塊外也能夠經過導入該模塊來訪問源文件裏的全部實體。一般狀況下,框架中的某個接口能夠被任何人使用時,你能夠將其設置爲 public 級別。

  • internal:能夠訪問同一模塊源文件中的任何實體,可是不能從模塊外訪問該模塊源文件中的實體。一般狀況下,某個接口只在應用程序或框架內部使用時,你能夠將其設置爲 internal 級別。

  • private:限制實體只能在所在的源文件內部使用。使用 private 級別能夠隱藏某些功能的實現細節。

public 爲最高(限制最少)訪問級別,private 爲最低(限制最多)訪問級別。默認爲 internal 級別。另外,子類的訪問級別不得高於父類的訪問級別、元組訪問級別爲成員裏最低級別。

枚舉和結構體

使用enum來建立一個枚舉。就像類和其餘全部命名類型同樣,枚舉能夠包含方法

enum Suit {
    case Spades, Hearts, Diamonds, Clubs
    func description() -> String {
        switch self {
        case .Spades:
            return "spades"
        case .Hearts:
            return "hearts"
        case .Diamonds:
            return "diamonds"
        case .Clubs:
            return "clubs"
        }
    }
}
let hearts = Suit.Hearts
let heartsDescription = hearts.description()

枚舉成員能夠有實例值,相同枚舉成員的實例能夠有不一樣的值。建立實例的時候傳入值便可。實例值和原始值是不一樣的:枚舉成員的原始值對於全部實例都是相同的,並且你是在定義枚舉的時候設置原始值。

enum ServerResponse {
    case Result(String, String)
    case Error(String)
}

let success = ServerResponse.Result("6:00 am", "8:09 pm")
let failure = ServerResponse.Error("Out of cheese.")

switch success {
case let .Result(sunrise, sunset):
    let serverResponse = "Sunrise is at \(sunrise) and sunset is at \(sunset)."
    print(serverResponse)
case let .Error(error):
    let serverResponse = "Failure...  \(error)"
    print(serverResponse)
}

結構體和類基本相似,但最大一個區別在於結構體是傳值,類是傳引用。

struct Card {
    var suit: Suit
    func description() -> String {
        return "The Card is suit of \(suit.description)"
    }
}

協議和拓展

protocol

使用protocol來聲明一個協議。類、枚舉和結構體均可以實現協議。

protocol ExampleProtocol {
    var simpleDescription: String { get }
    mutating func adjust()
}
class SimpleClass: ExampleProtocol {
    var simpleDescription: String = "A very simple class."
    var anotherProperty: Int = 69105
    func adjust() {
        simpleDescription += "  Now 100% adjusted."
    }
}

實現協議中的 mutating 方法時,如果類類型,則不用寫mutating關鍵字。而對於結構體和枚舉,則必須寫 mutating 關鍵字。

類只能單繼承,協議的實現能夠同時實現多個。而且協議間能夠相互繼承,並也能多繼承。在協議繼承列表中,添加class聲明只能被類採納。

class SomeClass: SomeSuperClass, FirstProtocol, AnotherProtocol {/*...*/}
protocol InheritingProtocol: SomeProtocol, AnotherProtocol {/*...*/}

協議只指定屬性的名稱和類型,還指定屬性是隻讀的仍是可讀可寫的。指定方法時不須要大括號和方法體。

協議能夠指定構造器,只是在實現類中要添加required

協議前添加@objc,表示只能被objective-c的類或@objc類採納。

extension

使用extension來爲現有的類型添加功能,好比新的方法和計算屬性。你可使用擴展在別處修改定義,甚至是從外部庫或者框架引入的一個類型,使得這個類型遵循某個協議。

extension Int: ExampleProtocol {
    var simpleDescription: String {
        return "The number \(self)"
    }
    mutating func adjust() {
        self += 42
    }
}
print(7.simpleDescription)

泛型

在尖括號裏寫一個名字來建立一個泛型函數或者類型。你也能夠建立泛型函數、方法、類、枚舉和結構體。

func repeatItem<Item>(item: Item, numberOfTimes: Int) -> [Item] {
    var result = [Item]()
    for _ in 0..<numberOfTimes {
        result.append(item)
    }
    return result
}
repeatItem(item: "knock", numberOfTimes:4)

// Reimplement the Swift standard library's optional type
enum OptionalValue<Wrapped> {
    case None
    case Some(Wrapped)
}
var possibleInteger: OptionalValue<Int> = .None
possibleInteger = .Some(100)

關聯類型

定義一個協議時,經過 typealias 關鍵字來指定關聯類型。

protocol A {
    typealias ItemType
    /*採用ItemType的一些方法*/
}
class SubA : A {
    typealias ItemType = Int
}

錯誤處理

func canThrowAnError() throws {
    // 這個函數有可能拋出錯誤
}

// 拋出錯誤消息,catch捕捉
do {
    try canThrowAnError()
    // 沒有錯誤消息拋出
} catch {
    // 有一個錯誤消息拋出
}

將錯誤轉換成可選值

func someThrowingFunction() throws -> Int {/*...*/}
// someThrowingFunction()拋出一個錯誤,x和y的值是nil
let x = try? someThrowingFunction()
let y: Int?
do {
    y = try someThrowingFunction()
} catch {
    y = nil
}

禁用錯誤傳遞

let photo = try! loadImage("./Resources/John Appleseed.jpg")
// 禁用錯誤傳遞

指定清理操做

使用defer語句在即將離開當前代碼塊時執行一系列語句

func processFile(filename: String) throws {
    if exists(filename) {
        let file = open(filename)
        defer {
            close(file)
        }
        while let line = try file.readline() {
            // 處理文件。
        }
        // close(file) 會在這裏被調用,即做用域的最後。
    }
}

資料

相關文章
相關標籤/搜索