A Swift Tour, 苹果新推出的开发语言
蘋果近日召開了全球開發(fā)者大會(WWDC),推出了一種新的開發(fā)語言 Swift,有人說是用來替代Objective-C的,以下是蘋果官方文檔,第一時間整理了一下,覺得還是很有前景的,有些英文看不懂的就直接復(fù)制了,接下來的時間還是要持續(xù)關(guān)注呢。
官方鏈接:
https://developer.apple.com/library/prerelease/ios/referencelibrary/GettingStarted/LandingPage/index.html#//apple_ref/doc/uid/TP40014345
https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/GuidedTour.html#//apple_ref/doc/uid/TP40014097-CH2-XID_1
簡介
Swift是iOS和OS X應(yīng)用編程的一種新的編程語言,基于C和Objective-C,卻沒有C的一些兼容約束。Swift采用了安全的編程模式和添加現(xiàn)代的功能來讓編程更加簡單、靈活和有趣。界面基于廣大人民群眾愛戴的Cocoa和Cocoa Touch框架,展示了軟件開發(fā)的新方向。
Swift已經(jīng)存在了多年。Apple基于已有的編譯器、調(diào)試器、框架作為其基礎(chǔ)架構(gòu)。通過ARC(Automatic Reference Counting,自動引用計數(shù))來簡化內(nèi)存管理。我們的框架棧則一直基于Cocoa。Objective-C進(jìn)化支持了塊、collection literal和模塊,允許現(xiàn)代語言的框架無需深入即可使用。
Objective-C開發(fā)者會感到Swift的似曾相識。Swift采用了Objective-C的命名參數(shù)和動態(tài)對象模型。提供了對Cocoa框架和mix-and-match的互操作性。基于這些基礎(chǔ),Swift引入了很多新功能和結(jié)合面向過程和面向?qū)ο蟮墓δ堋?br />
Swift對新的程序員也是友好的。他是工業(yè)級品質(zhì)的系統(tǒng)編程語言,卻又像腳本語言一樣的友好。他支持playground,允許程序員實(shí)驗編寫Swift代碼功能并立即看到結(jié)果,而無需麻煩的構(gòu)建和運(yùn)行一個應(yīng)用。
A Swift Tour
許多編程語言一開始都以hello world來開個好頭,用Swift來寫,只有一行:
println("Hello, world")如果你有C/C++,Objective-C的基礎(chǔ),看起來應(yīng)該會很熟悉,在Swift里,這一行就是一個完整的代碼了,不需要再引入其他的庫文件了,全局的代碼就已經(jīng)是程序的入口了,所以也不需main方法,甚至也不需要分號結(jié)尾
1.Simple Values(簡單值)
使用let定義常量,var定義變量,常量并不需編譯時制定,但至少需要賦值一次,意味著只需定義一次常量,就可在所有地方使用
var myVariable = 42 myVariable = 50 let myConstant = 42上面例子中,編譯自動推斷myVariable是個整數(shù)類型,不需要顯示聲明,在以后的賦值也要賦予相同的類型
如果在初始化的時候沒有提供足夠的信息或根本沒有初始化賦值,可以在后面聲明,用冒號分割
let implicitInteger = 70 let implicitDouble = 70.0 let explicitDouble: Double = 70已經(jīng)賦的值不會隱式轉(zhuǎn)換為其他類型,如果需要轉(zhuǎn)換為其他類型,需要明確寫出構(gòu)造所需類型的實(shí)例
let label = "The width is " let width = 94 let widthLabel = label + String(width)還有一種更簡單的寫法在字符串中顯示變量值,變量值寫入小括號中,并在前面添加反斜線 let apples = 3 let oranges = 5 let appleSummary = "I have \(apples)apples." let fruitSummary = "I have\(apples + oranges) pieces of fruit."用方括號[] 創(chuàng)建數(shù)據(jù)或字典,通過下標(biāo)或鍵值訪問元素
var shoppingList =["catfish", "water", "tulips", "bluepaint"] shoppingList[1] = "bottle ofwater"var occupations = ["Malcolm": "Captain","Kaylee": "Mechanic", ] occupations["Jayne"] ="Public Relations"如果想要創(chuàng)建一個空的數(shù)組或字典,使用初始化語句
let emptyArray = String[]() let emptyDictionary =Dictionary<String, Float>()如果不確定類型,可以直接寫成 [] 表示空數(shù)組,[:]表示空字典
shoppingList = [] //Went shopping and bought everything.
2.Control Flow(控制流)
使用if和switch作為條件控制,使用for-in,for,while和do-while來循環(huán),小括號不是必須的,但大括號是必須的
let individualScores = [75, 43, 103, 87, 12] var teamScore = 0 for score in individualScores {if score > 50 {teamScore += 3} else {teamScore += 1} } teamScore在if語句中,條件必須是布爾表達(dá)式,意味著 if score{…} 是錯誤的,不能隱式的與0比較
可以同時使用if和let來防止變量值的丟失,這些值是可選的,可選值可包含一個值或一個nil來指定值是否存在,類型后面的(?) 表示值是可選的
var optionalString: String? ="Hello" optionalString == nilvar optionalName: String? = "JohnAppleseed" var greeting = "Hello!" if let name = optionalName {greeting = "Hello, \(name)" }如果可選的值是nil,那么條件為false的語句將會跳過,Otherwise,the optional value is unwrapped and assigned to the constant after?let, which makes the unwrapped value available insidethe block of code.
?
switch支持多種數(shù)據(jù)以及多種比較,不局限于整數(shù)和測試數(shù)相等
let vegetable = "red pepper" switch vegetable { case "celery":let vegetableComment = "Add some raisins and make ants on alog." case "cucumber","watercress":let vegetableComment = "That would make a good tea sandwich." case let x wherex.hasSuffix("pepper"):let vegetableComment = "Is it a spicy \(x)?" default:let vegetableComment = "Everything tastes good in soup." }switch在匹配之后就會跳出程序塊,繼續(xù)執(zhí)行下一個邏輯代碼,而不需要break語句來跳出
?
使用for-in來遍歷字典中的每一個值,提供一對名稱來為每個鍵值對使用
let interestingNumbers = ["Prime": [2, 3, 5, 7, 11, 13],"Fibonacci": [1, 1, 2, 3, 5, 8],"Square": [1, 4, 9, 16, 25], ] var largest = 0 for (kind, numbers) ininterestingNumbers {for number in numbers {if number > largest {largest = number}} } largest使用while來重復(fù)執(zhí)行一代碼塊直到條件成立,循環(huán)的條件可放在while末尾來確保循環(huán)至少執(zhí)行一次
var n = 2 while n < 100 {n = n * 2 } nvar m = 2 do {m = m * 2 } while m < 100 m可在循環(huán)中定義一個索引,通過..來表示索引所表示的范圍,以下兩個例子做同樣的事情
var firstForLoop = 0 for i in 0..3 {firstForLoop += i } firstForLoopvar secondForLoop = 0 for var i = 0; i < 3; ++i {secondForLoop += 1 } secondForLoo使用 .. 構(gòu)建的范圍不包含最大值,使用 … 構(gòu)建的范圍大小值都包含
?
3.Functions and Closures(函數(shù)與閉包?)
使用func聲明一個函數(shù),調(diào)用函數(shù)的方法是使用函數(shù)名稱加括號里的參數(shù)列表,使用->分割參數(shù)名和返回的類型
func greet(name: String, day: String) -> String {return "Hello \(name), today is \(day)." } greet("Bob","Tuesday")使用tuple可以返回多個值
func getGasPrices() -> (Double,Double, Double) {return (3.59, 3.69, 3.79) } getGasPrices()函數(shù)參數(shù)個數(shù)可以不固定,用數(shù)組表示
func sumOf(numbers: Int...) -> Int {var sum = 0for number in numbers {sum += number}return sum } sumOf() sumOf(42, 597, 12)函數(shù)可以嵌套,內(nèi)嵌函數(shù)可訪問其定義所在函數(shù)的變量
func returnFifteen() -> Int {var y = 10func add() {y += 5}add()return y } returnFifteen()函數(shù)是第一類型的,意味著函數(shù)也可以返回另一個函數(shù)
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(numbers, lessThanTen)一個函數(shù)可以接收其他函數(shù)作為參數(shù)
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(numbers, lessThanTen)函數(shù)其實(shí)就是特殊形式的閉包,寫一個閉包不需要命名,只要加在大括號中,用in取參數(shù)和方法體的返回值
numbers.map({(number: Int) -> Int inlet result = 3 * numberreturn result })有很多種方式來寫一些更簡單的閉包,當(dāng)一個閉包的類型是已知的,比如說對委托的回調(diào),可以省略類型的參數(shù)和返回值,單一語句的閉包可以直接把值返回
numbers.map({ number in 3 * number })可以用數(shù)字取代名字來引用一個參數(shù),對短的閉包是很有用的,A closure passed as the last argument to a function can appearimmediately after the parentheses.
sort([1, 5, 3, 12, 2]) { $0 > $1 }
4.Objects and Classes(對象和類)
使用class 加類名來創(chuàng)建一個類,類中屬性的聲明和常量及變量的聲明是一樣的,除了這是在類的context中,方法和函數(shù)的聲明也是一樣的
class Shape {var numberOfSides = 0func simpleDescription() -> String {return "A shape with \(numberOfSides) sides."} }在類名的后面添加小括號來創(chuàng)建類的實(shí)例,使用點(diǎn)操作符訪問類的屬性和方法
var shape = Shape() shape.numberOfSides = 7 var shapeDescription =shape.simpleDescription()使用init來創(chuàng)建一個構(gòu)造器來在創(chuàng)建實(shí)例的時候初始化
class NamedShape {var numberOfSides: Int = 0var name: Stringinit(name: String) {self.name = name}func simpleDescription() -> String {return "A shape with \(numberOfSides) sides."} }Notice how self is used todistinguish the name property from the name argument to the initializer. Thearguments to the initializer are passed like a function call when you create aninstance of the class. Every property needs a value assigned—either in itsdeclaration (as with numberOfSides) or in the initializer (as with name).
如果需要在對象銷毀時進(jìn)行清理工作,使用deinit創(chuàng)建析構(gòu)器
子類包含其父類的名稱,以冒號分隔,在繼承標(biāo)準(zhǔn)子類時不需要聲明,所以可以根據(jù)需要包括或者忽略父類
子類的方法可通過override重載父類的方法,沒有的話會編譯錯誤,編譯器也會檢查那些沒有被重載的方法
class Square: NamedShape {var sideLength: Doubleinit(sideLength: Double, name: String) {self.sideLength = sideLengthsuper.init(name: name)numberOfSides = 4}func area() -> Double {return sideLength * sideLength}override func simpleDescription() -> String {return "A square with sides of length \(sideLength)."} } let test = Square(sideLength: 5.2,name: "my test square") test.area() test.simpleDescription()
在perimeter的setter方法中,新的值得命名就是newValue,可以在set之后提供一個不沖突的名稱
注意EquilateralTriangle類構(gòu)造有三個步驟:
1.????設(shè)置屬性的值
2.????調(diào)用父類的構(gòu)造器
3.????改變父類定義的值,Any additional setup work that uses methods, getters, or setters canalso be done at this point.
?
如果不需要計算屬性但卻需要賦值后才能繼續(xù)執(zhí)行,可以使用willSet和didSet,一下例子保證三角形的邊長等于矩形的邊長
class TriangleAndSquare {var triangle: EquilateralTriangle {willSet {square.sideLength = newValue.sideLength}}var square: Square {willSet {triangle.sideLength = newValue.sideLength}}init(size: Double, name: String) {square = Square(sideLength: size, name: name)triangle = EquilateralTriangle(sideLength: size, name: name)} } var triangleAndSquare =TriangleAndSquare(size: 10, name: "another test shape") triangleAndSquare.square.sideLength triangleAndSquare.triangle.sideLength triangleAndSquare.square =Square(sideLength: 50, name: "larger square") triangleAndSquare.triangle.sideLength函數(shù)和類的方法有一個不同點(diǎn),函數(shù)的參數(shù)名僅用于函數(shù),方法中的參數(shù)名也可以用來調(diào)用方法(除了第一個參數(shù)),缺省時,一個方法有一個同名的參數(shù),調(diào)用時就是使用參數(shù)本身,可以指定第二個名字,在方法內(nèi)部使用
class Counter {var count: Int = 0func incrementBy(amount: Int, numberOfTimes times: Int) {count += amount * times} } var counter = Counter() counter.incrementBy(2, numberOfTimes:7)當(dāng)使用可選值時,可以像方法屬性一樣在操作符前使用問號(?),如果值本來就是nil,那所有在?之后的代碼將會忽略,整個表達(dá)式都是nil,另外,可選值是unwrapped的,所有在?后的代碼都作為unwrapped值,在兩種情況下,真?zhèn)€表達(dá)式都是可選值
let optionalSquare: Square? =Square(sideLength: 2.5, name: "optional square") let sideLength =optionalSquare?.sideLength?
5.Enumerations and Structures(枚舉和結(jié)構(gòu))
使用enum來創(chuàng)建枚舉,跟類和其他命名一樣,枚舉也可以定義方法
enum Rank: Int {case Ace = 1case Two, Three, Four, Five, Six, Seven, Eight, Nine, Tencase Jack, Queen, Kingfunc simpleDescription() -> String {switch self {case .Ace:return "ace"case .Jack:return "jack"case .Queen:return "queen"case .King:return "king"default:return String(self.toRaw())}} } let ace = Rank.Ace let aceRawValue = ace.toRaw()以上例子中,初始值的枚舉類型為Int,那么只需要指定第一個初始值,其余的會自動分配,還可以使用字符串或浮點(diǎn)數(shù)作為初始值的枚舉。
?
使用toRaw和fromRaw函數(shù)可以轉(zhuǎn)換初始值和枚舉值
if let convertedRank = Rank.fromRaw(3){let threeDescription = convertedRank.simpleDescription() }枚舉中成員就是實(shí)際使用的值了,而不是其他方式寫的初始值,事實(shí)上,如果不提供第一個初始值的話,這種情況才是初始值
enum Suit {case Spades, Hearts, Diamonds, Clubsfunc simpleDescription() -> 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.simpleDescription()Notice the two ways that theHearts member of the enumeration is referred to above: When assigning a valueto the hearts constant, the enumeration member Suit.Hearts is referred to byits full name because the constant doesn’t have an explicit type specified.Inside the switch, the enumeration is referred to by the abbreviated form.Hearts because the value of self is already known to be a suit. You can usethe abbreviated form anytime the value’s type is already known.
?
使用struct來創(chuàng)建結(jié)構(gòu)體,結(jié)構(gòu)體支持多個與類相同的行為,包括方法和構(gòu)造器,區(qū)別是代碼之間總是使用拷貝(值傳遞),而類是傳遞引用
struct Card {var rank: Rankvar suit: Suitfunc simpleDescription() -> String {return "The \(rank.simpleDescription()) of\(suit.simpleDescription())"} } let threeOfSpades = Card(rank: .Three,suit: .Spades) let threeOfSpadesDescription =threeOfSpades.simpleDescription()一個枚舉的實(shí)例成員可以擁有實(shí)例的值。相同枚舉成員實(shí)例可以有不同的值。你在創(chuàng)建實(shí)例時賦值。指定值和原始值的區(qū)別:枚舉的原始值與其實(shí)例相同,你在定義枚舉時提供原始值。
例如,假設(shè)情況需要從服務(wù)器獲取太陽升起和降落時間。服務(wù)器可以響應(yīng)相同的信息或一些錯誤信息
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)." case let .Error(error):let serverResponse = "Failure... \(error)" }注意日出和日落時間實(shí)際上來自于對 ServerResponse 的部分匹配來選擇的
?
6.Protocols and Extensions(協(xié)議和擴(kuò)展)
使用protocol來聲明一個協(xié)議
protocol ExampleProtocol {var simpleDescription: String { get }mutating func adjust() }協(xié)議可以被類、枚舉和結(jié)構(gòu)使用
class SimpleClass: ExampleProtocol {var simpleDescription: String = "A very simple class."var anotherProperty: Int = 69105func adjust() {simpleDescription += " Now100% adjusted."} } var a = SimpleClass() a.adjust() let aDescription = a.simpleDescriptionstruct SimpleStructure: ExampleProtocol{var simpleDescription: String = "A simple structure"mutating func adjust() {simpleDescription += " (adjusted)"} } var b = SimpleStructure() b.adjust() let bDescription = b.simpleDescription注意,在SimpleStructure聲明中使用mutating關(guān)鍵字用于標(biāo)志這個方法的話會修改他的結(jié)構(gòu),而SimpleClass中并不需要設(shè)置mutaing標(biāo)志,因為類中的方法會修改這個類
?
使用extension去添加已有的類型,如新方法和計算值,可以使用extension,保證任意類型具有相同的協(xié)議,不管這個類型是從框架還是類庫中來的
extension Int: ExampleProtocol {var simpleDescription: String {return "The number \(self)"}mutating func adjust() {self += 42} } 7.simpleDescription可以像其他命令類型一樣使用協(xié)議命名,比如創(chuàng)建一個對象集合有不同的類型,但所有類型都符合同一個協(xié)議,當(dāng)使用一些協(xié)議類型的值時,在協(xié)議外部定義的方法是不可用的
let protocolValue: ExampleProtocol = a protocolValue.simpleDescription // protocolValue.anotherProperty // Uncomment to see the errorEven though the variableprotocolValue has a runtime type of SimpleClass, the compiler treats it as thegiven type of ExampleProtocol. This means that you can’t accidentally accessmethods or properties that the class implements in addition to its protocolconformance.
?
7.Generics(泛型)
在尖括號里的名字就定義了一個泛型的函數(shù)或類型
func repeat<ItemType>(item:ItemType, times: Int) -> ItemType[] {var result = ItemType[]()for i in 0..times {result += item}return result } repeat("knock", 4)泛型也可以用于函數(shù)和方法,類、枚舉及結(jié)構(gòu)
// Reimplement the Swift standardlibrary's optional type enum OptionalValue<T> {case Nonecase Some(T) } var possibleInteger:OptionalValue<Int> = .None possibleInteger = .Some(100)在類型后面使用where來指定一個需求列表,比如指定某個泛型必須實(shí)現(xiàn)某種協(xié)議,或要求兩種類型必須相同,或要求某個類必須具有一個父類
func anyCommonElements <T, U whereT: Sequence, U: Sequence, T.GeneratorType.Element: Equatable,T.GeneratorType.Element == U.GeneratorType.Element> (lhs: T, rhs: U) ->Bool {for lhsItem in lhs {for rhsItem in rhs {if lhsItem == rhsItem {return true}}}return false } anyCommonElements([1, 2, 3], [3])一般情況下可以忽略where,在括號后面寫一個協(xié)議名或泛型 Writing<T: Equatable> is the same as writing <T where T: Equatable>.
總結(jié)
以上是生活随笔為你收集整理的A Swift Tour, 苹果新推出的开发语言的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 简单的搜索方法
- 下一篇: 最近很多人问我:saiku下载不下来