Swift/Cocoa 編碼規(guī)范(中文)

注:以下皆為翻譯,如有錯(cuò)誤或疏漏拣度,請(qǐng)指正。謝謝?

簡(jiǎn)介

SlideShare 版

Swift

官方 SlideShare Swift 代碼規(guī)范

這份規(guī)范是用于 swift 編寫 iOS8 及以上應(yīng)用蜂莉。

目錄


<a id="xcode-preferences"/>

Xcode Preferences

  • 用“空格鍵”代替“Tab鍵”蜡娶,每個(gè) Tab 對(duì)應(yīng)4個(gè)空格(Xcode->Preferences->Text Editing->Indentation
    <a id=""/>

Switch

  • switch 狀態(tài)應(yīng)該有每個(gè) case 狀態(tài),包括 default映穗。
var value = 2
var test: String?

switch value {
case 1:
    test = "abc"
default:
    test = "xyz"
}
  • 如果你想要一個(gè)object 或 struct 的多個(gè)值窖张,創(chuàng)建一個(gè) tuple。如下:
struct TestValue {
    enum Val {
        case A
        case B
    }
    var value: Val = .A
    var detail: String = "Test"
}
var testValue = TestValue()

switch (testValue.value, testValue.detail) {
case (.A, "Test"):
    println("This is printed")
default:
    println("This is not printed")
}
  • 如果你不希望走到 default 蚁滋,用 assert宿接。
var test = "Hello"

switch test {
case "Hello"
    print("It prints")
case "World"
    print("It doesn't")
default:
    assert(false, "Useful message for developer")
}

<a id=""/>

Properties

  • 如果你希望創(chuàng)建一個(gè)只讀計(jì)算屬性,可以不需要 get{}
var computedProp: String {
    if someBool {
        return "Hello"
      }
}
  • 如果你希望創(chuàng)建一個(gè)可讀寫計(jì)算屬性辕录,必須實(shí)現(xiàn) get{} set{}
var computedProp: String {
    get {
        if someBool {
            return "Hello"
          }
    }
    set {
        println(newValue)
    }
}
  • 同樣的道理 willSet{} didSet{}
var property = 10 {
    willSet {
        println("willSet")
    }
    didSet {
        println("didSet")
    }
}
  • willSet 和 didSet 可以用 newValue 和 oldValue
var property = 10 {
    willSet {
        if newValue == 10 {
            println("It’s 10")
         }
    }
    didSet {
         if oldValue == 10 {
               println("It was 10")
         }
    }
}
  • 創(chuàng)建一個(gè)class常量用 static
class Test {
    static let ConstantValue: String = "TestString"
}

<a id=""/>

Closures

  • 閉包中不需要參數(shù)類型在參數(shù)列表里睦霎。另外,參數(shù)放在同一行走诞。
doSomethingWithCompletion() { param1 in
    println("\(param1)")
}
  • 閉包放在方法參數(shù)的最后面副女。
// Definition
func newMethod(input: Int, onComplete methodToRun: (input: Int) -> Void) {
    // content
}

// Usage
newMethod(10) { param in
    println("output: \(param)"")
}
  • However, if there are 2 closures as the last parameters, do not use trailing closure syntax for the last one as this is ambiguous. Also, when creating a closure inline as a method parameter, put the parameter name on a new line and follow the following indentation rules:
  • 如果有兩個(gè)閉包作為最后的參數(shù)......
testMethod(param: 2.5,
      success: {
        println("success")
      },
      failure: {
        println("failure")
      })
  • Use trailing closure syntax if a closure is the only parameter:
  • 如果閉包是僅有的參數(shù)......
array1.map { /* content */ }
  • If declaring the type of a function or closure with no return type, specify this by using Void as the return type. Also, put a space before and after -> when declaring a closure type:
  • 如果閉包返回類型為,......
func takeClosure(aClosure: () -> Void) {
    // content
}
  • 如果 func 或 closure 沒有返回值,就不要寫返回
func noReturn() {
    // content
}
  • 如果閉包太大蚣旱,就不要在一行創(chuàng)建碑幅,重新創(chuàng)建一個(gè)local變量
func foo(something: () -> Void) {
    something()
}

func doEverything() {
    let doSomething = {
        var x = 1
        for 1...3 {
            x++
        }
        println(x)
    }
    foo(doSomething)
}

<a id=""/>

Identifiers

  • Only use self.<parameter name> if you need to, which is when you have a parameter of the same name as the instance variable, or in closures:
  • 僅僅在必要的時(shí)候用 self.
class Test {

    var a: (() -> Void)?
    var b: Int = 3

    func foo(a: () -> Void) {
        self.a = a
    }

    func foo1() {
        foo() {
            println(self.b)
        }
    }
}
  • 如果定義一個(gè)變量捐顷,冒號(hào)直接在變量后面衅金,冒號(hào)后接空格
static var testVar: String
  • 定義字典類型凶朗,冒號(hào)前后各包含一個(gè)空格
var someDictionary: [String : Int]
  • 定義常量時(shí)禁悠,首字母大寫,駝峰方式
class TestClass {
    let ConstantValue = 3
}
  • 用 struct 定義多個(gè)常量
struct Constants {
    static let A = "A"
    static let B = "B"
}

<a id=""/>

Singleton

  • 用以下方式實(shí)現(xiàn)單例
class ClassA {

    static let sharedInstance: ClassA = ClassA()
    
    private init() {
        // ...
    }
}

Note: Xcode currently (6.0.1) does not indent properly in this case. Use the indentation specified above.

<a id="optionals"/>

Optionals

  • When unwrapping optionals, rebind the optional to the same name, unless there is a reason not to. This example shows this, but in this case it should be done within the binding.
  • 使用 optional 變量時(shí)魁衙,使用相同的名字重新關(guān)聯(lián)變量羡忘。
func possibleBike() -> Bike? {
    // content
}

let bike = possibleBike()
if let bike = bike {
    // content
}

<a id="strings"/>

Strings

  • When appending to a string, always use the += operator.
  • 用 += 拼接字符串
var newString = "Hello"
newString += " world!"

Note: do not concatenate user-facing strings as the ordering could change in different languages

<a id="enums"/>

Enums

  • When using an enum, always prefer the shorthand syntax when possible. The shorthand syntax should be possible whenever the type does not need to be inferred from the assigned value. Note: there are certain bugs that don't allow them to be used everywhere they should be possible.
  • 當(dāng)使用enum,記住用短語(yǔ)義么鹤。
enum TestEnum {
    case A
    case B
}

var theValue: TestEnum?
var shouldBeA = true

if shouldBeA {
    theValue = .A
} else {
    theValue = .B
}
  • When declaring and setting a variable/constant of an enum type, do so in the following manner.
  • 聲明一個(gè)enum變量或常量
var testValue: TestEnum = .A

<a id="documentation"/>

Documentation

  • 單行方法注釋如下
/// This method does nothing
func foo() {
    // content
}
  • 多行注釋如下
/**
 This method does something.
 It's very useful.
 */
func foo2() {
    // content
}
  • 用 swift 標(biāo)準(zhǔn)的注釋方式以方便快速查看,用 Ctl+I 格式化代碼

Note: Make sure to test your documentation by checking it's Quick Documentation by option-clicking on the method name.

/**
 This method has parameters and a return type.

 - Parameter input: This is an input parameter.
 - Returns: True if it worked; false otherwise.
 */
func foo3(input: String) -> Bool {
    // content
}

Note: The following section refers to marks, which are Swift's version of #pragma mark in Objective-C to separate code. There are 2 types of marks: section marks and sub-section marks.

Section Marks:

   // MARK: - Section Name

Sub-section Marks:

   // MARK: Sub-section Name
  • 用 marks 暗示新的代碼段
class Stuff {

    // MARK: - Instance methods

    func newMethod() {
        // content
    }
}
  • class/struct 應(yīng)該按照以下順序組織

      - Section: Singleton
      - Section: Declared Types (Enums, Structs, etc.), Type Aliases
      - Section: Constants
      - Section: Class Properties
      - Section: Instance Properties
          - Sub-section: Stored
          - Sub-section: Computed
      - Section: Init/Deinit
      - Section: Class Methods
          - Sub-section: Public
          - Sub-section: Private
      - Section: Instance Methods
          - Sub-section: Public
          - Sub-section: Private
      - Section: Protocols
          - Sub-section: <Protocol Name>
    
  • 當(dāng)一個(gè) class 實(shí)現(xiàn)一個(gè) protocol ,用擴(kuò)展的形式棋返,一個(gè)擴(kuò)展對(duì)應(yīng)一個(gè) protocol

// NewProtocol.swift //
protocol NewProtocol {
    func reqMethod()
}

// Test.swift //
class Test {

    // content
}

// MARK: - Protocols
// MARK: NewProtocol

extension Test: NewProtocol {
    func reqMethod() {
        // content
    }
}

Cocoa

目錄


<a id="protocols"></a>

Protocols

  • 重用 protocol 需要 reuse identifier.
protocol ReusableView {
    static var ReuseIdentifier: String { get }
    static var NibName: String { get }
}

<a id="uitableview"></a>

UITableView & UICollectionView

  • 在UITableViewCell/UICollectionViewCell的子類中延都,創(chuàng)建一個(gè)只讀計(jì)算屬性作為cell 的 reuse identifier,用大寫開頭懊昨,因?yàn)樗莻€(gè)常量窄潭。
class TableViewCell: UITableViewCell, ReusableView {
    static let ReuseIdentifier: String = "TableViewCellIdentifier"
    static let NibName: String = "CustomTableViewCell"
}

原因: 注冊(cè)一個(gè)UITableView 或 UICollectionView的重用 cell , 你需要 nib 名稱和重用 identifier.

<a id="strings"></a>

Strings

  • 國(guó)際化字符串放在變量中。
// Localizable.strings //
// <App Section>
"user_facing_string_key" = "This is a user-facing string."

// Someting.swift //
var userFacing = NSLocalizedString("user_facing_string_key", comment: "")

<a id="nsnotification"></a>

NSNotification

  • 用倒過來的域名加 notification name酵颁。
com.linkedin.slideshare.notification_name
  • 創(chuàng)建一個(gè) struct 管理所有notification的常量名。
struct GlobalNotifications {
    static let ABC = ""
}
  • 創(chuàng)建 lazy notification 監(jiān)聽變量月帝。
private lazy var handleNotification: (NSNotification!) -> Void { [weak self] notification in
    // Handle the notification
}

原因: This way you can define capture semantics for self and also use the identifier as the selector in the addObserver method (see below) instead of a string.確保編譯安全.

  • 創(chuàng)建registerNotifications() 和 deregisterNotifications()躏惋。
func registerNotifications() {
    let notificationCenter = NSNotificationCenter.defaultCenter()

    notificationCenter.addObserver(self, selector: handleNotificationABC, name: GlobalNotifications.ABC, object: nil)
}

func deregisterNotifications() {
    NSNotificationCenter.defaultCenter().removeObserver(self)
}

<a id="app-delegate"></a>

App Delegate

  • 將應(yīng)用初始化代碼抽象到一個(gè)單獨(dú)的類中。
class AppInitializer {
    func onAppStart() {
        // content
    }
}

<a id="core-foundation"></a>

Core Foundation

  • 用如下方法代替 CGRectMake 等.
var rect = CGRect(x: 10, y: 10, width: 45, height: 300)
  • 創(chuàng)建初始化為0時(shí)應(yīng)該使用如下方法:
var zeroRect = CGRect.zeroRect

<a id="view-controllers"></a>

View Controllers

  • 如果 controller 和一個(gè) storyboard 關(guān)聯(lián)嚷辅,創(chuàng)建一個(gè)類方法名為createInstance返回一個(gè)用 storyboard 創(chuàng)建的實(shí)例簿姨。
static func createInstance() -> MasterViewController {
    return UIStoryboard.initialControllerFromStoryboard("Master") as! MasterViewController
}

Reasoning: 如果你不會(huì)創(chuàng)建當(dāng)前類的子類,則用static ,否則用 class func

  • 如果你有以上描述的情形簸搞,但是需要初始化屬性扁位,可以創(chuàng)建designated/convenience initializer。
static func createInstanceWithId(id: Int) -> MasterViewController {
        let masterViewController = createInstance()
        masterViewController.id = id
        return masterViewController
}

<a id="uiview"></a>

UIView

  • 如果一個(gè)類繼承自一個(gè)有 xib 初始化的 uiview趁俊,創(chuàng)建一個(gè)方法createInstance 用法如上文 View Controllers 部分域仇。
class CustomView: UIView {

    private static let NibName: String = "CustomView"

    static func createInstance() -> CustomView {
        return NSBundle.mainBundle().loadNibNamed(nibName, owner: nil, options: nil)[0] as! CustomView
    }
}

<a id="objective-c-interoperability"></a>

Objective-C Interoperability

  • 你需要一個(gè) bridging-header 文件。如果你的工程里面會(huì)用到 OC 文件寺擂。
// <Product-Name>-Bridging-Header.h
#import "SDWebImageHeader.h"

// SDWebImageHeader.h
#import <SDWebImage/UIImageView+WebCache.h>
#import <SDWebImage/UIImage+MultiFormat.h>
#import <SDWebImage/SDWebImagePrefetcher.h>
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末暇务,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子怔软,更是在濱河造成了極大的恐慌垦细,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,826評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件挡逼,死亡現(xiàn)場(chǎng)離奇詭異括改,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)家坎,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門嘱能,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人乘盖,你說我怎么就攤上這事焰檩。” “怎么了订框?”我有些...
    開封第一講書人閱讀 164,234評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵析苫,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我,道長(zhǎng)衩侥,這世上最難降的妖魔是什么国旷? 我笑而不...
    開封第一講書人閱讀 58,562評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮茫死,結(jié)果婚禮上跪但,老公的妹妹穿的比我還像新娘。我一直安慰自己峦萎,他們只是感情好屡久,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,611評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著爱榔,像睡著了一般被环。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上详幽,一...
    開封第一講書人閱讀 51,482評(píng)論 1 302
  • 那天筛欢,我揣著相機(jī)與錄音,去河邊找鬼唇聘。 笑死版姑,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的迟郎。 我是一名探鬼主播剥险,決...
    沈念sama閱讀 40,271評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼谎亩!你這毒婦竟也來了炒嘲?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,166評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤匈庭,失蹤者是張志新(化名)和其女友劉穎夫凸,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體阱持,經(jīng)...
    沈念sama閱讀 45,608評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡夭拌,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,814評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了衷咽。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片鸽扁。...
    茶點(diǎn)故事閱讀 39,926評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖镶骗,靈堂內(nèi)的尸體忽然破棺而出桶现,到底是詐尸還是另有隱情,我是刑警寧澤鼎姊,帶...
    沈念sama閱讀 35,644評(píng)論 5 346
  • 正文 年R本政府宣布骡和,位于F島的核電站相赁,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏慰于。R本人自食惡果不足惜钮科,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,249評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望婆赠。 院中可真熱鬧绵脯,春花似錦、人聲如沸休里。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,866評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)妙黍。三九已至璃吧,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間废境,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,991評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工筒繁, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留噩凹,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,063評(píng)論 3 370
  • 正文 我出身青樓毡咏,卻偏偏與公主長(zhǎng)得像驮宴,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子呕缭,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,871評(píng)論 2 354

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

  • 以下翻譯自Apple官方文檔堵泽,結(jié)合自己的理解記錄下來。翻譯基于 swift 3.0.1 原文地址 Closure...
    藝術(shù)農(nóng)閱讀 1,538評(píng)論 0 3
  • 走著走著恢总,就散了迎罗, 朋友越來越多,卻也越來越少片仿,越來越好纹安。 回憶都淡了; 看著看著砂豌,就累了厢岂, 工作越來越多...
    炎燃閱讀 434評(píng)論 0 2
  • 昨天,我路過國(guó)內(nèi)某品牌腕表專柜阳距,最近我注意到一些朋友開始關(guān)注這個(gè)品牌的腕表塔粒,便停下來和店員聊了聊,我試著拿他們的表...
    管理顧問王榮增閱讀 424評(píng)論 0 1