2015年12月2日 星期三

iOS筆記:Swift (1)

常數和變數

The value of a constant cannot be changed once it is set, whereas a variable can be set to a different value in the future.

常數和變數宣告方法

常數和變數必须在使用前宣告,用let來宣告常數,用var來宣告變數。

    let maximumNumberOfLoginAttempts = 10
    var currentLoginAttempt = 0

在上述例子中的概念是,允许的最大嘗試登入次數被宣告為一个常數,因为這個值是固定的不會變。當前嘗試登錄次數被宣告為一個變數,因為每次嘗試登錄失敗的時候都需要增加這個值。

資料型別

Swift中型別按照參數傳遞方式不同可以分為:值型別和參考型別
值型別: 在賦值或把參數傳遞給函式的時候,建立一個參數的副本,把副本傳遞過去,這樣在函式的呼叫過程中不會影響原始資料.

參考型別: 在賦值或把參數傳遞給函式的時候,把本身資料傳遞過去,這樣在函式的呼叫過程中會影響原始資料.

數字型別之間的轉換

Swift對於型別的檢查非常嚴格,不同型別之間不能隨便轉換.

整數之間有兩種轉換方法:
1. 從小範圍數到大範圍數轉換是自動的
2. 從大範圍數到小範圍數需要”強制轉換型別”,有可能造成資料精確度的丟失

Type annotation

當你聲明常量或者變量的時候可以加上類型標註(type annotation),說明常量或者變量中要存儲的值的類型。冒號代表著“是...類型”

    var welcomeMessage: String
    welcomeMessage = "Hello"

在一行中定義多個同樣類型的變量,用逗號分割,並在最後一個變量名之後添加類型標註:

    var red, green, blue: Double

用print(:separator:terminator:)函數來輸出當前常量或變量的值,也可以將常量或變量名放入圓括號中,並在開括號前使用反斜杠將其轉義:

    var friendlyWelcome = "Hello!"
    friendlyWelcome = "Bonjour!"
    print(friendlyWelcome) // 输出 "Bonjour!"

    print("The current value of friendlyWelcome is \(friendlyWelcome)")
    // 输出 "The current value of friendlyWelcome is Bonjour!

The separator and terminator parameter have default values, so you can omit them when you call this function.

Type Aliases

類型別名(typealiases)就是給現有類型定義另一個名字。你可以使用typealias關鍵字來定義類型別名。

    typealias AudioSample = UInt16
    var maxAmplitudeFound = AudioSample.min
    // maxAmplitudeFound 现在是 0    

AudioSample被定義為UInt16的一個別名。因為它是別名,AudioSample.min實際上是UInt16.min,所以會給maxAmplitudeFound賦一個初值0。

Tuples

把多個值組合成一個複合值。元組內的值可以是任意類型,並不要求是相同類型。也可以將一個元組的內容分解(decompose)成單獨的常量和變量,然後你就可以正常使用它們了:

分解的时候可以把要忽略的部分用下標線(_)标记

    let http404Error = (404, "Not Found")
    // http404Error 的類型是 (Int, String),值是 (404, "Not Found")

    let (statusCode, statusMessage) = http404Error
    print("The status code is \(statusCode)")
    // 输出 "The status code is 404"      
    print("The status message is \(statusMessage)")
    // 输出 "The status message is Not Found"

    let (justTheStatusCode, _) = http404Error

Optional Binding

使用optional binding來判斷可選類型是否包含值,如果包含就把值賦給一個臨時常量或者變量。optional binding可以用在if和while語句中,這條語句不僅可以用來判斷可選類型中是否有值,同時可以將可選類型中的值賦給一個常量或者變量。

    let possibleNumber = "123"

    if let actualNumber = Int(possibleNumber) {
    print("\'\(possibleNumber)\' has an integer value of \(actualNumber)")
} else {
    print("\'\(possibleNumber)\' could not be converted to an integer")
}
    // 输出 "'123' has an integer value of 123"

這段代碼可以被理解為:
“如果Int(possibleNumber)返回的可選Int包含一個值,創建一個叫做actualNumber的新常量並將可選包含的值賦給它。”

++i vs i++

    var a = 0
    let b = ++a // a 和 b 现在都是 1
    let c = a++ // a 现在 2, 但 c 是 a 自增前的值 1

let b = ++a先把a加1了再返回a的值。所以a和b都是新值1。
而let c = a++,是先返回了a的值,然后a才加1。所以c得到了a的旧值1,而a加1后变成2。

Ternary Conditional Operator

Ternary Conditional Operator是以下代码的缩寫形式:

if question {
    answer1
} else {
    answer2
}

ex.

let contentHeight = 40
let hasHeader = true
let rowHeight = contentHeight + (hasHeader ? 50 : 20)
// rowHeight 现在是 90

Nil Coalescing Operator

The nil coalescing operator (a ?? b) unwraps an optional a if it contains a value, or returns a default value b if a is nil.
這個運算式有兩個條件:

  1. a必須是Optional類型
  2. b的類型必須要和a的類型保持一致

Nil Coalescing Operator 是以下的判斷式的縮寫”

a != nil ? a! : b

ex.

let defaultColorName = "red"
var userDefinedColorName: String?   //default值為 nil

var colorNameToUse = userDefinedColorName ?? defaultColorName
// userDefinedColorName 的值為nil,所以 colorNameToUse 的值為 "red"

Closed Range Operator and Half-Open Range Operator

Closed Range Operator (a…b)定義一個包含從a到b(包括a和b)的所有值的區間,b必須大於等於a.
用法:

for index in 1...5 {
    print("\(index) * 5 = \(index * 5)")
}
// 1 * 5 = 5
// 2 * 5 = 10
// 3 * 5 = 15
// 4 * 5 = 20
// 5 * 5 = 25

Half-Open Range Operator (a..<b)定義一個從a到b但不包括b的區間.

Initializing an Empty String

要創建一個空字符串作為初始值,可以將空的字符串字面量賦值給變量,也可以初始化一個新的String實例:

    var emptyString = ""               // empty string literal
    var anotherEmptyString = String()  // initializer syntax
    // these two strings are both empty, and are equivalent to each other

可以通過檢查其Boolean類型的isEmpty屬性來判斷該字符串是否為empty:

    if emptyString.isEmpty {
        print("Nothing to see here")
    }
    // prints "Nothing to see here"

Concatenating Strings and Characters

let string1 = "hello"
let string2 = " there"
var welcome = string1 + string2
// welcome = "hello there"

var instruction = "look over"
instruction += string2
// instruction = "look over there"

let exclamationMark: Character = "!"
welcome.append(exclamationMark)
// welcome = "hello there!"

String Indices

每一個String值都有一個關聯的索引(index)類型,String.Index,它對應著字符串中的每一個Character的位置.通過調用String.Index的predecessor()方法,可以立即得到前面一個索引,調用successor()方法可以立即得到後面一個索引。

let greeting = "Guten Tag!"
greeting[greeting.startIndex]
// G
greeting[greeting.endIndex.predecessor()]
// !
greeting[greeting.startIndex.successor()]
// u
let index = greeting.startIndex.advancedBy(7)
greeting[index]
// a

使用characters屬性的indices屬性會創建一個包含全部索引的範圍(Range),用來在一個字符串中訪問單個字符。

for index in greeting.characters.indices {
   print("\(greeting[index]) ", terminator: " ")
}
// 输出 "G u t e n   T a g !"

Inserting and Removing

insert(_:atIndex:)方法可以在一個字符串的指定索引插入一個字符.

var welcome = "hello"
welcome.insert("!", atIndex: welcome.endIndex)
// welcome now = "hello!"

使用insertContentsOf(_:at:)方法可以在一个字符串的指定索引插入一个字符串.

welcome.insertContentsOf(" there".characters, at: welcome.endIndex.predecessor())
// welcome = "hello there!"

removeAtIndex(_:)方法可以在一個字符串的指定索引刪除一個字符.

welcome.removeAtIndex(welcome.endIndex.predecessor())
// welcome = "hello there"

let range = welcome.endIndex.advancedBy(-6)..`<welcome.endIndex
welcome.removeRange(range)
// welcome = "hello"

Prefix and Suffix Equality

通過調用字符串的hasPrefix(_:)/hasSuffix(_:)方法來檢查字符串是否擁有特定前綴/後綴,兩個方法均接收一個String類型的參數,並返回一個布爾值。

    let romeoAndJuliet = [
        "Act 1 Scene 1: Verona, A public place",
        "Act 1 Scene 2: Capulet's mansion",
        "Act 1 Scene 3: A room in Capulet's mansion",
        "Act 1 Scene 4: A street outside Capulet's mansion",
        "Act 1 Scene 5: The Great Hall in Capulet's mansion",
        "Act 2 Scene 1: Outside Capulet's mansion",
        "Act 2 Scene 2: Capulet's orchard",
        "Act 2 Scene 3: Outside Friar Lawrence's cell",
        "Act 2 Scene 4: A street in Verona",
        "Act 2 Scene 5: Capulet's mansion",
        "Act 2 Scene 6: Friar Lawrence's cell"
    ]
    //hasPrefix(_:)方法計算話劇中第一幕的場景數:
    var act1SceneCount = 0
    for scene in romeoAndJuliet {
        if scene.hasPrefix("Act 1 ") {
            ++act1SceneCount
        }
    }
    print("There are \(act1SceneCount) scenes in Act 1")
    // prints "There are 5 scenes in Act 1"

參考資料:
1. https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/index.html#//apple_ref/doc/uid/TP40014097-CH3-ID0
2. http://wiki.jikexueyuan.com/project/swift/

沒有留言:

張貼留言