1. 程式人生 > >[Swift之個唐巧的技術部落格]

[Swift之個唐巧的技術部落格]

  • 簡單值(Simple Values
  • 控制流(Control Flow
  • 函式和閉包(Functions and Closures
  • 物件和類(Objects and Classes
  • 列舉和結構體(Enumerations and Structures
  • 介面和擴充套件(Protocols and Extensions
  • 泛型(Generics
  • 簡單值
  • 使用let來宣告常量,使用var來宣告變數。
  • 使用方括號[]來建立陣列和字典,並使用下標或者鍵(key)來訪問元素。
  •     var shoppingList = ["catfish", "water", "tulips", "blue paint"]
  •     shoppingList[1] = "bottle of water"
  •     var occupations = [
  •         "Malcolm": "Captain",
  •         "Kaylee": "Mechanic",
  •     ]
  •     occupations["Jayne"] = "Public Relations"
  • 要建立一個空陣列或者字典,使用初始化語法。
  •     let emptyArray = String[]()
  •     let emptyDictionary = Dictionary<String, Float>()
  • 如果型別資訊可以被推斷出來,你可以用[]
    [:]來建立空陣列和空字典——就像你宣告變數或者給函式傳引數的時候一樣。
  •     shoppingList = []   // 去逛街並買點東西
  • 控制流
  • 使用ifswitch來進行條件操作,使用for-inforwhiledo-while來進行迴圈。包裹條件和迴圈變數括號可以省略,但是語句體的大括號是必須的。
  •     let individualScores = [75, 43, 103, 87, 12]
  •     var teamScore = 0
  •     for score in individualScores {
  •         if score > 50 {
  •             teamScore += 3
  •         } else {
  •             teamScore += 1
  •         }
  •     }
  •     teamScore
  • if語句中,條件必須是一個布林表示式——這意味著像if score { ... }這樣的程式碼將報錯,而不會隱形地與 0 做對比。
  • 你可以一起使用iflet來處理值缺失的情況。有些變數的值是可選的。一個可選的值可能是一個具體的值或者是nil,表示值缺失。在型別後面加一個問號來標記這個變數的值是可選的。
  •     var optionalString: String? = "Hello"
  •     optionalString == nil
  •     var optionalName: String? = "John Appleseed"
  •     var greeting = "Hello!"
  •     if let name = optionalName {
  •         greeting = "Hello, \(name)"
  •     }
  • 練習:
  • optionalName改成nilgreeting會是什麼?新增一個else語句,當optionalNamenil時給greeting賦一個不同的值。
  • 如果變數的可選值是nil,條件會判斷為false,大括號中的程式碼會被跳過。如果不是nil,會將值賦給let後面的常量,這樣程式碼塊中就可以使用這個值了。
  • switch支援任意型別的資料以及各種比較操作——不僅僅是整數以及測試相等。
  •     let vegetable = "red pepper"
  •     switch vegetable {
  •     case "celery":
  •         let vegetableComment = "Add some raisins and make ants on a log."
  •     case "cucumber", "watercress":
  •         let vegetableComment = "That would make a good tea sandwich."
  •     case let x where x.hasSuffix("pepper"):
  •         let vegetableComment = "Is it a spicy \(x)?"
  •     default:
  •         let vegetableComment = "Everything tastes good in soup."
  •     }
  • 練習:
  • 刪除default語句,看看會有什麼錯誤?
  • 執行switch中匹配到的子句之後,程式會退出switch語句,並不會繼續向下執行,所以不需要在每個子句結尾寫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) in interestingNumbers {
  •         for number in numbers {
  •             if number > largest {
  •                 largest = number
  •             }
  •         }
  •     }
  •     largest
  • 練習:
  • 新增另一個變數來記錄哪種型別的數字是最大的。
  • 使用while來重複執行一段程式碼直到不滿足條件。迴圈條件可以在開頭也可以在結尾。
  •     var n = 2
  •     while n < 100 {
  •         n = n * 2
  •     }
  •     n
  •     var m = 2
  •     do {
  •         m = m * 2
  •     } while m < 100
  •     m
  • 你可以在迴圈中使用..來表示範圍,也可以使用傳統的寫法,兩者是等價的:
  •     var firstForLoop = 0
  •     for i in 0..3 {
  •         firstForLoop += i
  •     }
  •     firstForLoop
  •     var secondForLoop = 0
  •     for var i = 0; i < 3; ++i {
  •         secondForLoop += 1
  •     }
  •     secondForLoop
  • 使用..建立的範圍不包含上界,如果想包含的話需要使用...
  • 函式和閉包
  • 使用func來宣告一個函式,使用名字和引數來呼叫函式。使用->來指定函式返回值。
  •     func greet(name: String, day: String) -> String {
  •         return "Hello \(name), today is \(day)."
  •     }
  •     greet("Bob", "Tuesday")
  • 練習:
  • 刪除day引數,新增一個引數來表示今天吃了什麼午飯。
  • 使用一個元組來返回多個值。
  •     func getGasPrices() -> (Double, Double, Double) {
  •         return (3.59, 3.69, 3.79)
  •     }
  •     getGasPrices()
  • 函式的引數數量是可變的,用一個數組來獲取它們:
  •     func sumOf(numbers: Int...) -> Int {
  •         var sum = 0
  •         for number in numbers {
  •             sum += number
  •         }
  •         return sum
  •     }
  •     sumOf()
  •     sumOf(42, 597, 12)
  • 練習:
  • 寫一個計算引數平均值的函式。
  • 函式可以巢狀。被巢狀的函式可以訪問外側函式的變數,你可以使用巢狀函式來重構一個太長或者太複雜的函式。
  •     func returnFifteen() -> Int {
  •         var y = 10
  •         func add() {
  •             y += 5
  •         }
  •         add()
  •         return y
  •     }
  •     returnFifteen()
  • 函式是第一等型別,這意味著函式可以作為另一個函式的返回值。
  •     func makeIncrementer() -> (Int -> Int) {
  •         func addOne(number: Int) -> Int {
  •             return 1 + number
  •         }
  •         return addOne
  •     }
  •     var increment = makeIncrementer()
  •     increment(7)
  • 函式也可以當做引數傳入另一個函式。
  •     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)
  • 函式實際上是一種特殊的閉包,你可以使用{}來建立一個匿名閉包。使用in將引數和返回值型別宣告與閉包函式體進行分離。
  •     numbers.map({
  •         (number: Int) -> Int in
  •         let result = 3 * number
  •         return result
  •         })
  • 練習:
  • 重寫閉包,對所有奇數返回 0.
  • 有很多種建立閉包的方法。如果一個閉包的型別已知,比如作為一個回撥函式,你可以忽略引數的型別和返回值。單個語句閉包會把它語句的值當做結果返回。
  •     numbers.map({ number in 3 * number })
  • 你可以通過引數位置而不是引數名字來引用引數——這個方法在非常短的閉包中非常有用。當一個閉包作為最後一個引數傳給一個函式的時候,它可以直接跟在括號後面。
  •     sort([1, 5, 3, 12, 2]) { $0 > $1 }
  • 物件和類
  • 使用class和類名來建立一個類。類中屬性的宣告和常量、變數宣告一樣,唯一的區別就是它們的上下文是類。同樣,方法和函式宣告也一樣。
  •     class Shape {
  •         var numberOfSides = 0
  •         func simpleDescription() -> String {
  •             return "A shape with \(numberOfSides) sides."
  •         }
  •     }
  • 練習:
  • 使用let新增一個常量屬性,再新增一個接收一個引數的方法。
  • 要建立一個類的例項,在類名後面加上括號。使用點語法來訪問例項的屬性和方法。
  •     var shape = Shape()
  •     shape.numberOfSides = 7
  •     var shapeDescription = shape.simpleDescription()
  • 這個版本的Shape類缺少了一些重要的東西:一個建構函式來初始化類例項。使用init來建立一個構造器。
  •     class NamedShape {
  •         var numberOfSides: Int = 0
  •         var name: String
  •         init(name: String) {
  •             self.name = name
  •         }
  •         func simpleDescription() -> String {
  •             return "A shape with \(numberOfSides) sides."
  •         }
  •     }
  • 注意self被用來區別例項變數。當你建立例項的時候,像傳入函式引數一樣給類傳入構造器的引數。每個屬性都需要賦值——無論是通過宣告(就像numberOfSides)還是通過構造器(就像name)。
  • 如果你需要在刪除物件之前進行一些清理工作,使用deinit建立一個解構函式。
  • 子類的定義方法是在它們的類名後面加上父類的名字,用冒號分割。建立類的時候並不需要一個標準的根類,所以你可以忽略父類。
  • 子類如果要重寫父類的方法的話,需要用override標記——如果沒有新增override就重寫父類方法的話編譯器會報錯。編譯器同樣會檢測override標記的方法是否確實在父類中。
  •     class Square: NamedShape {
  •         var sideLength: Double
  •         init(sideLength: Double, name: String) {
  •             self.sideLength = sideLength
  •             super.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()
  • 練習:
  • 建立NamedShape的另一個子類Circle,構造器接收兩個引數,一個是半徑一個是名稱,實現areadescribe方法。
  • 屬性可以有 getter setter 
  •     class EquilateralTriangle: NamedShape {
  •         var sideLength: Double = 0.0
  •         init(sideLength: Double, name: String) {
  •             self.sideLength = sideLength
  •             super.init(name: name)
  •             numberOfSides = 3
  •         }
  •         var perimeter: Double {
  •         get {
  •             return 3.0 * sideLength
  •         }
  •         set {
  •                     sideLength = newValue / 3.0
  •         }
  •         }
  •         override func simpleDescription() -> String {
  •             return "An equilateral triagle with sides of length \(sideLength)."
  •         }
  •     }
  •     var triangle = EquilateralTriangle(sideLength: 3.1, name: "a triangle")
  •     triangle.perimeter
  •     triangle.perimeter = 9.9
  •     triangle.sideLength
  • perimeter setter中,新值的名字是newValue。你可以在set之後顯式的設定一個名字。
  • 注意EquilateralTriangle類的構造器執行了三步:
  • 設定子類宣告的屬性值
  • 呼叫父類的構造器
  • 改變父類定義的屬性值。其他的工作比如呼叫方法、getterssetters也可以在這個階段完成。
  • 如果你不需要計算屬性但是需要在設定一個新值之前執行一些程式碼,使用willSetdidSet
  • 比如,下面的類確保三角形的邊長總是和正方形的邊長相同。
  •     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
  • 類中的方法和一般的函式有一個重要的區別,函式的引數名只在函式內部使用,但是方法的引數名需要在呼叫的時候顯式說明(除了第一個引數)。預設情況下,方法的引數名和它在方法內部的名字一樣,不過你也可以定義第二個名字,這個名字被用在方法內部。
  •     class Counter {
  •         var count: Int = 0
  •         func incrementBy(amount: Int, numberOfTimes times: Int) {
  •             count += amount * times
  •         }
  •     }
  •     var counter = Counter()
  •     counter.incrementBy(2, numberOfTimes: 7)
  • 處理變數的可選值時,你可以在操作(比如方法、屬性和子指令碼)之前加?。如果?之前的值是nil?後面的東西都會被忽略,並且整個表示式返回nil。否則,?之後的東西都會被執行。在這兩種情況下,整個表示式的值也是一個可選值。
  •     let optionalSquare: Square? = Square(sideLength: 2.5, name: "optional square")
  •     let sideLength = optionalSquare?.sideLength
  • 列舉和結構體
  • 使用enum來建立一個列舉。就像類和其他所有命名型別一樣,列舉可以包含方法。enum Rank: Int {
  •         case Ace = 1
  •         case Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten
  •         case Jack, Queen, King
  •         func 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()
  • 練習:
  • 寫一個函式,通過比較它們的原始值來比較兩個Rank值。
  • 在上面的例子中,列舉原始值的型別是Int,所以你只需要設定第一個原始值。剩下的原始值會按照順序賦值。你也可以使用字串或者浮點數作為列舉的原始值。
  • 使用toRawfromRaw函式來在原始值和列舉值之間進行轉換。
  •     if let convertedRank = Rank.fromRaw(3) {
  •         let threeDescription = convertedRank.simpleDescription()
  •     }
  • 列舉的成員值是實際值,並不是原始值的另一種表達方法。實際上,如果原始值沒有意義,你不需要設定。
  •     enum Suit {
  •         case Spades, Hearts, Diamonds, Clubs
  •         func 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()
  • 練習:
  • Suit新增一個color方法,對spadesclubs返回“black”,對heartsdiamonds返回“red”
  • 注意,有兩種方式可以引用Hearts成員:給hearts常量賦值時,列舉成員Suit.Hearts需要用全名來引用,因為常量沒有顯式指定型別。在switch裡,列舉成員使用縮寫.Hearts來引用,因為self的值已經知道是一個suit。已知變數型別的情況下你可以使用縮寫。
  • 使用struct來建立一個結構體。結構體和類有很多相同的地方,比如方法和構造器。它們之間最大的一個區別就是結構體是傳值,類是傳引用。
  •     struct Card {
  •         var rank: Rank
  •         var suit: Suit
  •         func simpleDescription() -> String {
  •             return "The \(rank.simpleDescription()) of \
  •             (suit.simpleDescription())"
  •         }
  •     }
  •     let threeOfSpades = Card(rank: .Three, suit: .Spades)
  •     let threeOfSpadesDescription = threeOfSpades.simpleDescription()
  • 練習:
  • Card新增一個方法,建立一副完整的撲克牌並把每張牌的 rank suit 對應起來。
  • 一個列舉成員的例項可以有例項值。相同列舉成員的例項可以有不同的值。建立例項的時候傳入值即可。例項值和原始值是不同的:列舉成員的原始值對於所有例項都是相同的,而且你是在定義列舉的時候設定原始值。
  • 例如,考慮從伺服器獲取日出和日落的時間。伺服器會返回正常結果或者錯誤資訊。
  •     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)"
  • 相關推薦

    Swift技術部落

    簡單值(Simple Values) 控制流(Control Flow) 函式和閉包(Functions and Closures) 物件和類(Objects and Classes) 列舉和結構體(Enumerations and Structures) 介面和擴充套件(Protocols and Ext

    使用CocoaPods做依賴管理(淘寶源更換為HTTPS)--轉自 技術部落

    CocoaPods 簡介 每種語言發展到一個階段,就會出現相應的依賴管理工具,例如 Java 語言的 Maven,nodejs 的 npm。隨著 iOS 開發者的增多,業界也出現了為 iOS 程式提供依賴管理的工具,它的名字叫做:CocoaPods。 CocoaPod

    推薦20優秀企業技術部落

    想獲得第一手的新聞線索但無從下手?想確認最準確的行業動態但找不到來源?InfoQ編輯們的日常工作就是在第一時間內搜尋、更新來自四面八方的新聞線索,收集最有價值的新聞資訊。現在,向大家推薦InfoQ編輯們最常去的20個優秀知名企業技術部落格,如果您對行業內最新技術

    iOS移動開發週報——技術部落

    TNND,全是轉載的文章,好羞澀,終於有一篇原創的了。 這個大牛的技術部落格值得一看,關於iOS開發的動態,也有寫技術部落格 http://blog.devtang.com/blog/categories/ios/ (這也能算原創~~)

    黑馬程式設計師技術部落哲學家吃飯問題

    ----------- android培訓、java培訓、java學習型技術部落格、期待與您交流! ------------ 哲學家就餐:有五個哲學家繞著圓桌坐,每個哲學家面前有一碗麵,兩人之間有一支筷子,這樣每個哲學家左右各有一支筷子。哲學家有2個狀態,思考或者拿起筷子吃

    西濤offbye-移動全棧技術部落(關於移動端架構和全棧開發,Android, HTML5,Swift,前端,人工智慧,技術管理等)

    Hybrid HTML5跨平臺移動應用開發技術 Hybrid HTML5跨平臺移動應用開發技術,使用AngularJS,ionic Framework,PhoneGap開發跨平臺移動應用,技術和經驗分享。本專欄每月更新4篇以上

    《大資料Spark企業級實戰版》pdf附網盤連結+30總結JVM虛擬機器深度好文技術部落(收藏版)

    技術書閱讀方法論 一.速讀一遍(最好在1~2天內完成) 人的大腦記憶力有限,在一天內快速看完一本書會在大腦裡留下深刻印象,對於之後複習以及總結都會有特別好的作用。 對於每一章的知識,先閱讀標題,弄懂大概講的是什麼主題,再去快速看一遍,不懂也沒有關係,但是一定要在不懂的

    國內各大網際網路公司相關技術部落3.0版 (集合騰訊、阿里、百度、搜狐、新浪、網易、360等共29

    近日重新整理了一番,希望能對大家有所幫助 2013年 騰訊系列(13)  阿里系列(18)  百度系列(3)  搜狐系列(3)  新浪系列(2)  360系列(2)   其他(9) 2016年 騰訊系列(9)  阿里系列(5)  百度系列(6)  搜狐系列(1)

    重新開始自己的技術部落

    歡迎交流 E-mail:ce123#126.com(#->@) QQ:350725201 嵌入式開發交流群: (1)280352802(已滿) (2)289195589 宣告:版權所有,歡迎轉載! 轉載請註明出處:http://blog.csdn.net/ce123

    這是三篇影響百度17年的技術部落,作者李彥巨集

    來源 | DoNews 作者 | 李彥巨集 我與GO.COM 本文寫於2001年2月3日。         雖然早已是預料之中的事,但得知GO.COM關閉的訊息時,還是有些傷感,畢竟我為她和她的前身

    技術部落的太監

    大多數小說,部落格,網站,主頁 最後都逃脫不了一種命運。 寫著寫著就沒有下面了。 這是很多網站的常態,為什麼? 因為一切最終的結局都是歸於平靜。 小說寫的自己編不下去就棄更了, 部落格沒流量沒動力也沒精力維護了, 網站伺服器費用交不起沒備案被404了, 發的說說0贊0評沒朋友純屬自嗨也就放棄了。 所以太監是整

    我從寫技術部落中收穫到了什麼?- J_Knight_

    我是 J_Knight_,熟悉我的人都應該知道我是一名剛工作滿3年的非科班 iOS 開發者,而且一直堅持寫技術部落格快有2年半的時間了。 其實從去年開始就一直想分享我寫部落格的心得,但是一直也沒有找到合適的契機,剛好在今年年底前達成了掘金粉絲量過萬的小目標,索性就藉著這個機會分享一下我自己關於寫部落格的一些

    為什麼要寫技術部落

                                前言            

    技術部落的無限好處

    沒有讀者,寫技術部落格文章感覺不到太多的作用,是浪費時間的事情,是這樣嗎? 不是。 釋出有關軟體技術的部落格將帶來數以千計的美元,儘管沒有人曾讀您的部落格。閒話少敘,首先,讀者可能是寫部落格的目標,但他們實際上是自然的結果。一路上還有很多其他的個人利益,包括更好的工

    如何寫一篇好的技術部落

    在工作過程中,發現對很多東西都一知半解,不是很透澈,到頭來很容易模糊,如果有一篇好的技術部落格予以總結,一來即使忘記了,回國頭來再看,仍然能夠從自己的思路中恢復;二來總結一下,還會發現一些潛在問題;三來,有利於大家交流技術。很多大公司都有自己的內部技術部落格平臺,寫

    在windows下進行 linux 開發 (轉載第七星塵的技術部落

    1,介紹Vagrant 我們做web開發的時候經常要安裝各種本地測試環境,比如apache,php,mysql,redis等等。出於個人使用習慣,可能我們還是比較習慣用windows。雖然說在windows下搭建各種開發環境是可行的,各大開發環境都有windows版本。然而在windows下配置有時候會顯

    【天山雪的技術部落格】漢家煙塵在東北,漢將辭家破殘賊。男兒本自重橫行,天子非常賜顏色。摐金伐鼓下榆關,旌旆逶迤碣石間。校尉羽書飛瀚海,單于獵火照狼山。山川蕭條極邊土,胡騎憑陵雜風雨。戰士軍前半死生,美人帳下猶歌舞。大漠窮秋塞草腓,孤城落日鬥兵稀。身當恩遇恆輕

    漢家煙塵在東北,漢將辭家破殘賊。男兒本自重橫行,天子非常賜顏色。摐金伐鼓下榆關,旌旆逶迤碣石間。校尉羽書飛瀚海,單于獵火照狼山。山川蕭條極邊土,胡騎憑陵雜風雨。戰士軍前半死生,美人帳下猶歌舞。大漠窮秋...

    挨踢人,自由軟體開發者Tiandi的技術部落

    最近正好有用excel的做些統計的東西,vba的一些用法又從新的review了一下,在此記錄一下: 1. 函式返回 VBA的函式返回通過一個和函式名的相同的變數進行返回,而不用寫return xxx ret = myfunction... 非技術

    長期閱讀英文技術部落的好處

    最近突然決定要好好學習下自己的英語,所以蒐集下相關文章,摘錄一些準備實踐的觀點: 有人可能覺得學英語聽地道的美式、英式英語是最佳的。但是我覺得非常有必要接觸不同的方言口音。聽一些較歪的口音反而有利於提高我的耳朵對英語聲音的辨別能力。我現在的直接主管是一個法國人,他講話時他把pattern說的像button

    麥克周的技術部落(微訊號:michael_tec),保持軟體工匠心態

    清空Shared pool: alter system flush shared_pool; 但為了整個記憶體的清空,只好將整個Oracle RAC環境的例項和資料庫都關機,再重新啟動。 可以採用清空buffer cache的方式來做: alter system flush