Swift項(xiàng)目新浪微博

第一節(jié)

《The Swift Programming Language》

http://numbbbbb.gitbooks.io/-the-swift-programming-language-/參考資料

if分支語(yǔ)句

  • 和OC中if語(yǔ)句有一定的區(qū)別
    • 判斷句可以不加()
    • 在Swift的判斷句中必須有明確的真假
      • 不再有非0即真
      • 必須有明確的Bool值
      • Bool有兩個(gè)取值:false/true

guard的使用

  • guard是Swift2.0新增的語(yǔ)法
  • 它與if語(yǔ)句非常類(lèi)似瓷耙,它設(shè)計(jì)的目的是提高程序的可讀性
  • guard語(yǔ)句必須帶有else語(yǔ)句播瞳,它的語(yǔ)法如下:
    • 當(dāng)條件表達(dá)式為true時(shí)候跳過(guò)else語(yǔ)句中的內(nèi)容,執(zhí)行語(yǔ)句組內(nèi)容
    • 條件表達(dá)式為false時(shí)候執(zhí)行else語(yǔ)句中的內(nèi)容冶伞,跳轉(zhuǎn)語(yǔ)句一般是return系任、break恳蹲、continue和throw
* guard 條件表達(dá)式 else {
*     // 條換語(yǔ)句
*     break
* }
* 語(yǔ)句組

注意:guard必須用在函數(shù)中

switch分支

  • switch的簡(jiǎn)單使用
    • 基本用法和OC用法一致
    • 不同之處:
      • switch后可以不跟()
      • case后可以不跟break(默認(rèn)會(huì)有break)
      • 一個(gè)case判斷中,可以判斷多個(gè)值,多個(gè)值以","隔開(kāi)
      • 如果希望出現(xiàn)之前的case穿透,則可以使用關(guān)鍵字fallthrough
      • 浮點(diǎn)型的switch判斷
      • case后面的判斷支持字符串類(lèi)型
      • case后面支持區(qū)間判斷

while和do while循環(huán)

  • while循環(huán)
    • while的判斷句必須有正確的真假,沒(méi)有非0即真
    • while后面的()可以省略
  • do while循環(huán)
    • 使用repeat關(guān)鍵字來(lái)代替了do
在swift3.0中取消了傳統(tǒng)的for循壞

for循環(huán)

在swift3.0中取消了傳統(tǒng)的for循壞
那么我們?nèi)绻趕wift中范旭遍歷

for i in (0..<10).reverse(){
         print(i)
}

字符串

  • OC和Swift中字符串的區(qū)別

    • 在OC中字符串類(lèi)型時(shí)NSString,在Swift中字符串類(lèi)型是String
    • OC中字符串@"",Swift中字符串""
  • 使用 String 的原因

    • String 是一個(gè)結(jié)構(gòu)體,性能更高
    • NSString 是一個(gè) OC 對(duì)象俩滥,性能略差
    • String 支持直接遍歷
    • Swift 提供了 String 和 NSString 之間的無(wú)縫轉(zhuǎn)換
  • 字符串的格式化
  • 比如時(shí)間:03:04
let min = 3
let second = 4

let time = String(format: "%02d:%02d", arguments: [min, second])
  • 字符串的截取
    • Swift中提供了特殊的截取方式
      • 該方式非常麻煩
      • Index創(chuàng)建較為麻煩
    • 簡(jiǎn)單的方式是將String轉(zhuǎn)成NSString來(lái)使用
      • 在標(biāo)識(shí)符后加:as NSString即可

數(shù)組

  • 數(shù)組的遍歷
    區(qū)別OC多個(gè)一個(gè)區(qū)間遍歷
// 設(shè)置遍歷的區(qū)間
for item in array[0..<2] {
    print(item)
}
  • 數(shù)組的合并
  • 只要相同類(lèi)型類(lèi)型的數(shù)組就可以合并
var array = ["why", "lmj","lnj"]
var array1 = ["yz", "wsz"]
var array2 = array + array1;

字典

字典跟數(shù)組一樣也是一個(gè)泛型集合
字典的遍歷

// 遍歷字典中所有的值
for value in dict.values {
    print(value)
}
// 遍歷字典中所有的鍵
for key in dict.keys {
    print(key)
}

// 遍歷所有的鍵值對(duì)
for (key, value) in dict {
    print(key)
    print(value)
}

元組

  • 組成元組類(lèi)型的數(shù)據(jù)可以稱(chēng)為“元素”

元組的簡(jiǎn)單使用

let error = (404, "Not Found")
print(error.0)
print(error.1)

// 寫(xiě)法二:
let error = (errorCode : 404, errorInfo : "Not Found")
print(error.errorCode)
print(error.errorInfo)

// 寫(xiě)法三:
let (errorCode, errorIno) = (404, "Not Found")
print(errorCode)
print(errorIno)

可選類(lèi)型

  • 概念:

    • 在OC開(kāi)發(fā)中,如果一個(gè)變量暫停不使用,可以賦值為0(基本屬性類(lèi)型)或者賦值為空(對(duì)象類(lèi)型)
    • 在swift開(kāi)發(fā)中,nil也是一個(gè)特殊的類(lèi)型.因?yàn)楹驼鎸?shí)的類(lèi)型不匹配是不能賦值的(swift是強(qiáng)類(lèi)型語(yǔ)言)
    • 但是開(kāi)發(fā)中賦值nil,在所難免.因此推出了可選類(lèi)型
  • 可選類(lèi)型的取值:

    • 空值
    • 有值
  • 定義可選類(lèi)型

let name : Optional<String> = nil

// 寫(xiě)法二:定義可選類(lèi)型,語(yǔ)法糖(常用)
let name : String? = nil

可選綁定

//原理:首先判斷等號(hào)左邊的值是否為空,如果為空就不執(zhí)行大括號(hào)內(nèi)的代碼,如果不為空那么會(huì)把值賦值給等號(hào)后邊,然后執(zhí)行大括號(hào)內(nèi)的代碼
if let str = string {
    print(str)
}
//可選類(lèi)型+可選綁定讓我們的swift代碼更加嚴(yán)謹(jǐn)

函數(shù)的使用注意

  • 1.注意點(diǎn):外部參數(shù)和內(nèi)部參數(shù)

    • 在函數(shù)內(nèi)部可以看到的參數(shù),就是內(nèi)部參數(shù)
    • 在函數(shù)外面可以看到的參數(shù),就是外部參數(shù)
    • 默認(rèn)情況下,從第二個(gè)參數(shù)開(kāi)始,參數(shù)名稱(chēng)既是內(nèi)部參數(shù)也是外部參數(shù)
    • 如果第一個(gè)參數(shù)也想要有外部參數(shù),可以設(shè)置標(biāo)簽:在變量名前加標(biāo)簽即可
    • 如果不想要外部參數(shù),可以在參數(shù)名稱(chēng)前加_
  • 2.注意: 默認(rèn)參數(shù)
    • 某些情況,如果沒(méi)有傳入具體的參數(shù),可以使用默認(rèn)參數(shù)
func makecoffee(type :String = "卡布奇諾") -> String {
    return "制作一杯\(type)咖啡嘉蕾。"
}

let coffee1 = makecoffee("拿鐵")
let coffee2 = makecoffee()
  • 3.注意: 可變參數(shù)
    • swift中函數(shù)的參數(shù)個(gè)數(shù)可以變化,它可以接受不確定數(shù)量的輸入類(lèi)型參數(shù)
    • 它們必須具有相同的類(lèi)型
    • 我們可以通過(guò)在參數(shù)類(lèi)型名后面加入(...)的方式來(lái)指示這是可變參數(shù)
func sum(numbers:Double...) -> Double {
    var total: Double = 0
    for number in numbers {
        total += number
    }
    return total
}
//其實(shí)可變參數(shù),相當(dāng)于數(shù)組

sum(100.0, 20, 30)
sum(30, 80)
  • 4注意: 引用類(lèi)型(指針的傳遞)
    • 默認(rèn)情況下,函數(shù)的參數(shù)是值傳遞.如果想改變外面的變量,則需要傳遞變量的地址
    • 必須是變量,因?yàn)樾枰趦?nèi)部改變其值
    • Swift提供的inout關(guān)鍵字就可以實(shí)現(xiàn)
指針的傳遞
func swap1(inout a : Int, inout b : Int) {
    let temp = a
    a = b
    b = temp

    print("a:\(a), b:\(b)")
}

swap1(&a, b: &b)
print("a:\(a), b:\(b)")
  • 5.注意: 函數(shù)的嵌套使用
    • swift中函數(shù)可以嵌套使用
    • 即函數(shù)中包含函數(shù),但是不推薦該寫(xiě)法

Swift中類(lèi)的使用

  • Swift中類(lèi)的屬性有多種

    • 存儲(chǔ)屬性:存儲(chǔ)實(shí)例的常量和變量
    • 計(jì)算屬性:通過(guò)某種方式計(jì)算出來(lái)的屬性
    • 類(lèi)屬性:與整個(gè)類(lèi)自身相關(guān)的屬性
  • 類(lèi)屬性是與類(lèi)相關(guān)聯(lián)的霜旧,而不是與類(lèi)的實(shí)例相關(guān)聯(lián)

  • 所有的類(lèi)和實(shí)例都共有一份類(lèi)屬性.因此在某一處修改之后,該類(lèi)屬性就會(huì)被修改

  • 類(lèi)屬性的設(shè)置和修改,需要通過(guò)類(lèi)來(lái)完成

  • 下面是類(lèi)屬性的寫(xiě)法

    • 類(lèi)屬性使用static來(lái)修飾

監(jiān)聽(tīng)屬性的變化

  • 區(qū)別oc代碼,如果在oc代碼中藥監(jiān)聽(tīng)摸一個(gè)屬性的變化我們一般重寫(xiě)set的方法
  • 我們通過(guò)設(shè)置以下觀察方法來(lái)定義觀察者
    • willSet:在屬性值被存儲(chǔ)之前設(shè)置错忱。此時(shí)新屬性值作為一個(gè)常量參數(shù)被傳入。該參數(shù)名默認(rèn)為newValue挂据,我們可以自己定義該參數(shù)名
    • didSet:在新屬性值被存儲(chǔ)后立即調(diào)用以清。與willSet相同,此時(shí)傳入的是屬性的舊值崎逃,默認(rèn)參數(shù)名為oldValue
    • willSet與didSet只有在屬性第一次被設(shè)置時(shí)才會(huì)調(diào)用掷倔,在初始化時(shí),不會(huì)去調(diào)用這些監(jiān)聽(tīng)方法

類(lèi)的構(gòu)造函數(shù)

  • 真實(shí)創(chuàng)建對(duì)象時(shí),更多的是將字典轉(zhuǎn)成模型
  • 注意:
    • 去字典中取出的是NSObject,任意類(lèi)型.
    • 可以通過(guò)as!轉(zhuǎn)成需要的類(lèi)型,再賦值(不可以直接賦值)
    • KVC并不能保證會(huì)給所有的屬性賦值
    • 因此屬性需要有默認(rèn)值
class Person: NSObject {
    // 結(jié)構(gòu)體或者類(lèi)的類(lèi)型,必須是可選類(lèi)型.因?yàn)椴荒鼙WC一定會(huì)賦值
    var name : String?

    // 基本數(shù)據(jù)類(lèi)型不能是可選類(lèi)型,否則KVC無(wú)法轉(zhuǎn)化
    var age : Int = 0

    // 自定義構(gòu)造函數(shù),會(huì)覆蓋init()函數(shù)
    init(dict : [String : NSObject]) {
        // 必須先初始化對(duì)象
        super.init()

        // 調(diào)用對(duì)象的KVC方法字典轉(zhuǎn)模型
        setValuesForKeysWithDictionary(dict)
    }
}

// 創(chuàng)建一個(gè)Person對(duì)象
let dict = ["name" : "why", "age" : 18]
let p = Person(dict: dict)

OC中Block的復(fù)習(xí)

block的寫(xiě)法:
    類(lèi)型:
    返回值(^block的名稱(chēng))(block的參數(shù))

    值:
    ^(參數(shù)列表) {
        // 執(zhí)行的代碼
    };

閉包

  • Swift中的閉包是一個(gè)特殊的函數(shù)
  • 閉包的寫(xiě)法
閉包的寫(xiě)法:
    類(lèi)型:(形參列表)->(返回值)
    技巧:初學(xué)者定義閉包類(lèi)型,直接寫(xiě)()->().再填充參數(shù)和返回值

    值:
    {
        (形參) -> 返回值類(lèi)型 in
        // 執(zhí)行代碼
    }
  • 尾隨閉包寫(xiě)法:
    • 如果閉包是函數(shù)的最后一個(gè)參數(shù),則可以將閉包寫(xiě)在()后面
    • 如果函數(shù)只有一個(gè)參數(shù),并且這個(gè)參數(shù)是閉包,那么()可以不寫(xiě)
    // 開(kāi)發(fā)中建議該寫(xiě)法
    httpTool.loadRequest {
        print("回到主線程", NSThread.currentThread());
    }

閉包的循壞引用

  • swift中解決循環(huán)引用的方式
  • 方案一:
    • 使用weak,對(duì)當(dāng)前控制器使用弱引用
    • 但是因?yàn)閟elf可能有值也可能沒(méi)有值,因此weakSelf是一個(gè)可選類(lèi)型,在真正使用時(shí)可以對(duì)其強(qiáng)制解包(該處強(qiáng)制解包沒(méi)有問(wèn)題,因?yàn)榭刂破饕欢ù嬖?否則無(wú)法調(diào)用所在函數(shù))
  • 方案二:(常用方法)
    • 和方案一類(lèi)型,只是書(shū)寫(xiě)方式更加簡(jiǎn)單
    • 可以寫(xiě)在閉包中,并且在閉包中用到的self都是弱引用
    httpTool.loadData {[weak self] () -> () in
        print("加載數(shù)據(jù)完成,更新界面:", NSThread.currentThread())
        self!.view.backgroundColor = UIColor.redColor()
    }
  • 方案三:(常用)
    • 使用關(guān)鍵字unowned
    • 從行為上來(lái)說(shuō) unowned 更像OC中的 unsafe_unretained
    • unowned 表示:即使它原來(lái)引用的對(duì)象被釋放了个绍,仍然會(huì)保持對(duì)被已經(jīng)釋放了的對(duì)象的一個(gè) "無(wú)效的" 引用勒葱,它不能是 Optional 值,也不會(huì)被指向 nil
httpTool.loadData {[unowned self] () -> () in
        print("加載數(shù)據(jù)完成,更新界面:", NSThread.currentThread())
        self.view.backgroundColor = UIColor.redColor()
    }

懶加載

  • 懶加載的介紹
    • swift中也有懶加載的方式
    • (蘋(píng)果的設(shè)計(jì)思想:希望所有的對(duì)象在使用時(shí)才真正加載到內(nèi)存中)
    • 和OC不同的是swift有專(zhuān)門(mén)的關(guān)鍵字來(lái)實(shí)現(xiàn)懶加載
    // 懶加載的本質(zhì)是,在第一次使用的時(shí)候執(zhí)行閉包,將閉包的返回值賦值給屬性
    // lazy的作用是只會(huì)賦值一次
    lazy var array : [String] = {
        () -> [String] in
        return ["why", "lmj", "lnj"]
    }()

第二節(jié)

通過(guò)json動(dòng)態(tài)創(chuàng)建控制器

override func viewDidLoad() {
        super.viewDidLoad()

        // 1.加載json中的數(shù)據(jù)
        // 1.1.獲取路徑
        let path = NSBundle.mainBundle().pathForResource("MainVCSettings.json", ofType: nil)
        // 1.2.加載數(shù)據(jù)
        guard let data = NSData(contentsOfFile: path!) else {
            XMGLog("沒(méi)有獲取到j(luò)son數(shù)據(jù)")
            addChildViewController()
            return
        }

        // 1.3.通過(guò)序列化獲取內(nèi)容
        guard let childVcArray = try? NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers) as! [[String : AnyObject]] else {
            print("沒(méi)有獲取到值")
            addChildViewController()
            return
        }

        // 1.4.遍歷數(shù)組,并且創(chuàng)建控制器
        for dict in childVcArray {
            // 1.取出類(lèi)名稱(chēng)
            let vcName = dict["vcName"] as! String

            // 2.取出標(biāo)題
            let title = dict["title"] as! String

            // 3.取出圖標(biāo)名稱(chēng)
            let imageName = dict["imageName"] as! String

            // 4.創(chuàng)建控制器
            addChildViewController(vcName, imageName: imageName, title: title)
        }
    }

    private func addChildViewController() {
        self.addChildViewController("HomeViewController", imageName: "tabbar_home", title: "主頁(yè)")
        self.addChildViewController("MessageViewController", imageName: "tabbar_message_center", title: "消息")
        self.addChildViewController("DiscoverViewController", imageName: "tabbar_discover", title: "廣場(chǎng)")
        self.addChildViewController("ProfileViewController", imageName: "tabbar_profile", title: "我")
    }

    private func addChildViewController(childCVcName: String, imageName : String, title : String) {

        // 0.獲取命名空間
        guard let executable = NSBundle.mainBundle().infoDictionary!["CFBundleExecutable"] as? String else {
            XMGLog("沒(méi)有命名空間")
            return
        }

        // 1.獲取對(duì)應(yīng)的類(lèi)
        guard let childVcClass : AnyClass = NSClassFromString(executable + "." + childCVcName) else {
            XMGLog("轉(zhuǎn)成對(duì)應(yīng)的類(lèi)失敗")
            return
        }

        // 2.拿到對(duì)應(yīng)的類(lèi)
        let childClass = childVcClass as! UITableViewController.Type
        let childVc = childClass.init()

        // 3.創(chuàng)建自控制器
        let homeNav = UINavigationController(rootViewController: childVc)

        // 4.設(shè)置標(biāo)題
        childVc.title = title
        childVc.tabBarItem.selectedImage = UIImage(named: imageName + "_highlighted")
        childVc.tabBarItem.image = UIImage(named: imageName)

        // 5.添加到UITabbarController
        self.addChildViewController(homeNav)
    }

Swift的異常處理

  • 如果在調(diào)用系統(tǒng)某一個(gè)方法時(shí),該方法最后有一個(gè)throws.說(shuō)明該方法會(huì)拋出異常.如果一個(gè)方法會(huì)拋出異常,那么需要對(duì)該異常進(jìn)行處理

  • 在swift中提供三種處理異常的方式

方式一:try方式 程序員手動(dòng)捕捉異常
                do {
                    try NSJSONSerialization.JSONObjectWithData(jsonData, options: .MutableContainers)
                } catch {
                    // error異常的對(duì)象
                    print(error)
                }
        
            方式二:try?方式(常用方式) 系統(tǒng)幫助我們處理異常,如果該方法出現(xiàn)了異常,則該方法返回nil.如果沒(méi)有異常,則返回對(duì)應(yīng)的對(duì)象
                guard let anyObject = try? NSJSONSerialization.JSONObjectWithData(jsonData, options: .MutableContainers) else {
                    return
                }
            
            方式三:try!方法(不建議,非常危險(xiǎn)) 直接告訴系統(tǒng),該方法沒(méi)有異常.注意:如果該方法出現(xiàn)了異常,那么程序會(huì)報(bào)錯(cuò)(崩潰)
                let anyObject = try! NSJSONSerialization.JSONObjectWithData(jsonData, options: .MutableContainers)

遍歷構(gòu)造函數(shù)

   convenience : 便利,使用convenience修飾的構(gòu)造函數(shù)叫做便利構(gòu)造函數(shù)
     遍歷構(gòu)造函數(shù)通常用在對(duì)系統(tǒng)的類(lèi)進(jìn)行構(gòu)造函數(shù)的擴(kuò)充時(shí)使用
    /*
     遍歷構(gòu)造函數(shù)的特點(diǎn)
        1.遍歷構(gòu)造函數(shù)通常都是寫(xiě)在extension里面
        2.遍歷構(gòu)造函數(shù)init前面需要加載convenience
        3.在遍歷構(gòu)造函數(shù)中需要明確的調(diào)用self.init()
     */

時(shí)間監(jiān)聽(tīng)的本質(zhì)

    // 事件監(jiān)聽(tīng)本質(zhì)發(fā)送消息.但是發(fā)送消息是OC的特性
    // 將方法包裝成@SEL --> 類(lèi)中查找方法列表 --> 根據(jù)@SEL找到imp指針(函數(shù)指針) --> 執(zhí)行函數(shù)
    // 如果swift中將一個(gè)函數(shù)聲明稱(chēng)private,那么該函數(shù)不會(huì)被添加到方法列表中
    // 如果在private前面加上@objc,那么該方法依然會(huì)被添加到方法列表中

重寫(xiě)init

swift中規(guī)定:重寫(xiě)控件的init(frame方法)或者init()方法,必須重寫(xiě)init?(coder aDecoder: NSCoder)

modal一個(gè)控制器

modal一個(gè)控制器,默認(rèn)之前的控制器被移除,如果不想被移除,需要設(shè)置

popoverVc.modalPresentationStyle = .custom

第三課

請(qǐng)求授權(quán)的材料

App Key:3102179627
App Secret:c6663f645ea9ee709e7368a13edb36c9
授權(quán)回調(diào)頁(yè):http://www.baidu.com
取消授權(quán)回調(diào)頁(yè):http://www.baidu.com

請(qǐng)求地址
https://api.weibo.com/oauth2/authorize?client_id=3102179627&redirect_uri=http://www.baidu.com

服務(wù)器返回的code
code=6a10e36850c396efa921be8a38bc47b8

AFN使用常見(jiàn)錯(cuò)誤

  • AFN 訪問(wèn)方法最常見(jiàn)的錯(cuò)誤
status code == 200巴柿,但是提示 unacceptable content-type凛虽,表示網(wǎng)絡(luò)訪問(wèn)正常,但是無(wú)法對(duì)返回?cái)?shù)據(jù)做反序列化
解決辦法:增加 反序列化數(shù)據(jù) 格式
另外一個(gè)常見(jiàn)錯(cuò)誤
status code == 405广恢,不支持的網(wǎng)絡(luò)請(qǐng)求方法凯旋,檢查 GET / POST 是否寫(xiě)錯(cuò)

SnapKit框架替代Masonry框架

第四課

屬性監(jiān)聽(tīng)器didSet中如果在init的構(gòu)造函數(shù)中監(jiān)聽(tīng)某個(gè)值無(wú)效,謹(jǐn)記

巨坑


accout.screen_name = userInfoDict["screen_name"] as? String
accout.avatar_large = userInfoDict["avatar_large"] as? String           
NSKeyedArchiver.archiveRootObject(accout, toFile: UserAccountViewModel.shareInstance.accountPath)
            
UserAccountViewModel.shareInstance.account = accout

swift4.0中字典轉(zhuǎn)模型不要再用kvc,謹(jǐn)記

MVVM的簡(jiǎn)介

  • MVVM 是 Model-View-ViewModel 的簡(jiǎn)寫(xiě),MVVM 模式和 MVC 模式一樣钉迷,主要目的是分離視圖(View)和模型(Model)

  • MVC 存在的問(wèn)題

    • 模型的代碼很少
    • 控制器的代碼一不小心就越來(lái)越多
    • 不好測(cè)試
  • MVVM 概念

    • 在 MVVM 中至非,view 和 view controller 正式聯(lián)系在一起,我們把它們視為一個(gè)組件
    • view 和 view controller 都不能直接引用 model糠聪,而是引用視圖模型
    • view model 是一個(gè)放置用戶輸入驗(yàn)證邏輯睡蟋,視圖顯示邏輯,發(fā)起網(wǎng)絡(luò)請(qǐng)求和其他代碼
    • 15184301235885.png
  • MVVM 使用注意事項(xiàng)
    • view 引用 view model枷颊,但反過(guò)來(lái)不行
    • view model 引用了 model,但反過(guò)來(lái)不行
    • 如果我們破壞了這些規(guī)則,便無(wú)法正確地使用 MVVM

微博中發(fā)布時(shí)間的處理代碼

class func createTimeString(dateString : String) -> String {
        // 1.創(chuàng)建dateFmt對(duì)時(shí)間進(jìn)行格式化
        let fmt = NSDateFormatter()
        fmt.dateFormat = "EEE MM dd HH:mm:ss Z yyyy"
        fmt.locale = NSLocale(localeIdentifier: "en")

        // 2.將字符串轉(zhuǎn)成時(shí)間
        guard let createDate = fmt.dateFromString(dateString) else {
            return ""
        }

        // 3.獲取當(dāng)前時(shí)間
        let nowDate = NSDate()

        // 4.比較兩個(gè)時(shí)間差
        let interval = Int(nowDate.timeIntervalSinceDate(createDate))

        // 5.根據(jù)時(shí)間差,計(jì)算要顯示的字符串
        // 5.1.1分鐘內(nèi):剛剛
        if interval < 60 {
            return "剛剛"
        }

        // 5.2.1小時(shí)內(nèi):15分鐘前
        if interval < 60 * 60 {
            return "\(interval / 60)分鐘前"
        }

        // 5.3.1天內(nèi):3小時(shí)前
        if interval < 60 * 60 * 24 {
            return "\(interval / (60 * 60))小時(shí)前"
        }

        let calendar = NSCalendar.currentCalendar()
        // 5.4.昨天: 昨天 03:24
        if calendar.isDateInYesterday(createDate) {

            fmt.dateFormat = "HH:mm"
            return "昨天 \(fmt.stringFromDate(createDate))"
        }

        // 5.5.一年內(nèi): 02-23 03:24
        let comps =  calendar.components(.Year, fromDate: createDate, toDate: nowDate, options: [])
        if comps.year < 1 {
            fmt.dateFormat = "MM-dd HH:mm"
            return fmt.stringFromDate(createDate)
        }

        // 5.6.一年后: 2015-2-23 03:23
        if comps.year >= 1 {
            fmt.dateFormat = "yyyy-MM-dd HH:mm"
            return fmt.stringFromDate(createDate)
        }

        return ""
    }

歸檔 & 解檔的復(fù)習(xí)

歸檔和解檔是用來(lái)保存OC對(duì)象,OC對(duì)象要進(jìn)行歸檔和解檔的話對(duì)象必須遵守NScoding協(xié)議,然后實(shí)現(xiàn)協(xié)議方法

// MARK: - 歸檔 & 解檔
/// 歸檔 -> 將當(dāng)前對(duì)象歸檔保存至二進(jìn)制文件之前被調(diào)用
///
/// - parameter aCoder: 編碼器
func encodeWithCoder(aCoder: NSCoder) {
    aCoder.encodeObject(access_token, forKey: "access_token")
    aCoder.encodeObject(expiresDate, forKey: "expiresDate")
    aCoder.encodeObject(uid, forKey: "uid")
    aCoder.encodeObject(screen_name, forKey: "screen_name")
    aCoder.encodeObject(avatar_large, forKey: "avatar_large")
}

/// 解檔 -> 從二進(jìn)制文件恢復(fù)成對(duì)象時(shí)調(diào)用夭苗,與網(wǎng)絡(luò)的反序列化功能類(lèi)似
///
/// - parameter aDecoder: 解碼器
///
/// - returns: 用戶賬戶對(duì)象
required init?(coder aDecoder: NSCoder) {
    access_token = aDecoder.decodeObjectForKey("access_token") as? String
    expiresDate = aDecoder.decodeObjectForKey("expiresDate") as? NSDate
    uid = aDecoder.decodeObjectForKey("uid") as? String
    screen_name = aDecoder.decodeObjectForKey("screen_name") as? String
    avatar_large = aDecoder.decodeObjectForKey("avatar_large") as? String
}
  • 實(shí)現(xiàn)將當(dāng)前對(duì)象歸檔保存的函數(shù)
/// 將當(dāng)前對(duì)象保存至沙盒
func saveUserAccount() {
    var path = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true).last!
    path = (path as NSString).stringByAppendingPathComponent("account.plist")

    print(path)

    NSKeyedArchiver.archiveRootObject(self, toFile: path)
}
  • 調(diào)用歸檔使用 NSKeyedArchiver
  • 調(diào)用解檔使用 NSKeyedUnarchiver

第五課

在新浪項(xiàng)目的視圖模型中處理配圖數(shù)據(jù)

    if let picURLDicts = status.pic_urls{
            for picURLDict in picURLDicts{
                guard let picURLString = picURLDict["thumbnail_pic"] else{
                    continue
                }
                picURLs.append(NSURL(string: picURLString)!)
            }
        }

單張配圖的展示

因?yàn)樾吕说姆祷財(cái)?shù)據(jù)中沒(méi)有圖片的寬高,所以我們要獲取單張配圖的寬高,需要先緩存圖片

計(jì)算cellHeight

在開(kāi)發(fā)中我們可以使用自動(dòng)布局,讓cell中的所有空間自動(dòng)計(jì)算高度,只要在tableView中設(shè)置

       self.tableView.rowHeight = UITableViewAutomaticDimension
        self.tableView.estimatedRowHeight = 200;
        還需要設(shè)置cell最底部的控件距離cell的底部固定間距

也可以在viewModel模型中設(shè)置一個(gè)cellHeight屬性
在tableView中設(shè)置

self.tableView.estimatedRowHeight = 200;
如果在tableview中設(shè)置估算高度,那么tableview加載的時(shí)候會(huì)首先加載數(shù)據(jù)源方法,在數(shù)據(jù)源方法中會(huì)調(diào)用uitableviewCell,我們可以在cell中setModel屬性計(jì)算屬性,再保存到模型的cellHeight當(dāng)中

在項(xiàng)目中集成MJRefresh

在項(xiàng)目開(kāi)始加載首頁(yè)時(shí)進(jìn)入下拉加載最新數(shù)據(jù)
在reloadData后面停止刷新

            self.tableView.reloadData()
            
            self.tableView.mj_header.endRefreshing()
            self.tableView.mj_footer.endRefreshing()

第六課

通知的使用

在Swift3.0以后通知的改變

注冊(cè)通知

NotificationCenter.default.post(name: NSNotification.Name(rawValue: "AuthSuccessNotification"), object: nil)

監(jiān)聽(tīng)通知

NotificationCenter.default.addObserver(self, selector:#selector(ViewController.pageJump), name: NSNotification.Name(rawValue: "AuthSuccessNotification"), object: nil)

銷(xiāo)毀通知

deinit {
        NotificationCenter.default.removeObserver(self)
}

加載表情的視圖模型

15195472525419.png

第七課

圖文混排

let attStr = NSAttributedString(string: "陳栐齊", attributes: [NSAttributedStringKey.foregroundColor : UIColor.orange])
        
        let attstr1 = NSAttributedString(string: "陳恒均", attributes: [NSAttributedStringKey.foregroundColor : UIColor.red])
        
        //圖文混排
        
        let attachment = NSTextAttachment()
        attachment.image = UIImage(named: "compose_emotion_delete")
        let font = textView.font
        attachment.bounds = CGRect(x: 0, y: -4, width: (font?.lineHeight)!, height: (font?.lineHeight)!)
        
        
        let attrImageStr = NSAttributedString(attachment: attachment)
        
        let attrMStr = NSMutableAttributedString()
        attrMStr.append(attStr)
        attrMStr.append(attrImageStr)
        attrMStr.append(attstr1)
        
        textView.attributedText = attrMStr

AFN常見(jiàn)錯(cuò)誤

請(qǐng)求失敗-Error Domain=com.alamofire.error.serialization.response Code=-1011 "Request failed: bad request (400)" UserInfo={com.alamofire.serialization.response.error.response=<NSHTTPURLResponse: 0x7cec30d0> { URL: https://api.weibo.com/oauth2/access_token } { status code: 400, headers {
  • 檢查URL里面的錯(cuò)誤信卡。400錯(cuò)誤請(qǐng)求錯(cuò)誤最常見(jiàn)的原因是由于URL輸入錯(cuò)誤或點(diǎn)擊的鏈接指向一個(gè)URL和一種特定的錯(cuò)誤,比如語(yǔ)法問(wèn)題。
  • 重點(diǎn):這是最可能出現(xiàn)的問(wèn)題如果你得到一個(gè)400錯(cuò)誤請(qǐng)求錯(cuò)誤题造。尤其傍菇,檢查在URL中一些典型的字符,比如%字符界赔。像%字符在一些地方能夠被有效使用,你不會(huì)在標(biāo)準(zhǔn)URL中就發(fā)現(xiàn)一個(gè)丢习。

正則表達(dá)式

http://www.cnblogs.com/zxin/archive/2013/01/26/2877765.html

let str = "sdadsadsadsad1233122"
        
        let pattern = "^1[3578]\\d{9}$"
        
        guard let regex = try? NSRegularExpression(pattern: pattern, options: []) else{
            return
        }
        
        let results = regex.matches(in: str, options: [], range: NSRange(location: 0, length: str.characters.count))
        
        for result in results {
            print((str as NSString).substring(with: result.range))
            print(result.range)
        }

for循環(huán)swift3.0的改變

倒序遍歷

for i in (0...10).reversed() {  
    print(i)  
} 
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市淮悼,隨后出現(xiàn)的幾起案子咐低,更是在濱河造成了極大的恐慌,老刑警劉巖袜腥,帶你破解...
    沈念sama閱讀 218,682評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件见擦,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡羹令,警方通過(guò)查閱死者的電腦和手機(jī)鲤屡,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)福侈,“玉大人酒来,你說(shuō)我怎么就攤上這事》玖荩” “怎么了堰汉?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,083評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)显拜。 經(jīng)常有香客問(wèn)我衡奥,道長(zhǎng),這世上最難降的妖魔是什么远荠? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,763評(píng)論 1 295
  • 正文 為了忘掉前任矮固,我火速辦了婚禮,結(jié)果婚禮上譬淳,老公的妹妹穿的比我還像新娘档址。我一直安慰自己,他們只是感情好邻梆,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,785評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布守伸。 她就那樣靜靜地躺著,像睡著了一般浦妄。 火紅的嫁衣襯著肌膚如雪尼摹。 梳的紋絲不亂的頭發(fā)上见芹,一...
    開(kāi)封第一講書(shū)人閱讀 51,624評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音蠢涝,去河邊找鬼玄呛。 笑死,一個(gè)胖子當(dāng)著我的面吹牛和二,可吹牛的內(nèi)容都是我干的徘铝。 我是一名探鬼主播,決...
    沈念sama閱讀 40,358評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼惯吕,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼惕它!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起废登,我...
    開(kāi)封第一講書(shū)人閱讀 39,261評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤淹魄,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后钳宪,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體揭北,經(jīng)...
    沈念sama閱讀 45,722評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年吏颖,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了搔体。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,030評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡半醉,死狀恐怖疚俱,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情缩多,我是刑警寧澤呆奕,帶...
    沈念sama閱讀 35,737評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站衬吆,受9級(jí)特大地震影響梁钾,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜逊抡,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,360評(píng)論 3 330
  • 文/蒙蒙 一姆泻、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧冒嫡,春花似錦拇勃、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,941評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至蟀架,卻和暖如春瓣赂,著一層夾襖步出監(jiān)牢的瞬間榆骚,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,057評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工钩述, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留寨躁,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,237評(píng)論 3 371
  • 正文 我出身青樓牙勘,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親所禀。 傳聞我的和親對(duì)象是個(gè)殘疾皇子方面,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,976評(píng)論 2 355

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

  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫(kù)、插件色徘、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,105評(píng)論 4 62
  • 參考資源《swifter》https://github.com/iOS-Swift-Developers/Swif...
    柯浩然閱讀 1,449評(píng)論 0 6
  • 題記:離人遠(yuǎn)去萬(wàn)重山夢(mèng)里依稀回江南吟醉寒宵恨花殘歌泣露塵負(fù)紅顏 望海潮?離夢(mèng)吟歌 霽霞青岸恭金,雙飛歸燕,依荷倚渡韶年...
    穿越者木易君閱讀 797評(píng)論 27 45
  • “陌哥哥褂策,子越哥哥横腿,我們?cè)趺催^(guò)去?這湖中居在湖中央斤寂,而且有陣法保護(hù)耿焊。” 蕭蓉苦著臉對(duì)著他們遍搞,楚陌淡然地向湖走去...
    牧藥閱讀 236評(píng)論 0 0
  • 枉相思 孤鷹獨(dú)鳴長(zhǎng)空凄罗侯, 冷月淺照千山?jīng)觥? ...
    半裸銀裝施粉黛閱讀 247評(píng)論 10 15