第一節(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即可
- Swift中提供了特殊的截取方式
數(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)
}
加載表情的視圖模型
第七課
圖文混排
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)
}