Swift快速入門教程2

****函數(shù)****
目標(biāo)

  • 掌握函數(shù)的定義格式
  • 掌握外部參數(shù)的用處
  • 掌握無返回類型的三種函數(shù)定義方式

****代碼實現(xiàn)****
函數(shù)定義

  • 函數(shù)的定義

  • 格式fund 函數(shù)名(行參列表) -> 返回值 {代碼實現(xiàn)}

  • 調(diào)用 let result = 函數(shù)名(值1,參數(shù)2:值2...)

     fun sum(a:Int,b: Int) -> Int {
        return a + b
      }
       let result = sum(10, b: 20)
    
  • 函數(shù)格式小結(jié)

       // 格式:func 函數(shù)名(形參1: 類型 = 默認(rèn)值, _ 形參2: 類型 = 默認(rèn)值...) -> 返回值 { // 代碼實現(xiàn) }
       // 說明:包含默認(rèn)值的函數(shù)可以不用傳遞脱吱,并且可以任意組合
       //
       // 格式:func 函數(shù)名(形參1: 類型, _ 形參2: 類型...) -> 返回值 { // 代碼實現(xiàn) }
       // 說明:_ 可以忽略外部參數(shù)智厌,與其他語言的函數(shù)風(fēng)格更加類似
       //
       // 格式:func 函數(shù)名(外部參數(shù)1 形參1: 類型, 外部參數(shù)2 形參2: 類型...) -> 返回值 { // 代碼實現(xiàn) }
       // 說明:外部參數(shù)名供外部調(diào)用使用,形參 在函數(shù)內(nèi)部使用
       //
       // 格式:func 函數(shù)名(形參列表) -> 返回值 { // 代碼實現(xiàn)             }
    

****沒有返回值****

  • 沒有返回值的函數(shù),一共有三種寫法

  • 省略

  • ()

  • Void
    func demo(str: String) -> Void {
    print(str)
    }
    func demo1(str: String) -> () {
    print(str)
    }
    func demo2(str: String) {
    print(str)
    }

       demo("hello")
       demo1("hello world")
       demo2("oleo")
    
  • 外部參數(shù)

    • 在形參名前在增加一個外部參數(shù)名,能夠方便調(diào)用人員更好第理解函數(shù)的語義
    • 格式: func 函數(shù)名(外部參數(shù)名 形式參數(shù)名: 形式參數(shù)類型) -> 返回值類型 { // 代碼實現(xiàn) }
    • Swift 2.0中,默認(rèn)第一個參數(shù)名省略
func sum1(num1 a: Int, num2 b: Int) -> Int {
    return a + b
}

sum1(num1: 10, num2: 20)

****閉包****

與 OC 中的 Block 類似象迎,閉包主要用于異步操作執(zhí)行完成后的代碼回調(diào),網(wǎng)絡(luò)訪問結(jié)果以參數(shù)的形式傳遞給調(diào)用方

目標(biāo)

  • 掌握閉包的定義

  • 掌握閉包的概念和用法

  • 了解尾隨閉包的寫法

  • 掌握解除循環(huán)引用的方法

  • OC 中 Block 概念回顧

    • 閉包類似于 OC 中的 Block
    • 預(yù)先定義好的代碼
    • 在需要時執(zhí)行
    • 可以當(dāng)作參數(shù)傳遞
    • 可以有返回值
    • 包含 self 時需要注意循環(huán)引用

****閉包的定義****

  • 定義一個函數(shù)
//: 定義一個 sum 函數(shù)
func sum(num1 num1: Int, num2: Int) -> Int {
    return num1 + num2
}
sum(num1: 10, num2: 30)

//: 在 Swift 中函數(shù)本身就可以當(dāng)作參數(shù)被定義和傳遞
let mySum = sum
let result = mySum(num1: 20, num2: 30)
  • 定義一個閉包
    • 閉包= { (行參) -> 返回值 in // 代碼實現(xiàn) }
    • in 用于區(qū)分函數(shù)定義和代碼實現(xiàn)
//: 閉包 = { (行參) -> 返回值 in // 代碼實現(xiàn) }
let sumFunc = { (num1 x: Int, num2 y: Int) -> Int in
    return x + y
}
sumFunc(num1: 10, num2: 20)
  • 閉包格式小結(jié)
// 格式: let 閉包名: (形參) -> 返回類型 = { (形參1, 形參2, ...) in 代碼實現(xiàn) }
// 說明: 使用形參列表,可以直接提供外部參數(shù)
//
// 格式: let 閉包名: (形參類型) -> 返回類型 = { (形參1, 形參2, ...) in 代碼實現(xiàn) }
//
// 格式: { (外部參數(shù)1 形參1, 外部參數(shù)2 形參2, ...) -> 返回類型 in 代碼實現(xiàn) }
// 說明: 使用外部參數(shù)會方便調(diào)用
//
// 格式: { (形參列表) -> 返回類型 in 代碼實現(xiàn) }

最簡單的閉包乍钻,如果沒有參數(shù)/返回值咖杂,則 參數(shù)/返回值/in 統(tǒng)統(tǒng)都可以省略

  • {代碼實現(xiàn)}
let demoFunc = {
    print("hello")
}

****基本使用****

GCD異步

  • 模擬在后臺線程加載數(shù)據(jù)
func loadData() {
    dispatch_async(dispatch_get_global_queue(0, 0), { () -> Void in
        print("耗時操作 \(NSThread .currentThread())")
    })
}
  • 尾隨閉包庆寺,如果閉包是最后一個參數(shù),可以用以下寫法
  • 注意上下兩段代碼诉字,} 的位置
func loadData() {
    dispatch_async(dispatch_get_global_queue(0, 0)) { () -> Void in
        print("耗時操作 \(NSThread .currentThread())")
    }
}
  • 閉包的簡寫懦尝,如果閉包中沒有參數(shù)和返回值知纷,可以省略
func loadData() {
    dispatch_async(dispatch_get_global_queue(0, 0)) {
        print("耗時操作 \(NSThread .currentThread())")
    }
}

****自定義閉包參數(shù),實現(xiàn)主線程回調(diào)****

  • 添加沒有參數(shù)陵霉,沒有返回值的閉包
override func viewDidLoad() {
    super.viewDidLoad()

    loadData {
        print("完成回調(diào)")
    }
}
// MARK: - 自定義閉包參數(shù)
func loadData(finished: ()->()) {

    dispatch_async(dispatch_get_global_queue(0, 0)) {
        print("耗時操作 \(NSThread.currentThread())")

        dispatch_sync(dispatch_get_main_queue()) {
            print("主線程回調(diào) \(NSThread.currentThread())")

            // 執(zhí)行回調(diào)
            finished()
        }
    }
}
  • 添加回調(diào)參數(shù)
override func viewDidLoad() {
    super.viewDidLoad()

    loadData4 { (html) -> () in
        print(html)
    }
}
/// 加載數(shù)據(jù)
/// 完成回調(diào) - 傳入回調(diào)閉包琅轧,接收異步執(zhí)行的結(jié)果
func loadData4(finished: (html: String) -> ()) {

    dispatch_async(dispatch_get_global_queue(0, 0)) {
        print("加載數(shù)據(jù) \(NSThread.currentThread())")

        dispatch_sync(dispatch_get_main_queue()) {
            print("完成回調(diào) \(NSThread.currentThread())")

            finished(html: "<h1>hello world</h1>")
        }
    }
}

****循環(huán)引用****

  • 創(chuàng)建NetworkTools對象
class NetworkTools: NSObject {

    /// 加載數(shù)據(jù)
    ///
    /// - parameter finished: 完成回調(diào)
    func loadData(finished: () -> ()) {
        print("開始加載數(shù)據(jù)...")

        // ...
        finished()
    }

    deinit {
        print("網(wǎng)絡(luò)工具 88")
    }
}
  • 實例化NetworkTools并且加載數(shù)據(jù)
class ViewController: UIViewController {

    var tools: NetworkTools?

    override func viewDidLoad() {
        super.viewDidLoad()

        tools = NetworkTools()
        tools?.loadData() {
            print("come here \(self.view)")
        }
    }

    /// 與 OC 中的 dealloc 類似,注意此函數(shù)沒有()
    deinit {
        print("控制器 88")
    }
}

運(yùn)行不會形成循環(huán)引用踊挠,因為 loadData 執(zhí)行完畢后乍桂,就會釋放對 self 的引用

  • 修改 NetworkTools,定義回調(diào)閉包屬性
/// 完成回調(diào)屬性
var finishedCallBack: (()->())?

/// 加載數(shù)據(jù)
///
/// - parameter finished: 完成回調(diào)
func loadData(finished: () -> ()) {

    self.finishedCallBack = finished

    print("開始加載數(shù)據(jù)...")

    // ...
    working()
}

func working() {
    finishedCallBack?()
}

deinit {
    print("網(wǎng)絡(luò)工具 88")
}

運(yùn)行測試效床,會出現(xiàn)循環(huán)引用

****解除循環(huán)引用****

  • 與OC類似的方法
/// 類似于 OC 的解除引用
func demo() {
    weak var weakSelf = self
    tools?.loadData() {
        print("\(weakSelf?.view)")
    }
}
  • Swift 推薦的方法
loadData { [weak self] in
    print("\(self?.view)")
}
  • 還可以
loadData { [unowned self] in
    print("\(self.view)")
}

閉包(Block) 的循環(huán)引用小結(jié)

  • Swift
  • [weak self]
    • self是可選項睹酌,如果self已經(jīng)被釋放,則為nil
  • [unowned self]
    • self不是可選項剩檀,如果self已經(jīng)被釋放憋沿,則出現(xiàn)野指針訪問
  • Objc
    • __weak typeof(self) weakSelf;
    • 如果self已經(jīng)被釋放,則為nil
  • __unsafe_unretained typeof(self) weakSelf;
    • 如果self已經(jīng)被釋放沪猴,則出現(xiàn)野指針訪問

****面向?qū)ο?***
構(gòu)造函數(shù)基礎(chǔ)
構(gòu)造函數(shù)是一種特殊的函數(shù)辐啄,主要用來在創(chuàng)建對象時初始化對象,為對象成員變量設(shè)置初始值运嗜,在 OC 中的構(gòu)造函數(shù)是 initWithXXX壶辜,在 Swift 中由于支持函數(shù)重載,所有的構(gòu)造函數(shù)都是 init
構(gòu)造函數(shù)的作用

  • 分配空間 alloc
  • 設(shè)置初始值 init
構(gòu)造函數(shù)繼承圖.png

必選屬性

  • 自定義 Person 對象
class Person: NSObject {

    /// 姓名
    var name: String
    /// 年齡
    var age: Int
}

提示錯誤 Class 'Person' has no initializers -> 'Person' 類沒有實例化器s

原因:如果一個類中定義了必選屬性担租,必須通過構(gòu)造函數(shù)為這些必選屬性分配空間并且設(shè)置初始值

  • 重寫 父類的構(gòu)造函數(shù)
/// `重寫`父類的構(gòu)造函數(shù)
override init() {

}

提示錯誤 Property 'self.name' not initialized at implicitly generated super.init call -> 屬性 'self.name' 沒有在隱式生成的 super.init 調(diào)用前被初始化

  • 手動添加 super.init() 調(diào)用
/// `重寫`父類的構(gòu)造函數(shù)
override init() {
    super.init()
}

提示錯誤 Property 'self.name' not initialized at super.init call -> 屬性 'self.name' 沒有在 super.init 調(diào)用前被初始化

  • 為比選屬性設(shè)置初始值
/// `重寫`父類的構(gòu)造函數(shù)
override init() {
    name = "張三"
    age = 18

    super.init()
}

小結(jié)

  • 非 Optional 屬性砸民,都必須在構(gòu)造函數(shù)中設(shè)置初始值,從而保證對象在被實例化的時候翩活,屬性都被正確初始化
  • 在調(diào)用父類構(gòu)造函數(shù)之前阱洪,必須保證本類的屬性都已經(jīng)完成初始化
  • Swift 中的構(gòu)造函數(shù)不用寫 func

子類的構(gòu)造函數(shù)

  • 自定義子類時,需要在構(gòu)造函數(shù)中菠镇,首先為本類定義的屬性設(shè)置初始值
  • 然后再調(diào)用父類的構(gòu)造函數(shù)冗荸,初始化父類中定義的屬性
/// 學(xué)生類
class Student: Person {

    /// 學(xué)號
    var no: String

    override init() {
        no = "001"

        super.init()
    }
}

小結(jié)

  • 先調(diào)用本類的構(gòu)造函數(shù)初始化本類的屬性
  • 然后調(diào)用父類的構(gòu)造函數(shù)初始化父類的屬性
  • Xcode 7 beta 5之后,父類的構(gòu)造函數(shù)會被自動調(diào)用利耍,強(qiáng)烈建議寫 super.init()蚌本,保持代碼執(zhí)行線索的可讀性
  • super.init() 必須放在本類屬性初始化的后面,保證本類屬性全部初始化完成

****Optional 屬性****

  • 將對象屬性類型設(shè)置為 Optional
class Person: NSObject {
    /// 姓名
    var name: String?
    /// 年齡
    var age: Int?
}
  • 可選屬性不需要設(shè)置初始值隘梨,默認(rèn)初始值都是 nil
  • 可選屬性是在設(shè)置數(shù)值的時候才分配空間的程癌,是延遲分配空間的,更加符合移動開發(fā)中延遲創(chuàng)建的原則

重載構(gòu)造函數(shù)

  • Swift 中支持函數(shù)重載轴猎,同樣的函數(shù)名嵌莉,不一樣的參數(shù)類型
/// `重載`構(gòu)造函數(shù)
///
/// - parameter name: 姓名
/// - parameter age:  年齡
///
/// - returns: Person 對象
init(name: String, age: Int) {
    self.name = name
    self.age = age

    super.init()
}

注意事項

  • 如果重載了構(gòu)造函數(shù),但是沒有實現(xiàn)默認(rèn)的構(gòu)造函數(shù) init()捻脖,則系統(tǒng)不再提供默認(rèn)的構(gòu)造函數(shù)
  • 原因锐峭,在實例化對象時中鼠,必須通過構(gòu)造函數(shù)為對象屬性分配空間和設(shè)置初始值,對于存在必選參數(shù)的類而言沿癞,默認(rèn)的 init() 無法完成分配空間和設(shè)置初始值的工作

調(diào)整子類的構(gòu)造函數(shù)

  • 重寫父類的構(gòu)造函數(shù)
/// `重寫`父類構(gòu)造函數(shù)
///
/// - parameter name: 姓名
/// - parameter age:  年齡
///
/// - returns: Student 對象
override init(name: String, age: Int) {
    no = "002"

    super.init(name: name, age: age)
}

  • 重載構(gòu)造函數(shù)
/// `重載`構(gòu)造函數(shù)
///
/// - parameter name: 姓名
/// - parameter age:  年齡
/// - parameter no:   學(xué)號
///
/// - returns: Student 對象
init(name: String, age: Int, no: String) {
    self.no = no

    super.init(name: name, age: age)
}

注意:如果是重載的構(gòu)造函數(shù)援雇,必須 super 以完成父類屬性的初始化工作

****重載和重寫****

  • 重載,函數(shù)名相同椎扬,參數(shù)名/參數(shù)類型/參數(shù)個數(shù)不同
  • 重載函數(shù)并不僅僅局限于構(gòu)造函數(shù)
  • 函數(shù)重載是面相對象程序設(shè)計語言的重要標(biāo)志
  • 函數(shù)重載能夠簡化程序員的記憶
  • OC 不支持函數(shù)重載惫搏,OC 的替代方式是 withXXX...
  • 重寫,子類需要在父類擁有方法的基礎(chǔ)上進(jìn)行擴(kuò)展蚕涤,需要 override 關(guān)鍵字
重載和重寫.png

****KVC 字典轉(zhuǎn)模型構(gòu)造函數(shù)****

/// `重寫`構(gòu)造函數(shù)
///
/// - parameter dict: 字典
///
/// - returns: Person 對象
init(dict: [String: AnyObject]) {
    setValuesForKeysWithDictionary(dict)
}
  • 以上代碼編譯就會報錯筐赔!

  • 原因:

    • KVC 是 OC 特有的,KVC 本質(zhì)上是在運(yùn)行時钻趋,動態(tài)向?qū)ο蟀l(fā)送 setValue:ForKey: 方法川陆,為對象的屬性設(shè)置數(shù)值
    • 因此剂习,在使用 KVC 方法之前蛮位,需要確保對象已經(jīng)被正確實例化
    • 添加 super.init() 同樣會報錯
  • 原因:

    • 必選屬性必須在調(diào)用父類構(gòu)造函數(shù)之前完成初始化分配工作
  • 講必選參數(shù)修改為可選參數(shù),調(diào)整后的代碼如下:

/// 個人模型
class Person: NSObject {

    /// 姓名
    var name: String?
    /// 年齡
    var age: Int?

    /// `重寫`構(gòu)造函數(shù)
    ///
    /// - parameter dict: 字典
    ///
    /// - returns: Person 對象
    init(dict: [String: AnyObject]) {
        super.init()

        setValuesForKeysWithDictionary(dict)
    }
}

運(yùn)行測試鳞绕,仍然會報錯

錯誤信息:this class is not key value coding-compliant for the key age. -> 這個類的鍵值 age 與 鍵值編碼不兼容

  • 原因:
  • 在 Swift 中失仁,如果屬性是可選的,在初始化時们何,不會為該屬性分配空間
  • 而 OC 中基本數(shù)據(jù)類型就是保存一個數(shù)值萄焦,不存在可選的概念
  • 解決辦法:給基本數(shù)據(jù)類型設(shè)置初始值
  • 修改后的代碼如下:
/// 姓名
var name: String?
/// 年齡
var age: Int? = 0

/// `重寫`構(gòu)造函數(shù)
///
/// - parameter dict: 字典
///
/// - returns: Person 對象
init(dict: [String: AnyObject]) {
    super.init()

    setValuesForKeysWithDictionary(dict)
}

提示:在定義類時,基本數(shù)據(jù)類型屬性一定要設(shè)置初始值冤竹,否則無法正常使用 KVC 設(shè)置數(shù)值

****KVC 函數(shù)調(diào)用順序****

init(dict: [String: AnyObject]) {
    super.init()

    setValuesForKeysWithDictionary(dict)
}

override func setValue(value: AnyObject?, forKey key: String) {
    print("Key \(key) \(value)")

    super.setValue(value, forKey: key)
}

// `NSObject` 默認(rèn)在發(fā)現(xiàn)沒有定義的鍵值時拂封,會拋出 `NSUndefinedKeyException` 異常
override func setValue(value: AnyObject?, forUndefinedKey key: String) {
    print("UndefinedKey \(key) \(value)")
}
  • setValuesForKeysWithDictionary 會按照字典中的 key 重復(fù)調(diào)用 setValue:forKey 函數(shù)
  • 如果沒有實現(xiàn) forUndefinedKey 函數(shù),程序會直接崩潰
    • NSObject 默認(rèn)在發(fā)現(xiàn)沒有定義的鍵值時鹦蠕,會拋出 NSUndefinedKeyException 異常
  • 如果實現(xiàn)了 forUndefinedKey冒签,會保證 setValuesForKeysWithDictionary 繼續(xù)遍歷后續(xù)的 key
  • 如果父類實現(xiàn)了 forUndefinedKey,子類可以不必再實現(xiàn)此函數(shù)

子類的 KVC 函數(shù)

/// 學(xué)生類
class Student: Person {

    /// 學(xué)號
    var no: String?
}
  • 如果父類中已經(jīng)實現(xiàn)了父類的相關(guān)方法钟病,子類中不用再實現(xiàn)相關(guān)方法

** KVC 字典轉(zhuǎn)模型示意圖**

KVC字典轉(zhuǎn)模型.png

便利構(gòu)造函數(shù)

目的

  • 條件判斷萧恕,只有滿足條件,才實例化對象肠阱,可以防治造成不必
    要的內(nèi)存開銷
  • 簡化對象的創(chuàng)建
  • 本身不負(fù)責(zé)屬性的創(chuàng)建和初始化工作

特點

  • 默認(rèn)情況下票唆,所有的構(gòu)造方法都是指定構(gòu)造函數(shù) Designated
  • convenience 關(guān)鍵字修飾的構(gòu)造方法就是便利構(gòu)造函數(shù)
  • 便利構(gòu)造函數(shù)具有以下特點:
    • 可以返回 nil
    • 只有便利構(gòu)造函數(shù)中可以調(diào)用 self.init()
    • 便利構(gòu)造函數(shù)不能被重載或者 super
    • 便利構(gòu)造函數(shù)主要用于條件監(jiān)測或者簡化對象創(chuàng)建
/**
 便利構(gòu)造函數(shù)的目的:

 1. 條件判斷
 2. 簡化對象的創(chuàng)建
 3. 本身不負(fù)責(zé)屬性的創(chuàng)建和初始化工作
*/
convenience init?(dict: [String: AnyObject]) {

    // 判斷是否包含姓名
    guard let _ = dict["name"] as? String else {
        printLog("沒有指定姓名")
        return nil
    }
    guard let age = dict["age"] as? Int else {
        printLog("沒有指定年齡")
        return nil
    }

    if age > 100 || age < 0 {
        printLog("年齡不正確")
        return nil
    }

    // Convenience initializer for 'Person' must delegate (with 'self.init') rather than chaining to a superclass initializer (with 'super.init')
    // 遍歷構(gòu)造函數(shù)必須調(diào)用本類的 self.init,而不能調(diào)用父類的 super.init
    self.init()

    printLog(self.classForCoder)

    // Use of 'self' in method call 'setValuesForKeysWithDictionary' before super.init initializes self
    // 使用 self 調(diào)用 setValuesForKeysWithDictionary 之前需要調(diào)用 super.init 方法
    // 只有確保對象已經(jīng)被正確的實例化之后屹徘,才能向?qū)ο蟀l(fā)送消息
    setValuesForKeysWithDictionary(dict)
}

便利構(gòu)造函數(shù)應(yīng)用場景

  • 根據(jù)給定參數(shù)判斷是否創(chuàng)建對象走趋,而不像指定構(gòu)造函數(shù)那樣必須要實例化一個對象出來
  • 在實際開發(fā)中,可以對已有類的構(gòu)造函數(shù)進(jìn)行擴(kuò)展噪伊,利用便利構(gòu)造函數(shù)簿煌,簡化對象的創(chuàng)建
    構(gòu)造函數(shù)小結(jié)
  • 指定構(gòu)造函數(shù)必須調(diào)用其直接父類的的指定構(gòu)造函數(shù)(除非沒有父類)
  • 便利構(gòu)造函數(shù)必須調(diào)用同一類中定義的其他指定構(gòu)造函數(shù)或者用 self. 的方式調(diào)用父類的便利構(gòu)造函數(shù)
  • 便利構(gòu)造函數(shù)可以返回 nil
  • 便利構(gòu)造函數(shù)不能被重載
構(gòu)造函數(shù).png
便利構(gòu)造函數(shù)和析構(gòu)函數(shù).png

懶加載

在 iOS 開發(fā)中典挑,懶加載是無處不在的

  • 懶加載的格式如下
lazy var person: Person = {
    print("懶加載")
    return Person()
}()
  • 懶加載本質(zhì)上是一個閉包
  • 以上代碼可以改寫為以下格式
let personFunc = { () -> Person in
    print("懶加載")
    return Person()
}
lazy var demoPerson: Person = self.personFunc()
  • 懶加載的簡單寫法
lazy var demoPerson: Person = Person()

只讀屬性

  • 在 Swift 中 getter & setter 很少用,以下代碼僅供了解
private var _name: String?
var name: String? {
    get {
        return _name
    }
    set {
        _name = newValue
    }
}

存儲型屬性 & 計算型屬性

  • 存儲型屬性 - 需要開辟空間啦吧,以存儲數(shù)據(jù)
  • 計算型屬性 - 執(zhí)行函數(shù)返回其他內(nèi)存地址
var title: String {
    get {
        return "Mr " + (name ?? "")
    }
}
  • 只實現(xiàn) getter 方法的屬性被稱為計算型屬性您觉,等同于 OC 中的 ReadOnly 屬性
  • 計算型屬性本身不占用內(nèi)存空間
  • 不可以給計算型屬性設(shè)置數(shù)值
  • 計算型屬性可以使用以下代碼簡寫
var title: String {
    return "Mr " + (name ?? "")
}

計算型屬性與懶加載的對比

  • 計算型屬性
    • 不分配獨立的存儲空間保存計算結(jié)果
    • 每次調(diào)用時都會被執(zhí)行
    • 更像一個函數(shù),不過不能接收參數(shù)授滓,同時必須有返回值
var title2: String {
    return "Mr" + (name ?? "")
}
  • 懶加載屬性
    • 在第一次調(diào)用時琳水,執(zhí)行閉包并且分配空間存儲閉包返回的數(shù)值
    • 會分配獨立的存儲空間
    • 與 OC 不同的是,lazy 屬性即使被設(shè)置為 nil 也不會被再次調(diào)用
lazy var title: String = {
    return "Mr " + (self.name ?? "")
}()

網(wǎng)絡(luò)訪問

ATS 應(yīng)用傳輸安全

App Transport Security (ATS) lets an app add a declaration to its Info.plist file that specifies the domains with which it needs secure communication. ATS prevents accidental disclosure, provides secure default behavior, and is easy to adopt. You should adopt ATS as soon as possible, regardless of whether you’re creating a new app or updating an existing one.

If you’re developing a new app, you should use HTTPS exclusively. If you have an existing app, you should use HTTPS as much as you can right now, and create a plan for migrating the rest of your app as soon as possible.

強(qiáng)制訪問

<key>NSAppTransportSecurity</key>
<dict>
  <!--Include to allow all connections (DANGER)-->
  <key>NSAllowsArbitraryLoads</key>
      <true/>
</dict>

設(shè)置白名單

<key>NSAppTransportSecurity</key>
<dict>
    <key>NSExceptionDomains</key>
    <dict>
        <key>localhost</key>
        <dict>
            <key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
            <true/>
        </dict>
    </dict>
</dict>
  • 網(wǎng)絡(luò)訪問代碼
let url = NSURL(string: "http://www.weather.com.cn/data/sk/101010100.html")!

NSURLSession.sharedSession().dataTaskWithURL(url) { (data, _, error) in
    if error != nil {
        print(error)
        return
    }

}.resume()
  • 運(yùn)行提示:App Transport Security has blocked a cleartext HTTP (http://) resource load since it is insecure. Temporary exceptions can be configured via your app's Info.plist file.

  • JSON 序列化

let dict = try! NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions(rawValue: 0))
print(dict)
  • try catch
do {
    let tmpData = "{\"name\": \"zhangsan\"}".dataUsingEncoding(NSUTF8StringEncoding)
    let dict = try NSJSONSerialization.JSONObjectWithData(tmpData!, options: NSJSONReadingOptions[])
    print(dict)
} catch {
    print(error)
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末般堆,一起剝皮案震驚了整個濱河市在孝,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌淮摔,老刑警劉巖私沮,帶你破解...
    沈念sama閱讀 212,383評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異和橙,居然都是意外死亡仔燕,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評論 3 385
  • 文/潘曉璐 我一進(jìn)店門魔招,熙熙樓的掌柜王于貴愁眉苦臉地迎上來晰搀,“玉大人,你說我怎么就攤上這事办斑⊥馑。” “怎么了?”我有些...
    開封第一講書人閱讀 157,852評論 0 348
  • 文/不壞的土叔 我叫張陵乡翅,是天一觀的道長鳞疲。 經(jīng)常有香客問我,道長蠕蚜,這世上最難降的妖魔是什么尚洽? 我笑而不...
    開封第一講書人閱讀 56,621評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮波势,結(jié)果婚禮上翎朱,老公的妹妹穿的比我還像新娘。我一直安慰自己尺铣,他們只是感情好拴曲,可當(dāng)我...
    茶點故事閱讀 65,741評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著凛忿,像睡著了一般澈灼。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,929評論 1 290
  • 那天叁熔,我揣著相機(jī)與錄音委乌,去河邊找鬼。 笑死荣回,一個胖子當(dāng)著我的面吹牛遭贸,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播心软,決...
    沈念sama閱讀 39,076評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼壕吹,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了删铃?” 一聲冷哼從身側(cè)響起耳贬,我...
    開封第一講書人閱讀 37,803評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎猎唁,沒想到半個月后咒劲,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,265評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡诫隅,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,582評論 2 327
  • 正文 我和宋清朗相戀三年腐魂,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片阎肝。...
    茶點故事閱讀 38,716評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡挤渔,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出风题,到底是詐尸還是另有隱情,我是刑警寧澤嫉父,帶...
    沈念sama閱讀 34,395評論 4 333
  • 正文 年R本政府宣布沛硅,位于F島的核電站,受9級特大地震影響绕辖,放射性物質(zhì)發(fā)生泄漏摇肌。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 40,039評論 3 316
  • 文/蒙蒙 一仪际、第九天 我趴在偏房一處隱蔽的房頂上張望围小。 院中可真熱鬧,春花似錦树碱、人聲如沸肯适。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽框舔。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間刘绣,已是汗流浹背樱溉。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留纬凤,地道東北人福贞。 一個月前我還...
    沈念sama閱讀 46,488評論 2 361
  • 正文 我出身青樓,卻偏偏與公主長得像停士,于是被迫代替她去往敵國和親肚医。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,612評論 2 350

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

  • Hello Word 在屏幕上打印“Hello, world”向瓷,可以用一行代碼實現(xiàn): 你不需要為了輸入輸出或者字符...
    restkuan閱讀 3,171評論 0 6
  • importUIKit classViewController:UITabBarController{ enumD...
    明哥_Young閱讀 3,784評論 1 10
  • 前言 人生苦多肠套,快來 Kotlin ,快速學(xué)習(xí)Kotlin猖任! 什么是Kotlin你稚? Kotlin 是種靜態(tài)類型編程...
    任半生囂狂閱讀 26,172評論 9 118
  • 123.繼承 一個類可以從另外一個類繼承方法,屬性和其他特征。當(dāng)一個類繼承另外一個類時, 繼承類叫子類, 被繼承的...
    無灃閱讀 1,385評論 2 4
  • 窗前點滴碎晨霞朱躺,似水化冰半迷離刁赖; 楊柳不見歌舞衣,樓宇哀髯濕難消长搀。 路上行人愁泥濘宇弛,孩童嘻笑游戲頑; 凝視一地水中...
    大紅羊閱讀 291評論 10 23