隨機數(shù)生成
由于iPhoen5和之前的手機是32位CPU,arc4random 所返回的值不論在什么平臺上都是一個 UInt32 督弓,于是在 32 位的平 臺上就有一半幾率在進行 Int 轉(zhuǎn)換時越界 故使用func arc4random_uniform(_: UInt32) -> UInt32
let diceFaceCount: UInt32 = 6
let randomRoll = Int(arc4random_uniform(diceFaceCount)) + 1
print(randomRoll)
func random(in range: Range<Int>) -> Int {
let count = UInt32(range.endIndex - range.startIndex)
return Int(arc4random_uniform(count)) + range.startIndex
}
for _ in 0...100 {
let range = Range<Int>(1...6)
print(random(in: range))
}
print 和 debugPrint
extension Meeting: CustomStringConvertible {
var description: String {
return "于 \(self.date) 在 \(self.place) 與 \(self.attendeeName) 進行會議"
}
}
1.CustomDebugStringConvertible僅發(fā)生在調(diào)試中使用debugger來進行打印的時候的輸出
2.對于實現(xiàn)了CustomDebugStringConvertible協(xié)議的類型 可以在打斷點并在控制臺使用po 對象的命令進行打印
錯誤和異常處理
do {
try d.write(toFile: "Hello", options: [])
} catch let error as NSError {
print ("Error: \(error.domain)")
}
enum LoginError: Error {
case UserNotFound, UserPasswordNotMatch
}
func login(user: String, password: String) throws {
//users 是 [String: String],存儲[用戶名:密碼]
if !users.keys.contains(user) {
throw LoginError.UserNotFound
}
if users[user] != password {
throw LoginError.UserPasswordNotMatch
}
print("Login successfully.")
}
斷言
func convertToKelvin(_ celsius: Double) -> Double {
assert(celsius > -273.15, "輸入的攝氏溫度不能低于絕對零度")
return celsius - (-273.15)
}
斷言是開發(fā)時的特性 只有在Debug編譯的時候有效,而在運行時是不被編譯執(zhí)行的,因此斷言并不會消耗運行時的性能
可以強制禁用斷言
fatalError
class MyClass {
func methodMustBeImplementedInSubclass() {
fatalError("這個方法必須在子類中被重寫")
}
}
class YourClass: MyClass {
override func methodMustBeImplementedInSubclass() {
print("YourClass 實現(xiàn)了該方法")
}
}
class TheirClass: MyClass {
func someOtherMethod() {
}
}
YourClass().methodMustBeImplementedInSubclass()
// YourClass 實現(xiàn)了該方法
TheirClass().methodMustBeImplementedInSubclass()
JSON 和 Codable
struct Obj: Codable {
let menu: Menu
struct Menu: Codable {
let id: String
let value: String
let popup: Popup
}
struct Popup: Codable {
let menuItem: [MenuItem]
enum CodingKeys: String, CodingKey {
case menuItem = "menuitem"
}
}
struct MenuItem: Codable {
let value: String
let onClick: String
enum CodingKeys: String, CodingKey {
case value
case onClick = "onclick"
}
}
}
1.只有一個類型中所有成員都實現(xiàn)了Codable 那么這個類型就自動滿足Codable的要求
2.如果Json中的key和類型中的變量名不一致 要在對應(yīng)類中聲明CodingKeys枚舉,并用合適的鍵值覆蓋對應(yīng)的默認值
let data = jsonString.data(using: .utf8)!
do {
let obj = try JSONDecoder().decode(Obj.self, from: data)
let value = obj.menu.popup.menuItem[0].value
print(value)
} catch {
print("出錯啦:\(error)")
}
NSNull
NSNull 會默默的被通過Optional Binding被轉(zhuǎn)換為nil 避免被執(zhí)行
// 假設(shè) jsonValue 是從一個 JSON 中取出的 NSNull
let jsonValue: AnyObject = NSNull()
if let string = jsonValue as? String {
print(string.hasPrefix("a"))
} else {
print("不能解析")
}
// 輸出: // 不能解析
屬性訪問控制
當希望讀取到這個類的屬性 但是要保證類型的封裝和安全 只能在類型內(nèi)部對其進行改變或者設(shè)置
class MyClass {
private(set) var name: String?
}
泛型擴展
extension Array {
var random: Element? {
return self.count != 0 ? self[Int(arc4random_uniform(UInt32(self.count)))] :nil
}
}
let languages = ["Swift","ObjC","C++","Java"]
languages.random!
// 隨機輸出是這四個字符串中的某個
let ranks = [1,2,3,4]
ranks.random!
// 隨機輸出是這四個數(shù)字中的某個
尾遞歸
func sum(_ n: UInt) -> UInt {
if n == 0 {
return 0
}
return n + sum(n - 1)
}
sum(4) // 10
sum(100) // 5050
當輸入的數(shù)字過大時 就會出現(xiàn)錯誤 是因為每次對于sum的遞歸調(diào)用都需要在調(diào)用棧上保存當前狀態(tài),否則無法計算最后的值,當n足夠大,調(diào)用棧足夠深的時候,椂昱桑空間被耗盡而導(dǎo)致錯誤 棧溢出
使用尾遞歸的方式解決該問題 尾遞歸就是讓函數(shù)里的最后一個動作是一個函數(shù)調(diào)用的形式,這個調(diào)用的返回值將直接被當前函數(shù)返回 從而避免在棧上保存狀態(tài) 這樣就是更新最后的棧幀 不是新建一個 來避免棧溢出的發(fā)生
func tailSum(_ n: UInt) -> UInt {
func sumInternal(_ n: UInt, current: UInt) -> UInt {
if n == 0 {
return current
} else {
return sumInternal(n - 1, current: current + n)
}
}
return sumInternal(n, current: 0)
}
tailSum(1000000)
由于默認Debug模式下Swift編譯器不會對尾遞歸進行優(yōu)化 可以改為Relese模式 再運行