Swift規(guī)約

語言規(guī)約

命名規(guī)范

  • 【強制】Swift并不需要使用;結束一行代碼。

  • 【推薦】變量命名多參考蘋果庫或者優(yōu)秀的開源庫的命名方式柒巫。比如Swift 3.0開始,枚舉類型首字母都改成小寫,去掉了冗余信息腾它,比如UIColor.redColor變成UIColor.red力惯。argument label也去掉了冗余信息碗誉,變得非常簡潔。

//Swift 2.3
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell

//Swift 3.0父晶,cellForRowAtIndexPath簡化成cellForRowAt哮缺。
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
  • 【強制】雖然Swift命名傾向于不加任何前綴,但是仍然強制所有的自定義類型加上一個統(tǒng)一的前綴甲喝,比如阿里云App統(tǒng)一使用ALY尝苇。

  • 【強制】extension跟Objective-C一樣,函數(shù)必須加一個前綴埠胖,比如aly_loadImage糠溜,便于理解和使用。不同的模塊給同一個類增加相同命名的擴展押袍,編譯鏈接都不會有問題诵冒。但是如果同時import這些模塊,調(diào)用同名的擴展方法會報下面這個錯誤谊惭。

main.swift:10:5: error: 'test' is inaccessible due to 'internal' protection level
str.test()
^
<unknown>:0: note: 'test' declared here
<unknown>:0: note: 'test' declared here
  • 【強制】專有名詞汽馋,如ECS,使用大寫圈盔,即使出現(xiàn)在方法和屬性中豹芯。

代碼組織

  • 【推薦】相同邏輯代碼、同一個protocol函數(shù)的實現(xiàn)等驱敲,比如使用//MARK: ALYUIViewControllerRefreshDataProtocol標記铁蹈,方便閱讀代碼。

  • 【推薦】類的屬性使用lazy var實現(xiàn)众眨,并且放到class的后面握牧,方便閱讀代碼容诬。

lazy var textLabel : UILabel = {
    let label = UILabel()
    label.font = UIFont.aly_f10
    label.textColor = UIColor.aly_ct_2
    label.textAlignment = .center
    label.text = "添加"
    self.contentView.addSubview(label)

    return label
}()

最佳實踐

消除警告

  • 【強制】在Build Settings里面找到Swift Compiler - Warning Policies,Treat Warning as Erros設置為Yes沿腰,Swift這個設置跟Objective-C不在一起览徒,消除一切編譯警告非常有必要。

  • 【強制】返回值不需要強制使用的颂龙,請使用@discardableResult關鍵字习蓬,否則會產(chǎn)生warning

@discardableResult
func request(_ urlRequest: URLRequestConvertible) -> DataRequest {
    return SessionManager.default.request(urlRequest)
}

避免嚴重的崩潰

  • 【推薦】不要強解Optional類型措嵌。強解非常危險躲叼,剛開始使用Swift開發(fā)非常容易在這塊犯錯誤,導致crash率居高不下企巢》憧叮可以通過guard let、if let包斑、??來避免強解流礁。
//guard let適合后面有大量代碼依賴foo有值
guard let _foo = foo else {
    return
}

print(_foo)

//if let比較靈活
if let _foo = foo {
    //do something
}

//??更加靈活,但是一行代碼使用過多??可能有性能問題罗丰。
print(foo?? "hello world")

避免內(nèi)存泄露

  • 【強制】閉包使用weak或者unowned避免循環(huán)依賴神帅。如果明確外部變量在執(zhí)行代碼的過程中,不會變成nil萌抵,那么使用unowned找御,比如視覺元素的lazy代碼塊中搂擦。網(wǎng)絡接口的回調(diào)是異步的泌参,回調(diào)發(fā)生時,頁面可能已經(jīng)不存在了产园,這種場景下讨永,需要使用weak滔驶。
let cell = ALYCommonCellObject.Builder()
    .title(title: "使用許可協(xié)議", color: UIColor.aly_black)
    .selectionAction(select: { [unowned self] (cell) in
        self.utlogCounter("Setting", withMonitorPoint: "TermOfService")
    })
    .build()
  • 【強制】deinit里面要移除對所有通知和KVO的觀察。

合理選擇數(shù)據(jù)類型

  • 【推薦】盡量使用Swift的類型卿闹,而非Objective-C的橋接類型揭糕,比如使用URL而非NSURL,IndexPath而非NSIndexPath锻霎。

  • 【參考】數(shù)據(jù)對象盡量使用struct著角,而非class。struct是Swift的基礎類型旋恼,翻看蘋果的基礎庫吏口,可以發(fā)現(xiàn)所有的基礎類型,比如Int、String等類型都是struct产徊。

  • 【強制】Swift支持字符串枚舉類型昂勒,表達清晰,不易犯錯舟铜,是一個非常好用的功能叁怪。

enum ALYVote : String {
    case approve = "approve"
    case clean   = "clean"
    case oppose  = "oppose"
}
  • 【強制】Swift 3.0新增了Decimal類型,使用的便捷性比之前橋接的NSDecimalNumber有質(zhì)的飛越深滚,需要使用高精度的場景,比如跟錢有關系的涣觉,一定要使用Decimal痴荐。
let foo : Decimal = 10.12373223423
let bar : Decimal = 1.23423432432432

print(foo+bar) //11.3579665585543176192
print(foo-bar) //11.3579665585543176192
print(foo*bar) //12.4950578137552000654026872358296354816

合理選擇修飾符

  • 【推薦】函數(shù)和類的聲明采用最小夠用使用原則,加上private官册、final生兆、open、public膝宁、internal(默認)等修飾符鸦难。
  • 函數(shù)使用final修飾會走靜態(tài)分發(fā),性能更好员淫。
  • private修飾則不向外暴露合蔽,編譯器優(yōu)化可做內(nèi)聯(lián)。final和private都可以減少Xcode自動提示的信息量介返,提高Xcode的反應速度拴事,好處多多。
  • 對于動態(tài)庫暴露的類圣蝎,open表示可以被繼承的接口刃宵,public表示不能被繼承的接口。明確不需要被外部繼承使用的徘公,請使用public關鍵字牲证。
  • 【參考】關鍵的Swift代碼,如果考慮未來需要打hotpatch关面,那么接口可以使用dynamic修飾坦袍,走Objective-C的動態(tài)派發(fā)。

使用尾隨閉包

  • 【強制】如果函數(shù)接受一個閉包作為參數(shù)缭裆,那么將閉包放在最后一個位置键闺,方便用戶采用最簡方式調(diào)用。

  • 【推薦】使用閉包的最簡調(diào)用方式澈驼。

//最復雜版本
let fullGreetings = guestList.map({(person: String) -> String in return "Hello, \(person)!"})

//最簡單版本
let fullGreetings = guestList.map{ "Hello, \($0)!" }

使用Swift的新方式

  • 【強制】統(tǒng)一使用下面這種單例的編寫方式辛燥,非常簡潔,混編的時候也能被Objective-C識別。
class ALYXXX {
    static let sharedInstance = ALYXXX()
    private override init() {}
}
  • 【推薦】多用lazy var聲明屬性挎塌,代碼緊湊徘六、好看、好維護榴都。
lazy var textLabel : UILabel = {
    let label = UILabel()
    label.font = UIFont.aly_f10
    label.textColor = UIColor.aly_ct_2
    label.textAlignment = .center
    label.text = "添加"
    self.contentView.addSubview(label)

    return label
}()
  • 【推薦】foreach遍歷數(shù)組非常簡潔美觀待锈。map、filter能用的也盡量用起來吧嘴高。
self.groupList.forEach { (id, name) -> Void in
    vc.groupList[id] = name
}
  • 【推薦】defer可以簡化異常處理邏輯竿音,在作用域結束的時候,會執(zhí)行defer代碼塊拴驮。
if exists(filename) {
    let file = open(filename, O_READ)

    defer close(file)

    while let line = try file.readline() {
        //
    }
}

優(yōu)秀的Swift開發(fā)資源

  • 【推薦】盡量采用Swift開源庫春瞬,減少混編的場景。

  • 【推薦】Swift處理JSON不是一件容易的事情套啤,推薦使用HandyJSON宽气。我們從Swift 2.x一直用到3.0,非常穩(wěn)定且好用潜沦。

  • 【推薦】ObjectMapper是比較傳統(tǒng)的JSON解析方式萄涯。如果場景比較簡單,也是不錯的選擇唆鸡。

  • 【推薦】使用SnapKit寫AutoLayout約束涝影。

Swift與Objective-C混編

  • 【強制】Swift不支持宏,所以要使用變量喇闸。
//#define NW_NETWOEK_STATUS_NOTIFY @"TBNetworkStatusChangeNotify"
extern NSString* const NW_NETWOEK_STATUS_NOTIFY;
  • 【強制】Objective-C使用typedef enum定義的枚舉類型袄琳,Swift不能使用,需要使用NS_ENUM或者NS_OPTIONS燃乍。
//typedef enum {
typedef NS_ENUM(NSUInteger, NetworkStatus) {
    NotReachable = 0,
    ReachableViaWiFi,
    ReachableVia2G,
    ReachableVia3G,
    ReachableVia4G
};
//} NetworkStatus;
  • 【強制】構造函數(shù)務必返回instanceType唆樊。如果返回id,Swift必須要轉(zhuǎn)型才能使用刻蟹。
//返回id逗旁,在Swift就必須要轉(zhuǎn)型了。
//+ (id)sharedInstantce;
//(TBLoginCenter.sharedInstantce() as? LoginProtocol)

//使用instanceType符合規(guī)范
+ (instanceType)sharedInstantce;
  • 【推薦】合理使用Nullability Annotations舆瘪,讓Swift更加理解Objective-C的語義片效。
- (__nullable id)itemWithName:(NSString * __nonnull)name;

//NS_ASSUME_NONNULL_BEGIN和NS_ASSUME_NONNULL_END將中間的代碼都加上nonull,
//只需要對nullable的屬性和參數(shù)單獨聲明就好了英古。
//iOS SDK慣用這種方法淀衣。可以多跳進去看看召调。
NS_ASSUME_NONNULL_BEGIN
@interface Foo : NSObject
@property (nonatomic, copy, nullable) NSString *bar1;
@property (nonatomic, copy) NSArray *bar2;
@end
NS_ASSUME_NONNULL_END

顯著的坑

  • open lazy var和WMOSwift 3.0上會沖突膨桥,出現(xiàn)編譯報錯蛮浑。如果不需要被繼承,使用public只嚣。如果需要被繼承沮稚,不采用WMO或不使用open關鍵字。
//可能會出現(xiàn)編譯問題
open lazy var promptTitleLabel : UILabel = {
    let label = UILabel()

    return label
}()
  • weak delegate需要使用class關鍵字册舞。否則會報如下的錯誤:'weak' cannot be applied to non-class type 'MyClassDelegate'蕴掏。這是因為 Swift 的protocol是可以被除了class以外的其他類型遵守的,而對于像 struct 或是 enum這樣的類型调鲸,本身就不通過引用計數(shù)來管理內(nèi)存盛杰,所以也不可能用weak 這樣的 ARC的概念來進行修飾。
protocol MyClassDelegate: class {
    func method()
}

class MyClass {
    weak var delegate: MyClassDelegate?
}

class ViewController: UIViewController, MyClassDelegate {
    // ...
    var someInstance: MyClass!

    override func viewDidLoad() {
        super.viewDidLoad()

        someInstance = MyClass()
        someInstance.delegate = self
    }

    //...
}
  • private修飾的類藐石,如果使用KVC來給屬性設置值饶唤,編譯不會報錯,運行時也不會報錯贯钩,但就是設置不上。去掉private就好了办素。

  • Swift和OC混著寫的時候角雷,有時候會出現(xiàn)OC的類在CloudConsoleApp-Bridging-Header.h里面提供給Swift使用,但是這個類又需要引入CloudConsoleApp-Swift.h使用Swift的一些功能性穿,這樣就循環(huán)包含了勺三,沒法玩下去了。

  • Swift的二進制兼容做的尤其差需曾,如果向外輸出二進制庫的話吗坚,增加、刪除屬性呆万;新增商源、刪除、調(diào)整接口順序谋减,都會導致二進制不兼容牡彻,需要更新主版本號。

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末出爹,一起剝皮案震驚了整個濱河市庄吼,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌严就,老刑警劉巖总寻,帶你破解...
    沈念sama閱讀 212,718評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異梢为,居然都是意外死亡渐行,警方通過查閱死者的電腦和手機轰坊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,683評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來殊轴,“玉大人衰倦,你說我怎么就攤上這事∨岳恚” “怎么了樊零?”我有些...
    開封第一講書人閱讀 158,207評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長孽文。 經(jīng)常有香客問我驻襟,道長,這世上最難降的妖魔是什么芋哭? 我笑而不...
    開封第一講書人閱讀 56,755評論 1 284
  • 正文 為了忘掉前任沉衣,我火速辦了婚禮,結果婚禮上减牺,老公的妹妹穿的比我還像新娘豌习。我一直安慰自己,他們只是感情好拔疚,可當我...
    茶點故事閱讀 65,862評論 6 386
  • 文/花漫 我一把揭開白布肥隆。 她就那樣靜靜地躺著,像睡著了一般稚失。 火紅的嫁衣襯著肌膚如雪栋艳。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 50,050評論 1 291
  • 那天句各,我揣著相機與錄音吸占,去河邊找鬼。 笑死凿宾,一個胖子當著我的面吹牛矾屯,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播初厚,決...
    沈念sama閱讀 39,136評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼问拘,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了惧所?” 一聲冷哼從身側響起骤坐,我...
    開封第一講書人閱讀 37,882評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎下愈,沒想到半個月后纽绍,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,330評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡势似,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,651評論 2 327
  • 正文 我和宋清朗相戀三年拌夏,在試婚紗的時候發(fā)現(xiàn)自己被綠了僧著。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,789評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡障簿,死狀恐怖盹愚,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情站故,我是刑警寧澤皆怕,帶...
    沈念sama閱讀 34,477評論 4 333
  • 正文 年R本政府宣布,位于F島的核電站西篓,受9級特大地震影響愈腾,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜岂津,卻給世界環(huán)境...
    茶點故事閱讀 40,135評論 3 317
  • 文/蒙蒙 一虱黄、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧吮成,春花似錦橱乱、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,864評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至魔种,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間粉洼,已是汗流浹背节预。 一陣腳步聲響...
    開封第一講書人閱讀 32,099評論 1 267
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留属韧,地道東北人安拟。 一個月前我還...
    沈念sama閱讀 46,598評論 2 362
  • 正文 我出身青樓,卻偏偏與公主長得像宵喂,于是被迫代替她去往敵國和親糠赦。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,697評論 2 351

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