翻譯Raywenderlich 最新文章What’s New in Swift 4?

Swift學(xué)習(xí)有問必答群 : 313838956 ( mac版QQ有權(quán)限要求, 入群只能通過手機版 QQ申請). 本群由Guards翻譯組創(chuàng)建并維護(hù)
入群須知:

0.0 重申: mac版QQ有權(quán)限要求, 入群只能通過手機版 QQ申請.
0.1 群主晚上每天20點--21點定時回答Swift相關(guān)的問題.
0.2 群主會在看到問題后, 第一時間回復(fù)
0.3 拒絕長時間潛水, 拒絕討論和Swift , iOS 無關(guān)的問題



該文章轉(zhuǎn)載翻譯自: Raywenderlich
原文鏈接: What’s New in Swift 4?

譯者心聲

我們會不定期的更新翻譯文章, 需要可以關(guān)注我們的簡書

我們是一群熱愛翻譯并且熱愛 Swift 的人杆逗, 希望通過自己的努力讓不熟悉英語的程序員也能學(xué)習(xí)到國外的高質(zhì)量的文章. 如發(fā)現(xiàn)文章中翻譯錯誤之處, 煩請跟我們聯(lián)系, 我們第一時間更正.

想成為我們中一員? 是的, 我們正在招募對翻譯感興趣的小伙伴, 如果你想提高閱讀英語文檔的水平, 如果你不甘寂寞, 如果你想為廣大開發(fā)者做點事. QQ: 869293399

Swift 4是蘋果計劃在2017年秋季推出的最新版本煮甥,值得關(guān)注的是其提供了與Swift 3代碼很好的兼容性易猫,并最大限度的保持了ABI穩(wěn)定性.

本文著重介紹Swift中可能會明顯影響你的代碼的變化俯逾。ok,我們開始吧班缰!

導(dǎo)讀

Xcode9中已經(jīng)集成了Swift4, 你可以從developer portal下載最新版本的Xcode9 (需要開發(fā)者賬號), 每個Xcode beta 都會在發(fā)布時綁定最新的Swift 4快照版本勋磕。

在閱讀時,你會注意到[SE-xxxx]格式的鏈接犀概。這些鏈將帶你進(jìn)入相關(guān)的Swift Evolution提案立哑。如果你想了解更多話題,請務(wù)必查看阱冶。

我建議你在 Playground上嘗試每個 Swift 4的功能或更新刁憋。這將有助于鞏固你的知識,并使你能夠深入并了解每個主題, 試著擴展這些例子!

注意:本文將針對每個Xcode測試版進(jìn)行更新木蹬。如果你使用不同的Swift快照版本至耻,這里的代碼不能保證都有效若皱。

遷移到Swift 4

Swift 3遷移到4從2.2到3少了很多麻煩。一般來說尘颓,多數(shù)變化都是附加的走触,不需要個人大量去修改。正因為如此疤苹,Swift遷移工具可以處理你代碼的大部分變化互广。

Xcode 9同時支持Swift 4和Swift 3.2的中間版本。項目中的每個target可以是Swift3.2或Swift 4卧土,如果需要惫皱,可以只遷移部分。然而, 遷移到Swift3.2并非完全不受限制, 你可能需要更新部分代碼才能與新SDK兼容尤莺,且由于Swift ABI尚未穩(wěn)定旅敷,因此你需要使用Xcode 9重新編譯依賴項。

遷移到Swift 4颤霎,Xcode還提供了一個遷移工具來幫助你媳谁。在Xcode中,你可以點擊導(dǎo)航欄的 Edit/Convert/To Current Swift Syntax… 來啟動轉(zhuǎn)換工具友酱。

在選擇要轉(zhuǎn)換的target后晴音,Xcode會提示你優(yōu)先考慮Objective - C推斷的方式。 選擇推薦的選項缔杉,通過限制推斷來減少二進(jìn)制大小(關(guān)于這個主題的更多信息锤躁,參閱Limiting @objc Inference

1.png

API 變化

為了更好地理解你代碼中的變化,我們首先介紹Swift 4中變更的API

Strings

String在Swift 4中獲得了很多人的喜愛壮吩。 [SE-0163] 這個提案包含很多變化进苍,我們提取出最大的變化的.

字符串已經(jīng)像之前的2.0版一樣, 改為了Collection類型 加缘。此變化消除了字符串對字符數(shù)組的依賴⊙夹穑現(xiàn)在可以直接遍歷字符串對象:

  let galaxy = "Milky Way ??"
      for char in galaxy {
          print(char)
      }

你不僅可以通過字符串進(jìn)行邏輯迭代,還可以從SequenceCollection中獲取所有的bells and whistles :

  galaxy.count       // 11
  galaxy.isEmpty     // false
  galaxy.dropFirst() // "ilky Way ??"
  String(galaxy.reversed()) // "?? yaW ykliM"
  
  // Filter out any none ASCII characters
  galaxy.filter { char in
      let isASCII = char.unicodeScalars.reduce(true, { $0 && $1.isASCII })
      return isASCII
  } // "Milky Way "

上面的ASCII示例演示了對字符的一小部分改進(jìn)拣宏。你現(xiàn)在可以直接從字符訪問UnicodeScalarView沈贝。在這之前,你需要實例化一個新字符串[SE - 0178]勋乾。

另外還有一個StringProtocol宋下。它聲明了在String上聲明的大部分方法。為了改進(jìn)slice字符串的效率, Swift 4添加了Substring類型辑莫,用于引用String的子序列学歧。

StringSubstring都實現(xiàn)了StringProtocol,兩者幾乎具有相同的功能:

   // Grab a subsequence of String
   let endIndex = galaxy.index(galaxy.startIndex, offsetBy: 3)
   var milkSubstring = galaxy[galaxy.startIndex...endIndex]   // "Milk"
   type(of: milkSubstring)   // Substring.Type

   // Concatenate a String onto a Substring
   milkSubstring += ""     // "Milk"

   // Create a String from a Substring
   let milkString = String(milkSubstring) // "Milk"

另一個很大的改進(jìn)是String對圖形集合的解析各吨。這個處理方案來自于 Unicode 9的改編枝笨。以前,由多個代碼點組成的unicode字符會導(dǎo)致計數(shù)大于1。
常見的情況是横浑,這是一個帶有選擇的膚色的表情符號剔桨。以下是一個例子:

    "?????".count // Now: 1, Before: 2
    "????".count // Now: 1, Before: 2
    "???????????".count // Now: 1, Before, 3

這只是 String Manifesto 中提到的一個子集, 至于為何這么修改, 可以閱讀你感興趣的修改原始動機和方案。

Dictionary and Set

至于Collection類型徙融,SetDictionary并不那么最直觀的洒缀。幸運的是,Swift 團(tuán)隊對兩者做了很好的改進(jìn) [SE-0165]

Sequence Based Initialization

首先列表可以是從一系列鍵值對(元組)創(chuàng)建一個字典:

 let nearestStarNames = ["Proxima Centauri", "Alpha Centauri A", "Alpha Centauri B", "Barnard's Star", "Wolf 359"]
 let nearestStarDistances = [4.24, 4.37, 4.37, 5.96, 7.78]
 
 // Dictionary from sequence of keys-values
 let starDistanceDict = Dictionary(uniqueKeysWithValues: zip(nearestStarNames, nearestStarDistances)) 
// ["Wolf 359": 7.78, "Alpha Centauri B": 4.37, "Proxima Centauri": 4.24, "Alpha Centauri A": 4.37, "Barnard's Star": 5.96]

Duplicate Key Resolution

在初始化Dictionary時, 你現(xiàn)在可以使用你喜歡的方式來處理重復(fù)的鍵,同時避免覆蓋鍵值對欺冀,且不會出現(xiàn)任何問題:

   // Random vote of people's favorite stars
  let favoriteStarVotes = ["Alpha Centauri A", "Wolf 359", "Alpha Centauri A", "Barnard's Star"]

  // Merging keys with closure for conflicts
 let mergedKeysAndValues = Dictionary(zip(favoriteStarVotes, repeatElement(1, count: favoriteStarVotes.count)), uniquingKeysWith: +) // ["Barnard's Star": 1, "Alpha Centauri A": 2, "Wolf 359": 1]

上面的代碼使用了 zip+ 來快捷地處理重復(fù)的 key 和沖突的值树绩。

注意:如果你不熟悉 zip,你可以在Apple的Swift文檔中快速了解它 [Swift Documentation]
Filtering

Dictionary 和 Set現(xiàn)在都可以將結(jié)果 通過filter函數(shù) 過濾到原始類型的新對象中:

    // Filtering results into dictionary rather than array of tuples
 let closeStars = starDistanceDict.filter { $0.value < 5.0 }

 closeStars // Dictionary: ["Proxima Centauri": 4.24, "Alpha Centauri A": 4.37, "Alpha Centauri B": 4.37]
Dictionary Mapping

Dictionary為直接映射其值提供了一種非常有用的方法::

  // Mapping values directly resulting in a dictionary
  let mappedCloseStars = closeStars.mapValues { "\($0)" }

  mappedCloseStars // ["Proxima Centauri": "4.24", "Alpha Centauri A": "4.37", "Alpha Centauri B": "4.37"]
Dictionary Default Values

在Dictionary上訪問某個值時隐轩,常見的做法是使用nil-coalescing operator給出默認(rèn)值(譯者注: 不了解nil-coalescing operator 的伙伴 可參見Nil-Coalescing Operator葱峡。Dictionary Default Values可以更簡潔:

   // Subscript with a default value
  let siriusDistance = mappedCloseStars["Wolf 359", default: "unknown"] // "unknown"

   // Subscript with a default value used for mutating
   var starWordsCount: [String: Int] = [:]
   for starName in nearestStarNames {
        let numWords = starName.split(separator: " ").count
        starWordsCount[starName, default: 0] += numWords // Amazing 
    }
  starWordsCount // ["Wolf 359": 2, "Alpha Centauri B": 3, "Proxima Centauri": 2, "Alpha Centauri A": 3, "Barnard's Star": 2]

swift4之前, 處理這種情況需要包裝在臃腫的if - let語句中。現(xiàn)在簡短的代碼即可.

Dictionary Grouping

另一個令人驚訝稱贊的是龙助,我們可以從Sequence"中初始化Dictionary砰奕,并將其分組為bucket::

 // Grouping sequences by computed key
 let starsByFirstLetter = Dictionary(grouping: nearestStarNames) { $0.first! }

 // ["B": ["Barnard's Star"], "A": ["Alpha Centauri A", "Alpha Centauri B"], "W": ["Wolf 359"], "P": ["Proxima Centauri"]]

當(dāng)通過特定模式對數(shù)據(jù)進(jìn)行分組時,這相當(dāng)方便提鸟。

預(yù)留空間

SequenceDictionary現(xiàn)在都具有明確保留容量的能力军援。

    // Improved Set/Dictionary capacity reservation
    starWordsCount.capacity  // 6
    starWordsCount.reserveCapacity(20) // reserves at _least_ 20 elements of capacity
    starWordsCount.capacity // 24

在這些類型上,Reallocation可能是一項代價高昂的任務(wù)称勋。如果你知道需要存儲的數(shù)據(jù)量時, 使用reserveCapacity(_:)可以提高性能且便捷

私有訪問修飾符

Swift3中,有些人不太喜歡使用fileprivate胸哥。理論上它很強大,但在實踐中赡鲜,它的用法常令人困惑空厌。其目的是在成員內(nèi)部實現(xiàn)私有,不同一文件中银酬,訪問公有成員變量的時候很少使用fileprivate嘲更。

問題是Swift鼓勵使用extension將代碼分解成邏輯組。extension 代碼在原始作用域之外揩瞪,所以fileprivate也被廣泛使用赋朦。

Swift 4通過在類型和類型的extension間, 實現(xiàn)共享相同的訪問范圍。但這只適用于相同的源文件

    struct SpaceCraft {
        private let warpCode: String

        init(warpCode: String) {
            self.warpCode = warpCode
        }
    }

    extension SpaceCraft {
    func goToWarpSpeed(warpCode: String) {
        if warpCode == self.warpCode { // Error in Swift 3 unless warpCode is fileprivate
                print("Do it Scotty!")
            }
        }
    }

    let enterprise = SpaceCraft(warpCode: "KirkIsCool")
    //enterprise.warpCode  // error: 'warpCode' is inaccessible due to 'private' protection level
    enterprise.goToWarpSpeed(warpCode: "KirkIsCool") // "Do it Scotty!"
                                                       

新增API

現(xiàn)在讓我們來看看Swift 4的新特性李破。這些更改不應(yīng)該破壞現(xiàn)有的代碼宠哄,因為它們只是附加的。

存檔和序列化

目前為止嗤攻,要序列化和歸檔你的自定義類型毛嫉,你必須跳過一些坑。對于類類型妇菱,你需要將NSObject子類化并實現(xiàn)NSCoding協(xié)議承粤。像structenum這樣的值類型需要一些技巧惊畏,例如創(chuàng)建一個可以擴展NSObjectNSCoding的子對象。
Swift 4解決了這一問題密任,三種類型均可以序列化 [SE-0166]:

struct CuriosityLog: Codable {
  enum Discovery: String, Codable {
    case rock, water, martian
  }

  var sol: Int
  var discoveries: [Discovery]
}

// Create a log entry for Mars sol 42
let logSol42 = CuriosityLog(sol: 42, discoveries: [.rock, .rock, .rock, .rock])

在這個示例中颜启,你可以看到,要使swift類型 EncodableDecodable浪讳,惟一的要求是實現(xiàn)Codable的協(xié)議缰盏。如果所有的屬性都是Codable的,編譯器自動生成該協(xié)議的相應(yīng)實現(xiàn)

要真正對對象進(jìn)行編碼淹遵,需要將其傳遞給Encoder口猜。 每個編碼器根據(jù)不同的方案對你的對象進(jìn)行編碼 [SE-0167](Note: 部分提議仍在完善中):

let jsonEncoder = JSONEncoder() // One currently available encoder

 // Encode the data
 let jsonData = try jsonEncoder.encode(logSol42)
 // Create a String from the data
 let jsonString = String(data: jsonData, encoding: .utf8) // " {"sol":42,"discoveries":["rock","rock","rock","rock"]}"

它將一個對象自動編碼為JSON對象。一定要檢查JSONEncoder公開的屬性透揣,以定制它的輸出济炎。
該過程的最后一部分是將數(shù)據(jù)解碼為具體對象:

let jsonDecoder = JSONDecoder() // Pair decoder to JSONEncoder

// Attempt to decode the data to a CuriosityLog object
let decodedLog = try jsonDecoder.decode(CuriosityLog.self, from: jsonData)
decodedLog.sol         // 42
decodedLog.discoveries // [rock, rock, rock, rock]

使用Swift 4的 encoding/decoding,你可以在不依賴@ objc協(xié)議的開銷和限制的情況下獲得Swift的類型安全性辐真。

鍵值編碼

到目前為止须尚,你可以在不調(diào)用函數(shù)的情況下對函數(shù)進(jìn)行引用,因為在Swift中函數(shù)實質(zhì)是一個閉包侍咱。對于Swift 4, 可以引用類型的keyPath來獲取或設(shè)置實例的底層值 [SE-0161]:

struct Lightsaber {
  enum Color {
    case blue, green, red
  }
  let color: Color
}

class ForceUser {
  var name: String
  var lightsaber: Lightsaber
  var master: ForceUser?

  init(name: String, lightsaber: Lightsaber, master: ForceUser? = nil) {
    self.name = name
    self.lightsaber = lightsaber
    self.master = master
  }
}

let sidious = ForceUser(name: "Darth Sidious", lightsaber: Lightsaber(color: .red))
let obiwan = ForceUser(name: "Obi-Wan Kenobi", lightsaber: Lightsaber(color: .blue))
let anakin = ForceUser(name: "Anakin Skywalker", lightsaber: Lightsaber(color: .blue), master: obiwan)

在這里耐床,你創(chuàng)建了一些ForceUser實例,通過設(shè)置他們的name楔脯、lightsaber和master撩轰。要創(chuàng)建一個關(guān)鍵路徑,你只需使用一個反斜杠\昧廷,后面跟上你感興趣的屬性:

// Create reference to the ForceUser.name key path
let nameKeyPath = \ForceUser.name

// Access the value from key path on instance
let obiwanName = obiwan[keyPath: nameKeyPath]  // "Obi-Wan Kenobi"

在這個實例中堪嫂,你給ForceUser的name屬性創(chuàng)建了一個keyPath。然后木柬,你可以傳遞給新的subscript keyPath來使用這個keyPath〗源現(xiàn)在,默認(rèn)情況下弄诲,此下標(biāo)現(xiàn)在可用于每種類型
下面是一些使用keyPath來深入到子對象愚战、設(shè)置屬性和構(gòu)建keyPath引用的例子:

// Use keypath directly inline and to drill down to sub objects
let anakinSaberColor = anakin[keyPath: \ForceUser.lightsaber.color]  // blue

// Access a property on the object returned by key path
let masterKeyPath = \ForceUser.master
let anakinMasterName = anakin[keyPath: masterKeyPath]?.name  // "Obi-Wan Kenobi"

// Change Anakin to the dark side using key path as a setter
anakin[keyPath: masterKeyPath] = sidious
anakin.master?.name // Darth Sidious

// Note: not currently working, but works in some situations
// Append a key path to an existing path
//let masterNameKeyPath = masterKeyPath.appending(path: \ForceUser.name)
//anakin[keyPath: masterKeyPath] // "Darth Sidious"

Swift的keyPath之美是強類型的! 沒有更多的objective - c字符串混亂風(fēng)格!

多行String

多行String是很多編程語言非常常見的特性。Swift4添加了這個非常簡單和有用的語法是通過三個引號來實現(xiàn)的 [SE-0168]:

let star = "??"
let introString = """
  A long time ago in a galaxy far,
  far away....

  You could write multi-lined strings
  without "escaping" single quotes.

  The indentation of the closing quotes
       below deside where the text line
  begins.

  You can even dynamically add values
  from properties: \(star)
  """
print(introString) // prints the string exactly as written above with the value of star

當(dāng)創(chuàng)建XML/JSON消息的時候或者創(chuàng)建UI界面上非常長的格式化字符串的時候這是非常有用的齐遵。

半開區(qū)間

為了減少冗長和提高可讀性,標(biāo)準(zhǔn)庫現(xiàn)在可以推導(dǎo)出開始和結(jié)束使用半開區(qū)間塔插。 [SE-0172]

這為確定集合的范圍的起始索引或者結(jié)束索引提供了非常便利的方法梗摇。

// Collection Subscript
var planets = ["Mercury", "Venus", "Earth", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune"]
let outsideAsteroidBelt = planets[4...] // Before: planets[4..<planets.endIndex]
let firstThree = planets[..<4]          // Before: planets[planets.startIndex..<4]

正如你所看到的,半開區(qū)間減少了明確的開始或者結(jié)束索引想许。

無窮大

他們也允許在開始索引確定的情況下定義無窮的的結(jié)束索引伶授。


// Infinite range: 1...infinity
var numberedPlanets = Array(zip(1..., planets))
print(numberedPlanets) // [(1, "Mercury"), (2, "Venus"), ..., (8, "Neptune")]

planets.append("Pluto")
numberedPlanets = Array(zip(1..., planets))
print(numberedPlanets) // [(1, "Mercury"), (2, "Venus"), ..., (9, “Pluto")]

模式匹配

另一個非常大的作用是將半開區(qū)間用于模式匹配:


// Pattern matching

func temperature(planetNumber: Int) {
  switch planetNumber {
  case ...2: // anything less than or equal to 2
    print("Too hot")
  case 4...: // anything greater than or equal to 4
    print("Too cold")
  default:
    print("Justtttt right")
  }
}

temperature(planetNumber: 3) // Earth

泛型下標(biāo)

下標(biāo)是高效訪問數(shù)據(jù)類型的方式, 為了提高通用性 添加了泛型断序。[SE-0148]

struct GenericDictionary<Key: Hashable, Value> {
  private var data: [Key: Value]

  init(data: [Key: Value]) {
    self.data = data
  }

  subscript<T>(key: Key) -> T? {
    return data[key] as? T
  }
}

在上面這個例子中,返回值類型是泛型糜烹。你可以使用泛型下標(biāo)就像這樣:

// Dictionary of type: [String: Any]
var earthData = GenericDictionary(data: ["name": "Earth", "population": 7500000000, "moons": 1])

// Automatically infers return type without "as? String"
let name: String? = earthData["name"]

// Automatically infers return type without "as? Int"
let population: Int? = earthData["population"]

不僅僅只是返回值類型可以是泛型违诗,實際下標(biāo)類型也可以是泛型:

extension GenericDictionary {
  subscript<Keys: Sequence>(keys: Keys) -> [Value] where Keys.Iterator.Element == Key {
    var values: [Value] = []
    for key in keys {
      if let value = data[key] {
        values.append(value)
      }
    }
    return values
  }
}

// Array subscript value
let nameAndMoons = earthData[["moons", "name"]]        // [1, "Earth"]
// Set subscript value
let nameAndMoons2 = earthData[Set(["moons", "name"])]  // [1, "Earth"]

在這個例子中,你可以看到疮蹦,傳遞兩個不同的Sequence類型(ArraySet)會得到各自的數(shù)組值诸迟。

其他

以上列舉的囊括了swift4中最大變化的部分, 現(xiàn)在我們快速看看其他方面的小改動

MutableCollection.swapAt(::)

MutableCollection現(xiàn)在具有mutate方法swapAt(_:_ :); 交換指定的索引值[SE-0173]:

// Very basic bubble sort with an in-place swap
func bubbleSort<T: Comparable>(_ array: [T]) -> [T] {
  var sortedArray = array
  for i in 0..<sortedArray.count - 1 {
    for j in 1..<sortedArray.count {
      if sortedArray[j-1] > sortedArray[j] {
        sortedArray.swapAt(j-1, j) // New MutableCollection method
      }
    }
  }
  return sortedArray
}

bubbleSort([4, 3, 2, 1, 0]) // [0, 1, 2, 3, 4]
關(guān)聯(lián)類型約束

現(xiàn)在可以使用where語句來約束關(guān)聯(lián)類型[SE-0142]:

protocol MyProtocol {
  associatedtype Element
  associatedtype SubSequence : Sequence where SubSequence.Iterator.Element == Iterator.Element
}

通過協(xié)議,在associatedtype的聲明時就可以直接約束它的值愕乎。

類和協(xié)議的存在方式

在定義某個類型時(譯者注: 指變量或常量), 這特性可以讓其必須符合某種類型以及遵守一組協(xié)議[SE-0156]:

protocol MyProtocol { }
class View { }
class ViewSubclass: View, MyProtocol { }

class MyClass {
  var delegate: (View & MyProtocol)?
}

let myClass = MyClass()
//myClass.delegate = View() // error: cannot assign value of type 'View' to type '(View & MyProtocol)?'
myClass.delegate = ViewSubclass()
限制@objc 推斷

要向objective - c公開或使用Swift API阵苇,可以使用@ objc編譯器特性。在很多情況下感论,編譯器可以為快速推斷绅项。然而, 這種大量的推理會導(dǎo)致三個問題是:

  1. 有可能顯著地增加二進(jìn)制文件的大小比肄;
  2. 有時候@objc會推斷模糊快耿;
  3. 增加創(chuàng)建Objective-C Selector沖突的可能性。

Swift 4通過限制@objc的推斷來解決這個問題[SE-0160] 芳绩,也就是說在Objective-C處于完全動態(tài)的情況下润努,您需要使用@objc
您需要修改的幾個示例程序包括私有方法示括,動態(tài)聲明和NSObject子類的任何方法铺浇。

NSNumber Bridging

NSNumberSwift的數(shù)字之間有許多有趣的行為,這些行為長久以來一直困擾著這個語言垛膝。幸運的是鳍侣,Swift 4將這些可以避免這些錯誤[SE-0170]
這里有一個例子

let n = NSNumber(value: 999)
let v = n as? UInt8 // Swift 4: nil, Swift 3: 231

在Swift 3中會出現(xiàn)的怪異現(xiàn)象吼拥,如果數(shù)字溢出倚聚,它會從0開始。在這個例子中"999% 2 ^ 8 = 231凿可。
只有在包含的類型中可以安全地表示這個數(shù)字時,Swift 4才通過強制轉(zhuǎn)換返回一個值

Swift Package Manager

在最近幾個月中惑折,Swift Package Manager有許多更新,幾個比較大的更新如下:
· 源代碼的依賴來自于分支或者提交的分支
· 更容易控制的package版本
· 用更為常見的解決方案代替非直觀的命令
· 能夠自定義編譯的swift版本
· 指定每個target的源文件的位置

這些都是SPM所做的重大改變枯跑。 SPM還有很長的路要走惨驶,但是我們可以通過保持積極的建議來幫助它更完善。
有關(guān)最近解決的提案的全面了解敛助,請查看Swift 4 Package Manager Update粗卜。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市纳击,隨后出現(xiàn)的幾起案子续扔,更是在濱河造成了極大的恐慌攻臀,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,839評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件纱昧,死亡現(xiàn)場離奇詭異刨啸,居然都是意外死亡,警方通過查閱死者的電腦和手機识脆,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評論 2 382
  • 文/潘曉璐 我一進(jìn)店門设联,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事£夹疲” “怎么了?”我有些...
    開封第一講書人閱讀 153,116評論 0 344
  • 文/不壞的土叔 我叫張陵粘招,是天一觀的道長。 經(jīng)常有香客問我偎球,道長洒扎,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,371評論 1 279
  • 正文 為了忘掉前任衰絮,我火速辦了婚禮袍冷,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘猫牡。我一直安慰自己胡诗,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 64,384評論 5 374
  • 文/花漫 我一把揭開白布淌友。 她就那樣靜靜地躺著煌恢,像睡著了一般。 火紅的嫁衣襯著肌膚如雪震庭。 梳的紋絲不亂的頭發(fā)上瑰抵,一...
    開封第一講書人閱讀 49,111評論 1 285
  • 那天,我揣著相機與錄音器联,去河邊找鬼二汛。 笑死,一個胖子當(dāng)著我的面吹牛拨拓,可吹牛的內(nèi)容都是我干的肴颊。 我是一名探鬼主播,決...
    沈念sama閱讀 38,416評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼千元,長吁一口氣:“原來是場噩夢啊……” “哼苫昌!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起幸海,我...
    開封第一講書人閱讀 37,053評論 0 259
  • 序言:老撾萬榮一對情侶失蹤祟身,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后物独,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體袜硫,經(jīng)...
    沈念sama閱讀 43,558評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,007評論 2 325
  • 正文 我和宋清朗相戀三年挡篓,在試婚紗的時候發(fā)現(xiàn)自己被綠了婉陷。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,117評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡官研,死狀恐怖秽澳,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情戏羽,我是刑警寧澤担神,帶...
    沈念sama閱讀 33,756評論 4 324
  • 正文 年R本政府宣布,位于F島的核電站始花,受9級特大地震影響妄讯,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜酷宵,卻給世界環(huán)境...
    茶點故事閱讀 39,324評論 3 307
  • 文/蒙蒙 一亥贸、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧浇垦,春花似錦炕置、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至煌抒,卻和暖如春仍劈,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背寡壮。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評論 1 262
  • 我被黑心中介騙來泰國打工贩疙, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人况既。 一個月前我還...
    沈念sama閱讀 45,578評論 2 355
  • 正文 我出身青樓这溅,卻偏偏與公主長得像,于是被迫代替她去往敵國和親棒仍。 傳聞我的和親對象是個殘疾皇子悲靴,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,877評論 2 345

推薦閱讀更多精彩內(nèi)容