Swift是供iOS和OS X應用編程的新程式設計語言,基於C和Objective-C,而卻沒有C的一些相容約束。Swift採用了安全的編程模式和添加現代的功能來是的編程更加簡單、靈活和有趣。介面則基於廣受人民群眾愛戴的Cocoa和Cocoa Touch架構,展示了軟體開發的新方向。
變數與常量
變數定義使用var,常量使用let,型別安全,有自動類型推導,注意賦值的=號兩邊必須有空格。變數和常量名是可以幾乎所有字元,這些都非常像javascript。中文編程一下牛逼了。
var a = 123 //a為Intlet b = "helo" //b為Stringvar 貓叫 = "喵"
數字
- 十進位
- 二進位 0b101
- 八進位 0o5
- 十六進位 0x5
比較長的數字間可以加上_用來提高程式的可讀性,比如0_0其實就是0,_線不能加在開頭
布爾類型
true和false,流程式控制制if的時候,判斷語句返回必須是一個Bool值,比如:
這樣就可以通過
它不像js裡會有自動類型轉換
類型別名
給現在的類型添加別名,同樣可以提高程式的可讀性,如
可以在別的地方使用 var 已發現的最大振幅 = 音頻採樣.min
元組
它可以是一組值,這些值不必是相同的類型,例如,定義我自己:
var jserme = ("183cm", 26, "76kg")
可以像數組一樣訪問
println(jserme.0) //返回183cm
元組還原為獨立的變數或者常量
let jserme = ("183cm",26,"76kg")let (身高, 年齡, 體重) = jsermeprintln("身高是 \(身高)")
也可以給每個值命名(這就像在JS裡把數組搞成了對象了。。。)
let jserme = (身高:"183cm",年齡:26,體重:"76kg")println("身高是 \(jserme.身高)")
字串
字串字面量只能用""來定義,String本質上是Character的有序集合。
for char in "一言既出"{ println(char)} /*一言既出*/
字面量與判斷是否為空白
var 字串 = "我是字串"var Null 字元串 = "" if Null 字元串.isEmpty { println("這是一個空的字串")} if Null 字元串 == "" { println("這是一個空的字串")}
字串執行個體有兩個方法hasPrefix與hasSuffix,如:
var 成語數組 = [ "一言既出", "一觸即發", "一呼百應", "一槌定音", "一無所有", "一生一世", "一見鐘情"] var count = 0for 成語 in 成語數組 { if(成語.hasPrefix("一")){ count++ }} println(count) //輸出7
與js一樣,string也是傳值引用,下面的兩個變數的修改不會影響到彼此
var 一串 = "我是字串一"var 二串 = 一串 二串 = "我是字串二" println("字串一:\(一串), 字串二:\(二串)")
區間運算子
閉區間使用a...b,從a到b,包含a與b,半區間a..b,從a到b,不包含b,例如:
var 成語數組 = [ "一言既出", "一觸即發", "一呼百應"] for i in 0..成語數組.count { println("第\(i)個成語是:\(成語數組[i])")}//這裡如何使用...會報錯,因為成語數組[3]是沒有值的
兩種集合,array 和 dictionaries
相對於js對數組和對象成員鬆散的要求,swift要求數組和dictionaries裡成員類型必須一致
var 購物清單: String[] = ["雞蛋", "牛奶"]//也可以是下面的這樣//var 購物清單 = ["雞蛋", "牛奶"]
數組的修改可以使用append方法或者+=
var 購物清單 = ["雞蛋", "牛奶"] 購物清單.append("蘋果") 購物清單 += "草莓" println("\(購物清單)") //[雞蛋, 牛奶, 蘋果, 草莓]
數組的擷取,可以通過索引,也可以通過區間運算子
var 購物清單 = ["雞蛋", "牛奶"] println("\(購物清單[0])") //雞蛋println("\(購物清單[0..1])") //[雞蛋]println("\(購物清單[0...1])") //[雞蛋, 牛奶]println("\(購物清單[0...2])") //[雞蛋, 牛奶, ]
dictionaries的定義
var airports: Dictionary<String, String> = ["TYO": "Tokyo", "DUB": "Dublin"] //也可以簡化為//var airports = ["TYO": "Tokyo", "DUB": "Dublin"]
它的修改與讀取使用[],而不能使用.
airports["BJ"] = "Beijin"
控制語句
如前面的幾個例子所示,控制語句的條件不像js有小括弧
for var index = 0; index < 3; index++ { println("index is \(index)")}//index is 0//index is 1//index is 2
函數
函數的聲明與調用:
func sayHello(personName: String) -> String { let greeting = "Hello, " + personName + "!" return greeting} println(sayHello("jserme"))
無返回的函數,其實質是返回一個Void,它等同於一個空的元組()
多傳回值的函數與預設參數:
func info(word:String = "aha") -> (length:Int, containA:Bool){ var containA = false for char in word { if( char == "a") { containA = true break } } return (word.utf16count, containA)} println(info(word: "波波")) //(2, false)println(info()) //(3, true)
便於閱讀的外部參數名,在參數定義之前,與參數定義以空格隔開,如下面的多個參數
func join(string s1: String, toString s2: String, withJoiner joiner: String) -> String { return s1 + joiner + s2} //調用的時候join(string: "hello", toString: "world", withJoiner: ", ")// returns "hello, world"
參數名與外部參數名一致,可以給參數名加#標識:
func containsCharacter(#string: String, #characterToFind: Character) -> Bool { for character in string { if character == characterToFind { return true } } return false}let containsAVee = containsCharacter(string: "aardvark", characterToFind: "v")// containsAVee equals true, because "aardvark" contains a "v"
函數的參數是常量,不可以修改,如果在函數內修改,變數定義前加var
func alignRight(var string: String, count: Int, pad: Character) -> String { let amountToPad = count - countElements(string) for _ in 1...amountToPad { string = pad + string } return string} let originalString = "hello"let paddedString = alignRight(originalString, 10, "-")// paddedString is equal to "-----hello"// originalString is still equal to "hello"
如果想在函數內修改傳入的參數,可以使用inout關鍵字來標識,傳入的參數需要首碼&,這內部實現應該是指標。
func swapTwoInts(inout a: Int, inout b: Int) { let temporaryA = a a = b b = temporaryA}var someInt = 3var anotherInt = 107swapTwoInts(&someInt, &anotherInt)println("someInt is now \(someInt), and anotherInt is now \(anotherInt)")// prints "someInt is now 107, and anotherInt is now 3"
函數類型,可以像js一樣使用函數作為參數及傳回值
func addTwoInts(a: Int, b: Int) -> Int { return a + b} //函數類型為 (Int, Int) -> Intfunc multiplyTwoInts(a: Int, b: Int) -> Int { return a * b}//函數類型為 (Int, Int) -> Int //接收名為mathFunction的函數類型func printMathResult(mathFunction: (Int, Int) -> Int, a: Int, b: Int) { println("Result: \(mathFunction(a, b))")}printMathResult(addTwoInts, 3, 5)// prints "Result: 8" //返回函數類型func stepForward(input: Int) -> Int { return input + 1}func stepBackward(input: Int) -> Int { return input - 1}func chooseStepFunction(backwards: Bool) -> (Int) -> Int { return backwards ? stepBackward : stepForward}var currentValue = 3let moveNearerToZero = chooseStepFunction(currentValue > 0)// moveNearerToZero now refers to the stepBackward() function
閉包
函數與它包含的內容相關的變數在一起稱為閉包。如sort函數:
let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"] func backwards(s1: String, s2: String) -> Bool { return s1 > s2}var reversed = sort(names, backwards)println(reversed)// reversed is equal to ["Ewa", "Daniella", "Chris", "Barry", "Alex"]s
使用閉包可以表示為:
let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"] var reversed = sort(names, {(s1:String, s2:String) -> Bool in return s1 > s2})println(reversed)// reversed is equal to ["Ewa", "Daniella", "Chris", "Barry", "Alex"]
也可以簡化為
let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"] var reversed = sort(names, { s1, s2 in s1 > s2 } ) println(reversed)
枚舉
通過下面的文法聲明
enum Barcode { case UPCA(Int, Int, Int) = (1,2,3) case QRCode(String) = "hello"}
類與結構體
推薦使用首字母大寫來命名
struct Resolution { var width = 0 var heigth = 0}class VideoMode { var resolution = Resolution() var interlaced = false var frameRate = 0.0 var name: String?}
產生執行個體:
let someResolution = Resolution()let someVideoMode = VideoMode()
屬性訪問與修改,使用.文法:
println("The width of someVideoMode is \(someVideoMode.resolution.width)")someVideoMode.resolution.width = 12880println("The width of someVideoMode is now \(someVideoMode.resolution.width)")
結構體有自動成員初始化器,類執行個體沒有:
let vga = resolution(width:640, heigth: 480)
結構體與枚舉都是實值型別,類是參考型別
對於引用了同一個執行個體的值,可以使用===和!==來進行判斷
延遲屬性,@lazy,設定在調用的時候才初始化特定的屬性
class DataImporter { /* DataImporter 是一個將外部檔案中的資料匯入的類。 這個類的初始化會消耗不少時間。 */ var fileName = "data.txt" // 這是提供資料匯入功能} class DataManager { @lazy var importer = DataImporter() var data = String[]() // 這是提供資料管理功能} let manager = DataManager()manager.data += "Some data"manager.data += "Some more data"// DataImporter 執行個體的 importer 屬性還沒有被建立
類、結構體、枚舉都可以通過設定setter與getter來
struct AlternativeRect { var origin = Point() var size = Size() var center: Point { get { let centerX = origin.x + (size.width / 2) let centerY = origin.y + (size.height / 2) return Point(x: centerX, y: centerY) } set { //這裡setter 沒有定義表示新值的參數名,則可以使用預設名稱newValue origin.x = newValue.x - (size.width / 2) origin.y = newValue.y - (size.height / 2) } }}
唯讀屬性去掉get與set
屬性監視可以使用willset和didset來處理
類型屬性有點像靜態變數,以static關鍵字聲明
struct SomeStructure { static var storedTypeProperty = "Some value." static var computedTypeProperty: Int { // 這裡返回一個 Int 值 }}
下標
類、結構體、枚舉都可以有下標,它有像給它們增加了一個捷徑,如下:
struct TimesTable { let multiplier: Int subscript(index: Int) -> Int { return multiplier * index }}let threeTimesTable = TimesTable(multiplier: 3)println("3的6倍是\(threeTimesTable[6])")// 輸出 "3的6倍是18"
繼承
定義一個類
class Vehicle { var numberOfWheels: Int var maxPassengers: Int func description() -> String { return "\(numberOfWheels) wheels; up to \(maxPassengers) passengers" } init() { numberOfWheels = 0 maxPassengers = 1 }}
繼承類
class Bicycle: Vehicle { init() { super.init() numberOfWheels = 2 }}
重寫屬性與方法
class Car: Vehicle { var speed: Double = 0.0 override var speed: Double { get { return super.speed } set { super.speed = min(newValue, 40.0) } } init() { super.init() maxPassengers = 5 numberOfWheels = 4 } override func description() -> String { return super.description() + "; " + "traveling at \(speed) mph" }}
防止重寫,在方法與屬性前加關鍵字@final,編譯時間會出錯
建構函式
聲明裡可以寫多個init,這有點像重載
struct Celsius { var temperatureInCelsius: Double = 0.0 init(fromFahrenheit fahrenheit: Double) { temperatureInCelsius = (fahrenheit - 32.0) / 1.8 } init(fromKelvin kelvin: Double) { temperatureInCelsius = kelvin - 273.15 }} let boilingPointOfWater = Celsius(fromFahrenheit: 212.0)// boilingPointOfWater.temperatureInCelsius 是 100.0let freezingPointOfWater = Celsius(fromKelvin: 273.15)// freezingPointOfWater.temperatureInCelsius 是 0.0”
類的析構
有些地方叫反初始化,很彆扭的名字哦
class Player { var coinsInPurse: Int init(coins: Int) { coinsInPurse = Bank.vendCoins(coins) } func winCoins(coins: Int) { coinsInPurse += Bank.vendCoins(coins) } deinit { Bank.receiveCoins(coinsInPurse) }} var player = Player(coins:200)player = nil //調用deinit方法
擴充
對於類、結構體、枚舉,可以擴充它們的一切
class Player{ var age:Int} extension Player{ func repetitions(task: () -> ()) { for i in 0..self { task() } }}
協議
其實就是介面描述
protocol SomeProtocol { var mustBeSettable: Int { get set } var doesNotNeedToBeSettable: Int { get } func someTypeMethod() }
協議繼承
protocol InheritingProtocol: SomeProtocol, AnotherProtocol { // protocol definition goes here }
泛型
這個函數的泛型版本使用了節點類型命名(通常此情況下用字母T來表示)來代替實際類型名(如Int、String或Double)。節點類型名並不是表示T必須是任何類型,但是其規定a和b必須是同一類型的T,而不管T表示任何類型。只有swapTwoValues函數在每次調用時所傳入的實際類型決定了T所代表的類型。
func swapTwoValues<T>(inout a: T, inout b: T) { let temporaryA = a a = b b = temporaryA }
運算子多載
這裡示範重載+號運算子
struct Vector2D { var x = 0.0, y = 0.0}@infix func + (left: Vector2D, right: Vector2D) -> Vector2D { return Vector2D(x: left.x + right.x, y: left.y + right.y)}
- 前置運算子 @prefix
- 後置運算子 @postfix
- 組合賦值運算子 @assignment
- 比較子 @infix
@prefix @assignment func ++ (inout vector: Vector2D) -> Vector2D { vector += Vector2D(x: 1.0, y: 1.0) return vector}
自訂運算子
個性的運算子只能使用這些字元 / = - + * % < >!& | ^。~
operator prefix +++ {}@prefix @assignment func +++ (inout vector: Vector2D) -> Vector2D { vector += vector return vector}
結合性(associativity)的值預設為none,可用left,right,none,優先順序(precedence)預設為100。
operator infix +- { associativity left precedence 140 }func +- (left: Vector2D, right: Vector2D) -> Vector2D { return Vector2D(x: left.x + right.x, y: left.y - right.y)}let firstVector = Vector2D(x: 1.0, y: 2.0)let secondVector = Vector2D(x: 3.0, y: 4.0)let plusMinusVector = firstVector +- secondVector// plusMinusVector 此時的值為 (4.0, -2.0)
來自:http://jser.me