1.字符串Strings
swift3中,我们要遍历字符串,需要这样做:
let string = "abcd"
for char in string.characters {
print(char)
}
到了Swift4,我们可以直接使用:
let string = "abcd"
for char in string {
print(char)
}
swift3中,需要对字符串中的字符进行操作时,需要这样做:
string.characters.count
string.characters.dropFirst()
string.characters.reversed()
let result = string.characters.filter { char in
return char != "c"
}
result
swift4中:
string.count
string.dropFirst()
string.reversed()
let result = string.filter { char in
return char != "c"
}
result
2.字典dic和集合set
swift4增加了从数组创建出字典的能力
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]
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]
可以利用具有重复的key的数组去创建字典,并不会有什么问题。
let favoriteStarVotes = ["Alpha Centauri A", "Wolf 359", "Alpha Centauri A", "Barnard's Star"]
let mergedKeysAndValues = Dictionary(zip(favoriteStarVotes, repeatElement(1, count: favoriteStarVotes.count)), uniquingKeysWith: +)
// ["Barnard's Star": 1, "Alpha Centauri A": 2, "Wolf 359": 1]
字典和集合现在具有了过滤的功能
closeStars = starDistanceDict.filter { $0.value < 5.0 }
closeStars // Dictionary: ["Proxima Centauri": 4.24, "Alpha Centauri A": 4.37, "Alpha Centauri B": 4.37]
字典有了一个新的方法,可以直接映射他的值
//将closeStars的value转换成字符串
let mappedCloseStars = closeStars.mapValues { “\($ 0)” }
mappedCloseStars // [ “Proxima Centauri”:“4.24”,“Alpha Centauri A”:“4.37”,“Alpha Centauri B”:“4.37” ]
字典有了新的方法给与取值时返回默认值
let siriusDistance = mappedCloseStars["Wolf 359", default: "unknown"] // "unknown"
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]
字典有了一个分组功能,能够根据指定的方式进行分组
//按照首字母进行分组
let starsByFirstLetter = Dictionary(grouping: nearestStarNames) { $0.first! }
// ["B": ["Barnard's Star"], "A": ["Alpha Centauri A", "Alpha Centauri B"], "W": ["Wolf 359"], "P": ["Proxima Centauri"]]
字典和集合有了预留容量的功能,当了解自己需要多大的容量时,可以指定
starWordsCount.capacity // 6
starWordsCount.reserveCapacity(20) //预留了20的空间
starWordsCount.capacity // 24
3.修饰符
private在swift3中,表示该成员在类中可以使用,在开发过程中,我们经常需要给类写扩展,而在swift3中,在扩展里面,我们是无法访问到private修饰的成员的。虽说可以用fileprivate来解决。这个问题在swift4中得到了修改,在扩展中可以使用private修饰的成员。
struct SpaceCraft {
private let warpCode: String
init(warpCode: String) {
self.warpCode = warpCode
}
}
extension SpaceCraft {
func goToWarpSpeed(warpCode: String) {
if warpCode == self.warpCode { //在swift3中会报错
print("Do it Scotty!")
}
}
}
let enterprise = SpaceCraft(warpCode: "KirkIsCool")
//enterprise.warpCode // 这里使用依然会报错,想要在这里也能访问,需要修改为fileprivate
enterprise.goToWarpSpeed(warpCode: "KirkIsCool")
4.新增API
序列化和归档
swift4中,对一个class、struct、enum进行序列化和归档,会变得非常容易
//遵循该协议
struct CuriosityLog: Codable {
enum Discovery: String, Codable {
case rock, water, martian
}
var sol: Int
var discoveries: [Discovery]
}
let logSol42 = CuriosityLog(sol: 42, discoveries: [.rock, .rock, .rock, .rock])
let jsonEncoder = JSONEncoder() // 指定解释器
// 开始将数据编码成字符串
let jsonData = try jsonEncoder.encode(logSol42)
// 创建出jsonstring
let jsonString = String(data: jsonData, encoding: .utf8) // "{"sol":42,"discoveries":["rock","rock","rock","rock"]}"
//通过字符串生成需要的类型或者对象
let jsonDecoder = JSONDecoder() // 指定解码器
let decodedLog = try jsonDecoder.decode(CuriosityLog.self, from: jsonData)
decodedLog.sol // 42
decodedLog.discoveries // [rock, rock, rock, rock]
通过类型的关键路径来或者/设置实例的基础值
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: obi wan)
//通过路径获取
let nameKeyPath = \ForceUser.name
let obiwanName = obiwan[keyPath: nameKeyPath] // "Obi-Wan Kenobi"
let anakinSaberColor = anakin[keyPath: \ForceUser.lightsaber.color] // blue
//返回对象的引用
let masterKeyPath = \ForceUser.master
let anakinMasterName = anakin[keyPath: masterKeyPath]?.name // "Obi-Wan Kenobi"
//设置
anakin[keyPath: masterKeyPath] = sidious
anakin.master?.name // Darth Sidious
多行字符串
增加了多行字符串,而不必使用\n来实现。
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)
增加单面范围
var planets = ["Mercury", "Venus", "Earth", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune"]
let outsideAsteroidBelt = planets[4...] // swift3: planets[4..<planets.endIndex]
let firstThree = planets[..<4] // swift3: planets[planets.startIndex..<4]
无限序列
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")]
模式匹配
func temperature(planetNumber: Int) {
switch planetNumber {
case ...2: // 小于等于2的值
print("Too hot")
case 4...: // 大于等于4的值
print("Too cold")
default:
print("Justtttt right")
}
}
temperature(planetNumber: 3) // Justtttt right
通用下标
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
}
}
//字典类型 [String: Any]
var earthData = GenericDictionary(data: ["name": "Earth", "population": 7500000000, "moons": 1])
// 自动推断类型有没有 "as? String"
let name: String? = earthData["name"]
// 自动推断类型有没有 "as? Int"
let population: Int? = earthData["population"]
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
}
}
let nameAndMoons = earthData[["moons", "name"]] // [1, "Earth"]
let nameAndMoons2 = earthData[Set(["moons", "name"])] // [1, "Earth"]
交换索引值swapAt(::)
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)
}
}
}
return sortedArray
}
bubbleSort([4, 3, 2, 1, 0]) // [0, 1, 2, 3, 4]
限制关联类型
protocol MyProtocol {
associatedtype Element
associatedtype SubSequence : Sequence where SubSequence.Iterator.Element == Iterator.Element
}
类和协议共存
protocol MyProtocol { }
class View { }
class ViewSubclass: View, MyProtocol { }
class MyClass {
var delegate: (View & MyProtocol)?
}
let myClass = MyClass()
//myClass.delegate = View() // 会报错,需要的是该类型: '(View & MyProtocol)?'
myClass.delegate = ViewSubclass()
NSNumber桥接
let n = NSNumber(value: 999)
let v = n as? UInt8 // Swift 4: nil, Swift 3: 231