31.Any屋休、NSObject钾唬、AnyObject的區(qū)別
- Any : public typealias Any = protocol<>
- 是"零”個(gè)協(xié)議,任何類(lèi)型都遵循了這個(gè)協(xié)議,涵蓋范圍最大
AnyObject: @objc public protocol AnyObject {}
是一個(gè)協(xié)議內(nèi)容為空的協(xié)議,涵蓋范圍次之, 所有的 class 都隱式地實(shí)現(xiàn)了這個(gè)接口
-
NSObject: public class NSObject :
- NSObjectProtocol遵循了NSObjectProtocol協(xié)議的類(lèi),涵蓋范圍最小: (NSObject類(lèi)或其子類(lèi)的實(shí)例對(duì)象)
32.可選鏈的使用
概念: 它的可選性體現(xiàn)于請(qǐng)求或調(diào)用的目標(biāo)當(dāng)前可能為空(nil)
( 如果可選的目標(biāo)有值,那么調(diào)用就會(huì)成功赃春;如果選擇的目標(biāo)為空(nil)静秆,則這種調(diào)用將返回空(nil))多次調(diào)用被鏈接在一起形成一個(gè)鏈,如果任何一個(gè)節(jié)點(diǎn)為空(nil)將導(dǎo)致整個(gè)鏈?zhǔn)А?/p>
可選鏈的使用:
①在可選類(lèi)型后面放一個(gè)問(wèn)號(hào)严衬,可以定義一個(gè)可選鏈澄者。
②可選值后面放一個(gè)嘆號(hào)來(lái)強(qiáng)制拆得其封包內(nèi)的值( 一般的強(qiáng)制解析很容易引發(fā)運(yùn)行時(shí)錯(cuò)誤。)
33.協(xié)議
1.協(xié)議基本使用:
1)協(xié)議的格式: 協(xié)議的定義方式與類(lèi),結(jié)構(gòu)體粱挡,枚舉的定義都非常相似
protocol SomeProtocol {
// 協(xié)議方法
}
2)遵守協(xié)議的格式:
class SomeClass:SomeSuperClass ,FirstProtocol, AnotherProtocol{
// 類(lèi)的內(nèi)容
//實(shí)現(xiàn)協(xié)議中的方法
}
3)定義協(xié)議和遵守協(xié)議: 類(lèi), 結(jié)構(gòu)體, 枚舉都可以遵循協(xié)議
4)協(xié)議之間的繼承:
protocol CrazySportProtocol {
func jumping()
}
protocol SportProtocol : CrazySportProtocol {
func playBasketball()
func playFootball()
}
2.協(xié)議中代理使用:
概念:即協(xié)議繼承用于代理設(shè)計(jì)模式
protocol BuyTicketProtocol {
func buyTicket()
}
class Person {
// 1.定義協(xié)議屬性
var delegate : BuyTicketProtocol
// 2.自定義構(gòu)造函數(shù)
init (delegate: BuyTicketProtocol) {
self.delegate = delegate
}
// 3.行為
func goToBeijing() {
delegate.buyTicket()
}
}
class HuangNiu: BuyTicketProtocol {
func buyTicket() {
print("買(mǎi)了一張火車(chē)票")
}
}
let p = Person(delegate: HuangNiu())
p.goToBeijing()
注意:
代理屬性, 一般都是使用weak修飾赠幕,而weak修飾的又必須是類(lèi)類(lèi)型的對(duì)象 所以, 一般要求, 協(xié)議繼承自NSObjectProtocol / class
3.協(xié)議中的可選:
1)注意:
①在swift里面, 如果遵循了一個(gè)協(xié)議, 必須要實(shí)現(xiàn), 協(xié)議里面所有的方法
② 協(xié)議可選, 是屬于OC 的特性
2)使用:
@objc 修飾協(xié)議,@objc optional 修飾方法
// 1.定義協(xié)議
@objc
protocol SportProtocol {
func playBasketball()
@objc optional func playFootball()
}
// 2.遵守協(xié)議
class Person : SportProtocol {
var name : String?
var age : Int = 0
// 實(shí)現(xiàn)協(xié)議中的方法
@objc func playBasketball() {
print("人在打籃球")
}
}
34.泛型
- 概念:簡(jiǎn)單理解就是一個(gè)"泛化"的類(lèi)型, 并不特指某一個(gè)具體的類(lèi)型
- 使用:
①作為函數(shù)的參數(shù)或者返回值
②泛型與類(lèi)型的結(jié)合:- 與類(lèi)的結(jié)合
- 與協(xié)議的關(guān)聯(lián)
- 與結(jié)構(gòu)體的結(jié)合
③泛型與where子句的結(jié)合使用
func test<T>(a:T) where T:Person{}
35.閉包
1.基本使用:
閉包的介紹: 閉包和OC中的block非常相似
注意:
①OC中的block是匿名的函數(shù)询筏,Swift中的閉包是一個(gè)特殊的函數(shù)
② block和閉包都經(jīng)常用于回調(diào)-
閉包使用:
block寫(xiě)法:
類(lèi)型: 返回值(^block的名稱(chēng))(block的參數(shù))
值: ^(參數(shù)列表) { //執(zhí)行的代碼 };閉包的寫(xiě)法: 類(lèi)型: (形參列表)->(返回值) 值: { (形參) -> 返回值類(lèi)型 in //執(zhí)行代碼 } 閉包的簡(jiǎn)寫(xiě): 如果閉包沒(méi)有參數(shù), in和in之前的內(nèi)容可以省略 httpTool.loadRequest( { print("回到主線程", NSThread.currentThread());} )
2.參數(shù)閉包/尾隨閉包:
尾隨閉包寫(xiě)法: ①如果閉包是函數(shù)的最后一個(gè)參數(shù),則可以將閉包寫(xiě)在()后面 ②如果函數(shù)只有一個(gè)參數(shù),并且這個(gè)參數(shù)是閉包,那么()可以不寫(xiě) //方式一 httpTool.loadRequest() { print("回到主線程", NSThread.currentThread()); } //方式二 // 開(kāi)發(fā)中建議該寫(xiě)法 httpTool.loadRequest { print("回到主線程", NSThread.currentThread()); }
36.閉包循環(huán)引用
1.原因:如果在HttpTool中有對(duì)閉包進(jìn)行強(qiáng)引用,則會(huì)形成循環(huán)引用
class HttpTool: NSObject {
// 定義屬性,來(lái)強(qiáng)引用傳入的閉包
var callBack : (()->())?
func loadRequest(callBack : ()->()) { dispatch_async(dispatch_get_global_queue(0, 0)) {
() -> Void in
print("加載數(shù)據(jù)", [NSThread.currentThread()])
dispatch_async(dispatch_get_main_queue(), {
() -> Void in
callBack()
})
}
self.callBack = callBack //直接調(diào)用self榕堰,引發(fā)循環(huán)引用
}
}
補(bǔ)充:
在Swift中檢測(cè)一個(gè)對(duì)象是否銷(xiāo)毀,可以實(shí)現(xiàn)對(duì)象的`deinit`函數(shù) // 析構(gòu)函數(shù)(相當(dāng)于OC中dealloc方法)
deinit{
print("ViewController----deinit")
}
2.解決方案:
方案一: 使用weak,對(duì)self使用弱引用。
(但是因?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ù))
weak var weakSelf = self //(OC: __weak typeof(self) weakself = self )
httpTool.loadData {
print("加載數(shù)據(jù)完成,更新界面:", NSThread.currentThread())
weakSelf!.view.backgroundColor = UIColor.redColor()
}
方案二: 和方案一本質(zhì)一樣,只是書(shū)寫(xiě)方式更加簡(jiǎn)單 可以寫(xiě)在閉包中,此時(shí)閉包中用到的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()
}
37.懶加載的使用
- 介紹
swift中也有懶加載的方式踱讨,和OC不同的是swift有專(zhuān)門(mén)的關(guān)鍵字來(lái)實(shí)現(xiàn)懶加載魏蔗,lazy關(guān)鍵字可以用于定義某一個(gè)屬性懶加載(蘋(píng)果的設(shè)計(jì)思想:希望所有的對(duì)象在使用時(shí)才真正加載到內(nèi)存中) - 格式
lazy var 變量: 類(lèi)型 = 函數(shù)名()
//構(gòu)造函數(shù)或者自定義函數(shù)
lazy var 變量: 類(lèi)型 = { 創(chuàng)建變量代碼 }()
// 懶加載的本質(zhì)是,在第一次使用的時(shí)候執(zhí)行閉包,將閉包的返回值賦值給屬性(lazy的作用是只會(huì)賦值一次)
lazy var array : [String] = {
() -> [String] in
return ["sz", "lmj", "lnj"]
}()
38.常見(jiàn)注釋
①單行注釋 //
②多行注釋 /* */ 注意:和與 C 語(yǔ)言多行注釋不同,Swift 的多行注釋可以嵌套在其它的多行注釋之中
③文檔注釋?zhuān)?
/** */
或者
///
④分組注釋
注意:swift中不可以再使用 `#pragma mark -` 改用 `// MARK:-`方式
⑤TODO 需要做
⑥FIXME 解決Bug
39.訪問(wèn)權(quán)限
OC中的訪問(wèn)權(quán)限:
@private : 作用范圍只能在自身類(lèi)
@protected: 作用范圍在自身類(lèi)和繼承自己的子類(lèi)痹筛,什么都不寫(xiě)莺治,默認(rèn)是此屬性。
@public: 作用范圍最大帚稠,在任何地方
@package: 本包內(nèi)使用谣旁,跨包不可以
注意:
①只是用來(lái)修飾成員變量; 無(wú)法修飾方法
②@interface中的聲明的成員變量默認(rèn)是public,@implatation中聲明的成員變量默認(rèn)是privateSwift 中的訪問(wèn)控制權(quán)限:基于模塊和源文件,類(lèi)這三個(gè)概念
internal : 在本模塊中都可以進(jìn)行訪問(wèn) (默認(rèn),子類(lèi)也可以繼承)
private : 當(dāng)前類(lèi)私有 (一個(gè)源文件中可以有多個(gè)類(lèi)W淘纭B凇)
fileprivate: 在當(dāng)前源文件中可以訪問(wèn)
public : 在其他模塊中可以訪問(wèn), 但不能被override,如果修飾類(lèi), 則無(wú)法繼承
open: 在其他模塊中可以訪問(wèn), 并且可以被override馆衔,如果修飾類(lèi), 可以繼承
注意:
①Swift訪問(wèn)權(quán)限, 作用于類(lèi), 屬性, 方法等
②Swift 中的訪問(wèn)級(jí)別遵循一個(gè)基本原則:不可以在某個(gè)實(shí)體中定義訪問(wèn)級(jí)別更高的實(shí)體
40.異常
異常介紹
只要我們?cè)诰幊涛僚校鸵欢ㄒ鎸?duì)錯(cuò)誤處理的問(wèn)題。( 比如:只有使用Optional才能處理空值角溃;)
Swift在設(shè)計(jì)的時(shí)候就盡可能讓我們明確感知錯(cuò)誤拷获,明確處理錯(cuò)誤如何描述一個(gè)錯(cuò)誤?
在Swift里减细,任何一個(gè)遵從Error protocol的類(lèi)型匆瓜,都可以用于描述錯(cuò)誤。
Error是一個(gè)空的protocol未蝌,它唯一的功能驮吱,就是告訴Swift編譯器矫钓,某個(gè)類(lèi)型用來(lái)表示一個(gè)錯(cuò)誤腐巢。
通常,我們使用一個(gè)enum來(lái)定義各種錯(cuò)誤的可能性范抓。-
處理異常的方式
方式一: try方式,需要手動(dòng)處理異常
do{
let result = try readFileContent("abc")
}catch{
print(error)
}方式二: try?方式,不處理異常,如果出現(xiàn)了異常,則返回一個(gè)nil.沒(méi)有異常,則返回對(duì)應(yīng)的值 let result = try? readFileContent("abc”) // 最終返回結(jié)果為一個(gè)可選類(lèi)型 方式三: try!方法,告訴系統(tǒng)該方法沒(méi)有異常. try! readFileContent("abc”) // 注意:如果出現(xiàn)了異常,則程序會(huì)崩潰
41.Swift調(diào)用OC
①根據(jù)系統(tǒng)提示纸型,創(chuàng)建橋接文件
②手動(dòng)配置橋接文件
42.OC調(diào)用Swift
①根據(jù)系統(tǒng)提示拇砰,創(chuàng)建橋接文件
②手動(dòng)配置橋接文件: -Swift.h結(jié)尾梅忌,開(kāi)頭任意,配置好之后除破,用到Swift的地方導(dǎo)入你設(shè)置的頭文件就好牧氮。
注意:
- swfit文件你想共享,跨模塊得是Public或者open
- 如果是類(lèi), 必須繼承自NSObject
- 如果是協(xié)議瑰枫,必須用@objc修飾協(xié)議踱葛。
43.Playground高級(jí)使用
快速查看: 數(shù)值,image光坝,color剖毯,URL,View
-
Sources 目錄
- 原因:在 Playground寫(xiě)的代碼教馆,會(huì)被編譯器實(shí)時(shí)編譯,并運(yùn)行將結(jié)果顯示出來(lái)擂达,造成效率低下
解決方案:
放到Sources 目錄下的源文件會(huì)被編譯成模塊(module)并自動(dòng)導(dǎo)入到 Playground 中并且只會(huì)編譯一次土铺。
使用注意: 需要使用public關(guān)鍵字修飾資源文件中, 需要暴露給外界的內(nèi)容資源
原因:?jiǎn)我坏腜layground并不是一個(gè)完整的APP, 所以并沒(méi)有使用沙盒機(jī)制,如果想要在Playground中, 使用某些資源(比如圖片資源), 該怎樣做呢?
解決方案: 將數(shù)據(jù)存放在資源中板鬓。
①獨(dú)立資源:Resources目錄悲敷,放置到此目錄下的資源是每個(gè) Playground 是獨(dú)立的,可以通過(guò) mainBundle 進(jìn)行訪問(wèn)獲取俭令。
②共享資源:共享資源的目錄是放在用戶(hù)目錄的Documents目錄下的XCPlaygroundSharedDataDirectoryURL來(lái)獲取共享資源目錄的 URL
注意:需要先導(dǎo)入 XCPlayground 模塊異步執(zhí)行
原因: Playground 中的代碼會(huì)從上到下執(zhí)行后德,并在執(zhí)行完畢之后立即停止.所以, 在Playground , 測(cè)試一些異步處理(比如網(wǎng)絡(luò)請(qǐng)求) 一般情況, 就無(wú)法實(shí)現(xiàn)
-
解決方案:
步驟:
1.讓Playground永遠(yuǎn)執(zhí)行
XCPlaygroundPage.currentPage.needsIndefiniteExecution = true
或者
PlaygroundPage.current.needsIndefiniteExecution = true2.停止執(zhí)行 XCPlaygroundPage.currentPage.finishExecution() 或者 PlaygroundPage.current.finishExecution() print("走到這里了") XCPlaygroundPage.currentPage.needsIndefiniteExecution = true let queue = DispatchQueue(label: "test") queue.asyncAfter(deadline: DispatchTime.now() + 2) { print("幾秒后執(zhí)行") XCPlaygroundPage.currentPage.finishExecution() }
多頁(yè)面
-
解釋?zhuān)杭纯梢园巡煌拇a, 放在不同的界面
界面間跳轉(zhuǎn):
//: Next//: [Previous](@previous) //: ["Go to AnyPage"](PageName) 注意:①Playground支持 markdown語(yǔ)法, 所以默認(rèn), 是以markdown語(yǔ)法的格式顯示 ②如果需要跳轉(zhuǎn), 需要,設(shè)置渲染文檔[圖片上傳中。抄腔。瓢湃。(1)]
TimeLine : 捕捉動(dòng)畫(huà)
XCPlaygroundPage.currentPage.liveView
44.集成CocoaPods
注意:swift中podfile文件, 一定要添加use_frameworks!因?yàn)閟wift只支持framework格式的庫(kù)。