注:以下皆为翻译,如有错误或疏漏,请指正。谢谢☺
简介
SlideShare 版
Swift
官方 SlideShare Swift 代码规范
这份规范是用于 swift 编写 iOS8 及以上应用。
目录
- Xcode Preferences
- Switch
- Properties
- Closures
- Identifiers
- Singleton
- Optionals
- Strings
- Enums
- Documentation
<a id="xcode-preferences"/>
Xcode Preferences
- 用“空格键”代替“Tab键”,每个 Tab 对应4个空格(
Xcode->Preferences->Text Editing->Indentation
)
<a id=""/>
Switch
- switch 状态应该有每个 case 状态,包括 default。
var value = 2
var test: String?
switch value {
case 1:
test = "abc"
default:
test = "xyz"
}
- 如果你想要一个object 或 struct 的多个值,创建一个 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
- 如果你希望创建一个只读计算属性,可以不需要 get{}
var computedProp: String {
if someBool {
return "Hello"
}
}
- 如果你希望创建一个可读写计算属性,必须实现 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")
}
}
}
- 创建一个class常量用 static
class Test {
static let ConstantValue: String = "TestString"
}
<a id=""/>
Closures
- 闭包中不需要参数类型在参数列表里。另外,参数放在同一行。
doSomethingWithCompletion() { param1 in
println("\(param1)")
}
- 闭包放在方法参数的最后面。
// 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:
- 如果有两个闭包作为最后的参数......
testMethod(param: 2.5,
success: {
println("success")
},
failure: {
println("failure")
})
- Use trailing closure syntax if a closure is the only parameter:
- 如果闭包是仅有的参数......
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
}
- 如果闭包太大,就不要在一行创建,重新创建一个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:
- 仅仅在必要的时候用 self.
class Test {
var a: (() -> Void)?
var b: Int = 3
func foo(a: () -> Void) {
self.a = a
}
func foo1() {
foo() {
println(self.b)
}
}
}
- 如果定义一个变量,冒号直接在变量后面,冒号后接空格
static var testVar: String
- 定义字典类型,冒号前后各包含一个空格
var someDictionary: [String : Int]
- 定义常量时,首字母大写,驼峰方式
class TestClass {
let ConstantValue = 3
}
- 用 struct 定义多个常量
struct Constants {
static let A = "A"
static let B = "B"
}
<a id=""/>
Singleton
- 用以下方式实现单例
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 变量时,使用相同的名字重新关联变量。
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.
- 当使用enum,记住用短语义。
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.
- 声明一个
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 标准的注释方式以方便快速查看,用 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 应该按照以下顺序组织
- 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>
当一个 class 实现一个 protocol ,用扩展的形式,一个扩展对应一个 protocol
// NewProtocol.swift //
protocol NewProtocol {
func reqMethod()
}
// Test.swift //
class Test {
// content
}
// MARK: - Protocols
// MARK: NewProtocol
extension Test: NewProtocol {
func reqMethod() {
// content
}
}
Cocoa
目录
- Protocols
- UITableView/UICollectionView
- Strings
- NSNotification
- App Delegate
- Core Foundation
- View Controllers
- UIView
- Objective-C Interoperability
<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的子类中,创建一个只读计算属性作为cell 的 reuse identifier,用大写开头,因为他是个常量。
class TableViewCell: UITableViewCell, ReusableView {
static let ReuseIdentifier: String = "TableViewCellIdentifier"
static let NibName: String = "CustomTableViewCell"
}
原因: 注册一个UITableView 或 UICollectionView的重用 cell , 你需要 nib 名称和重用 identifier.
<a id="strings"></a>
Strings
- 将
国际化
字符串放在变量中。
// 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
- 创建一个 struct 管理所有notification的常量名。
struct GlobalNotifications {
static let ABC = ""
}
- 创建 lazy notification 监听变量。
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.确保编译安全.
- 创建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
- 将应用初始化代码抽象到一个单独的类中。
class AppInitializer {
func onAppStart() {
// content
}
}
<a id="core-foundation"></a>
Core Foundation
- 用如下方法代替 CGRectMake 等.
var rect = CGRect(x: 10, y: 10, width: 45, height: 300)
- 创建初始化为0时应该使用如下方法:
var zeroRect = CGRect.zeroRect
<a id="view-controllers"></a>
View Controllers
- 如果 controller 和一个 storyboard 关联,创建一个类方法名为createInstance返回一个用 storyboard 创建的实例。
static func createInstance() -> MasterViewController {
return UIStoryboard.initialControllerFromStoryboard("Master") as! MasterViewController
}
Reasoning: 如果你不会创建当前类的子类,则用static ,否则用 class func
- 如果你有以上描述的情形,但是需要初始化属性,可以创建designated/convenience initializer。
static func createInstanceWithId(id: Int) -> MasterViewController {
let masterViewController = createInstance()
masterViewController.id = id
return masterViewController
}
<a id="uiview"></a>
UIView
- 如果一个类继承自一个有 xib 初始化的 uiview,创建一个方法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
- 你需要一个 bridging-header 文件。如果你的工程里面会用到 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>