那些年,學swift踩過的坑

最近在學Swift,本以為多是語法與oc不同,而且都是使用相同的cocoa框架,相同的API,但是或多或少還是有些坑在里,為了避免以后再踩,在這里記下了,以后發現新的坑,也會慢慢在這里加上

[TOC]

1.main文件去哪兒了?

OC中main.m中的代碼, 通過@UIApplicationMain標記自動生成

可以注掉AppDelegate里的@UIApplicationMain,自己實現Main,不過一般沒人這樣做

實現下面代碼就是OC中的main文件的函數

UIApplicationMain(Process.argc, Process.unsafeArgv,nil, NSStringFromClass(AppDelegate))

2.如何通過字符串創建類對象?

在swift中打印對象時,會發現在類型前面總會有命名空間

.+類名

在swift中用字符串生成類對象就需要拼接成這樣的格式,才能成功生成類

注意,命名空間不要加特殊符號,不然依然無法獲取控制器類

//獲取命名空間,在info.plist文件里就是Executable fileletnameSpace = NSBundle.mainBundle().infoDictionary!["CFBundleExecutable"]as!String//拼接成固定格式letcontroller:AnyClass = NSClassFromString(nameSpace +"."+ controllerName)!//創建對象letviewController = (controlleras! UIViewController.Type).init()

3.Swift中的Any,AnyObject,AnyClass分別代表是什么?

AnyObject: 相當于OC中的id, 表示所有class類型的數據, 所有繼承與NSObject的類都隱式實現了protocol AnyObject協議, 所以他可以表示所有的class類型

Any:所有基本數據類型和enum/ struct都可以用Any來表示

注意: 有的時候你會發現將基本數據類型或者enum/ struct通過AnyObject來保存也不會報錯, 這是因為Swift中很多數據類型可以和OC中的數據類型進行自動轉換, 系統內部已經將他們轉換為了OC的對象類型

AnyClass: 用來表示任意類的類類型(元類型)

typealiasAnyClass=AnyObject.Type.Type用于獲取類的元類型, 例如Person.Type就代表著獲取Person的元類型? .self如果通過類名調用, 那么可以獲取該類的類型, 說白了就是獲取自己

4.在Swife中如何抓取異常?

在Swift中抓取異常需要do,catch,try這三個關鍵字

這里舉個json序列化的例子

do{letpath =/..路徑../letdata =/..轉data..///編譯器會要求你實行異常檢測,于是在序列化前面添加try字段//外部包裹do,catch,顯而易見出錯自然會走catchletdicArr =tryNSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers)? ? ? ? }catch{// 如果拋出異常就會來到catch}

5.在swift中如何定義全局打印方法

由于swift沒有宏,我們不能像oc那樣去定義

直接在AppDelegate中寫,反正哪里都可以用

用泛型傳參

如何判斷調試與發布狀態呢?

在Build settings里找到Swift Compiler-custom Flags

在other swift flags 的Debug里添加兩個字段

"-D"

"DEBUG"

代碼中直接判斷就行

funcHJSLog(message: T){? ? #ifDEBUGprint("\(message)")? ? #endif}

6.在swift中,單例怎么寫?

在swift中,單例有兩種寫法

一種是按照OC的思維去寫

static var onceToken: dispatch_once_t =0staticvarinstance: NetworkTools?classfunc shareNetworkTools() -> NetworkTools? ? {? ? ? ? dispatch_once(&onceToken) { () ->Voidinprint("我被調用了")instance= NetworkTools()? ? ? ? }returninstance!? ? }

另一種就是swift的純正寫法

在swift中,let本身就只會創建一次,可以運用這個特性

let是線程安全的

staticletinstance:NetworkTools=NetworkTools()classfuncshareNetworkTools() ->NetworkTools{returninstance? ? }

7.在swift中如何私有化點擊事件方法

一般我們不公開方法會在前面添加private

但是例如按鈕點擊方法,光是添加private是不夠的

因為swift的方法調用是在編譯時就決定了

而點擊事件方法由于是來自于runloop中

編譯器不會它一起編譯進來,只有在運行時呼叫,這屬于OC的調用方式

所以我們還需要再在方法前面加上@objc

//按鈕點擊handle@objcprivatefunccomposeClick(){? ? }`

8.在swift中如何懶加載

在swift中對懶加載有專門的關鍵字

///懶加載一個imageViewprivate lazy var icon:UIImageView= {? ? ? ? let imageV =UIImageView(image:UIImage(named:"visitordiscover_feed_image_smallicon"))returnimageV? ? }()

9.在swift中的協議(protocol)

在swift中定義協議也很簡單

只需要在類前定義就行

@objcprotocolVisitorViewDelegate:NSObjectProtocol{//點擊注冊按鈕optionalfuncvisitorViewDidRegisterBtnClick(visitView: VisitorView)//點擊登錄按鈕optionalfuncvisitorViewDidLoginBtnClick(visitView:VisitorView)}

代理屬性需要設定為weak,防止循環引用

weakvardelegate:VisitorViewDelegate?

在調用代理方法時,代理作為可選屬性,已經幫我們預防代理不存在的可能

我們還需要借助可選屬性來預防方法未實現

當然在確定實現的前提下可以解包

///注冊handle@objcprivatefuncregisterClick(){delegate?.visitorViewDidRegisterBtnClick!(self)? }///登錄handle@objcprivatefuncloginClick(){ delegate?.visitorViewDidLoginBtnClick?(self)? }

10.在swift中如何寫分類

我剛從oc轉過來就遇到了如何在swift中寫分類的問題

swift中寫分類很簡單

extension就是swift中的分類

例如給UIBarbuttonItem添加分類

新建一個UIBarButtonItem+Extension.swift文件

importUIKitextensionUIBarButtonItem{? ? convenience init(target:AnyObject?,action:Selector,image:String) {? ? ? ? let btn =UIButton(type:UIButtonType.Custom)? ? ? ? btn.setImage(UIImage(named: image), forState:UIControlState.Normal)? ? ? ? btn.setImage(UIImage(named: image +"_highlighted"), forState:UIControlState.Highlighted)? ? ? ? btn.addTarget(target, action: action, forControlEvents:UIControlEvents.TouchUpInside)self.init(customView:btn)? ? }}

11.為何經常被強制實現init(coder: NSCoder)

因為Objective-C 和 Swift 中都沒有直接的這樣的抽象函數語法支持

然而有些時候我們卻有不想讓別人調用某個方法,但又不得不將其暴露出來的時候。

一般滿足這種需求的就是抽象類型或者抽象函數

在面對這種情況時,為了確保子類實現這些方法,而父類中的方法不被錯誤地調用,我們就可以利用 fatalError 來在父類中強制拋出錯誤,以保證使用這些代碼的開發者留意到他們必須在自己的子類中實現相關方法:

classMyClass{funcmethodMustBeImplementedInSubclass(){? ? ? ? fatalError("這個方法必須在子類中被重寫")? ? }}classYourClass:MyClass{overridefuncmethodMustBeImplementedInSubclass(){print("YourClass 實現了該方法")? ? }}classTheirClass:MyClass{funcsomeOtherMethod(){? ? }}YourClass().methodMustBeImplementedInSubclass()// YourClass 實現了該方法TheirClass().methodMustBeImplementedInSubclass()// 這個方法必須在子類中被重寫

不僅僅是對于類似抽象函數的使用中可以選擇 fatalError,對于其他一切我們不希望別人隨意調用,但是又不得不去實現的方法,我們都應該使用 fatalError 來避免任何可能的誤會。比如父類標明了某個 init 方法是 required 的,但是你的子類永遠不會使用這個方法來初始化時,就可以采用類似的方式, 被廣泛使用 (以及被廣泛討厭的) init(coder: NSCoder) 就是一個例子。在子類中,我們往往會寫

requiredinit(coder:NSCoder) {fatalError("NSCoding not supported")}

12.在swift中使用guard與fatalError配合拋出異常

在嚴謹的開發中會經常用到斷言

前面一條介紹了fatalError來拋出錯誤

這條就來介紹一下guard與fatalError的配合使用達到斷言的效果

guardletsafeValue = criticalValueelse{? fatalError("criticalValue cannot be nil here")}someNecessaryOperation(safeValue)

本來我認為if也可以達到這樣的效果

ifletsafeValue = criticalValue {? someNecessaryOperation(safeValue)}else{? fatalError("criticalValue cannot be nil here")}

或者

ifcriticalValue ==nil{? fatalError("criticalValue cannot be nil here")}someNecessaryOperation(criticalValue!)

但是看到有些博客這么說:

這個flatten code以其他方式進入一個if let 代碼塊,并且在靠近相關的環境中過早地退出了,而不是進入else代碼塊。甚 至當你沒有捕獲一個值(guard let),這個模式在編譯期間也會強制過早退出。在第二個if的例子里,盡管代碼flattend得像guard一樣,但是一個毀滅性的錯誤或者其他返回 一些無法退出的進程(或者基于確切實例的非法態)將會導致crash。一個過早的退出發生時,guard聲明將會及時發現錯誤,并將其從else block中移除。(這博主翻譯得真爛)

所以,還是用guard比較好

13.在swift中,互斥鎖變成什么樣了?

在swift中,互斥鎖如何寫

oc中的互斥鎖:

@synchronized(self) {//需要執行的代碼塊}

swift中的互斥鎖

objc_sync_enter(self)//需要執行的代碼塊objc_sync_exit(self)

至于其他多線程的API和以前的一樣,只是少了perform這一類的API,蘋果已經去掉了

14.在swift中,引用self時,如何避免循環引用

在oc中,我們需要在代碼塊用到self時,可以直接把self付給其他變量,然后在塊中使用完畢后制空,或者像下面弱引用self來避免循環引用:

__weaktypeof(self) weakSelf =self;

那么在swift中我們怎么辦到這點呢?

很簡單,看下面代碼

//這里用gcd舉例不好,畢竟系統的塊不會造成循環引用,這里就勉強的學一下怎么改吧dispatch_async(dispatch_get_global_queue(0,0)) {[unownedself] () -> Voidinself.view//添加自己的代碼}

只需要在閉包里加入[unowned self]即可

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,791評論 6 545
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,795評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,943評論 0 384
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 64,057評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,773評論 6 414
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,106評論 1 330
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,082評論 3 450
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,282評論 0 291
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,793評論 1 338
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,507評論 3 361
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,741評論 1 375
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,220評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,929評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,325評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,661評論 1 296
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,482評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,702評論 2 380

推薦閱讀更多精彩內容