-
Notifications
You must be signed in to change notification settings - Fork 5
Руководство по оформлению кода на языке Swift
Версия raywenderlich.com в переводе на русский язык.
- Имена
- Пробелы и табуляция
- Комментарии
- Классы и структуры
- Объявления функций
- Безымянные функции
- Типы
- Точки с запятой
- Язык
Используем говорящие имена с ГорбатымСинтаксисом ("CamelCase") для классов, методов, переменных и т. д. Имена классов, структур и перечислений пишем с заглавной буквы, имена методов и переменных – со строчной.
Следует писать так:
private let maximumWidgetCount = 100
class WidgetContainer {
var widgetButton: UIButton
let widgetHeightPercentage = 0.85
}
А не так:
let MAX_WIDGET_COUNT = 100
class app_widgetContainer {
var wBut: UIButton
let wHeightPct = 0.85
}
При описании функций и инициализаторов (init) следует задавать и использовать именованные параметры для всех аргументов, исключение – когда контекст максимально понятен интуитивно. Кроме того, лучше использовать еще и внешние имена параметров, если это сделает вызовы функции более читабельными.
func dateFromString(_ dateString: String) -> NSDate
func convertPointAt(column: Int, row: Int) -> CGPoint
func timedAction(afterDelay delay: NSTimeInterval, perform action: SKAction) -> SKAction!
// Вызов выглядит так:
dateFromString("2014-03-14")
convertPointAt(column: 42, row: 13)
timedAction(afterDelay: 1.0, perform: someOtherAction)
При описании методов лучше следовать стандартному соглашению Apple — ссылаться на первый параметр в имени метода таким образом, чтоб в сочетании друг с другом имя метода и параметр представляли собой одну фразу (в следующем примере это "combine with other counter"):
class Counter {
func combine(with otherCounter: Counter, options: Dictionary?) { ... }
func increment(by amount: Int) { ... }
}
Используем горбатыйСинтаксис ("camelCase") для значений перечислений
enum Shape {
case rectangle
case square
case triangle
case circle
}
Описыва функции в литературе (обучающих статьях, книгах, комментариях), включаем внешние (со стороны вызова) имена параметров или символ _
для безымянных параметров.
Вызываем
convertPoint(column:row:)
из своей собственной реализацииinit
.Если вызываем
dateFromString(_:)
, нужно убедиться, что передаем строку в формате "yyyy-MM-dd".Если вызываем
timedAction(afterDelay:perform:)
изviewDidLoad()
, не забываем передавать урегулированное значение задержки и действие, которое нужно совершить.Не следует непосредственно вызывать data source-метод
tableView(_:cellForRowAt:)
Если сомневаемся, смотрим, как Xcode описывает метод в выпрыгивающем меню (jump bar) – наше руководство соответствует этим описаниям.
Следует указывать префикс принадлежности к модулю только если два имени из разных модулей совпадают и требуется избавиться от неоднозначности. В других же случаях эти префиксы указывать не нужно.
import SomeModule
let myClass = MyModule.UsefulClass()
- Делаем отступы, используя 4 пробела, а не табуляцию. Убедитесь, что эти параметры в настройках Xcode установлены по умолчанию:
- Скобки метода и другие скобки (
if
/else
/switch
/while
etc.) всегда открываем на той же строке, что и название метода/оператора, но закрываем всегда на отдельной новой строке. - Подсказка: Чтоб автоматически перерасставить отступы, выделите часть кода (или выделите весь код, воспользовавшись сочетанием клавиш ⌘A) и затем воспользуйтесь сочетанием клавиш Ctrl-I (или Editor → Structure → Re-Indent в меню).
Следует писать так:
if user.isHappy {
// Что-нибудь делаем
} else {
// Делаем что-нибудь другое
}
А не так:
if user.isHappy
{
// Что-нибудь делаем
}
else {
// Делаем что-нибудь другое }
- Чтобы обеспечить визуальную ясность и организованность, между методами следует оставлять ровно одну пустую строку. Пропуски внутри методов должны разделять части кода по функциональности, притом, наличие слишком большого количества пропусков (при следовании этому предписанию) обычно означает, что метод следует разделить на несколько методов.
Когда нужно, используйте комментарии чтоб объяснить, зачем конкретная часть кода делает что-либо. Комментарии должны оставаться актуальными, в противном случае их следует удалять.
Не следует злоупотреблять комментариями. Код должен быть максимально понятным и сам по себе ("самодокументирующимся"). Исключение: Это не касается тех комментариев, которые используются непосредственно для генерации документации
Помним, что структуры (structs) имеют семантику значений (value semantics). Используем структуры для вещей, которые не являются индивидуальными объектами. Массив, содержащий только [a, b, c]
абсолютно таков же, как и любой друой, содержащий только [a, b, c]
, и они абсолютно равнозначны и заменяемы. Совсем не важно, используете ли вы первый массив или второй, потому что они представляют из себя одну и ту же вещь. Вот почему массивы считаются структурами.
Классы имеют семантику ссылок (reference semantics). Используем классы для вещей, которые являются индивидуальными объектами или имеют специфический жизненный цикл. Например, людей следует представлять (моделировать) как класс. Два объекта, являющиеся экземплярами класса людей – две разные сути. То, что два человека имеют одно и то же имя и одну и ту же дату рождения, совсем не означает, что они – один и тот же человек. При этом, дата рождения человека может быть структурой, ведь дата, обозначающая третье марта 1950 года всегда совпадает с любым объектом-датой, обозначающим 3 марта 1950. Дата сама по себе не являются индивидуальным объектом.
Иногда некоторые вещи, при том, что они должны быть структурами, должны наследоваться от NSObject
, или они уже исторически смоделированы как классы (NSDate
, NSSet
). Тем не менее, нужно пытаться следовать этим предписаниям настолько близко, насколько это возможно.
Пример хорошо оформленного описания класса:
class Circle: Shape {
var x: Int, y: Int
final var radius: Double
final var diameter: Double {
get {
return radius * 2
}
set {
radius = newValue / 2
}
}
init(x: Int, y: Int, radius: Double) {
self.x = x
self.y = y
self.radius = radius
}
convenience init(x: Int, y: Int, diameter: Double) {
self.init(x: x, y: y, radius: diameter / 2)
}
func describe() -> String {
return "I am a circle at \(centerString()) with an area of \(computeArea())"
}
override func computeArea() -> Double {
return M_PI * radius * radius
}
private func centerString() -> String {
return "(\(x),\(y))"
}
}
Пример выше демонстрирует следующие правила оформления:
- При указании типов пробел ставим после двоеточия, не перед ним. Например,
x: Int
иCircle: Shape
. - Определяем несколько переменных (структур) на одной строке, если они имеют общую цель/контекст.
- При описании getter-ов и setter-ов не забываем о правилах отступов и др.
- Не добавляем модификаторы доступа, такие как
internal
, если они уже установлены по умолчанию. Таким же образом, не повторяем модификатор доступа при переопределении метода. - Используем
final
для свойств, которые не должны быть перегружены при наследовании. Если нет необходимости в наследовании от данного класса вообще, помечаем весь класс какfinal
. Это помогает компилятору в оптимизации кода.
Из соображений краткости избегаем использования self
, поскольку Swift не требует его для доступа к свойствам объекта или вызова его методов.
Используем self
, когда необходимо различать названия свойств от аргументов в инициализаторах, а также при ссылках на свойства в замыканиях (closures) в соответствии с требованиями компилятора:
class BoardLocation {
let row: Int, column: Int
init(row: Int, column: Int) {
self.row = row
self.column = column
let closure = {
println(self.row)
}
}
}
Указывая соответствие класса протоколу, лучше указывать отдельное расширение класса для методов протокола. Это сохраняет соответствующие методы сгруппированными по протоколам и может упростить инструкции добавления протокола к классу со связанными с ним методами.
Также, не забываем про // MARK:
— комментарий для поддержания организованности!
Следует писать так:
class MyViewcontroller: UIViewController {
// всё, что относится к классу
}
// MARK: - UITableViewDataSource
extension MyViewcontroller: UITableViewDataSource {
// data source-методы для Table View
}
// MARK: - UIScrollViewDelegate
extension MyViewcontroller: UIScrollViewDelegate {
// delegate-методы для Scroll View
}
А не так:
class MyViewcontroller: UIViewController, UITableViewDataSource, UIScrollViewDelegate {
// вообще все методы
}
Из соображений краткости, если вычисляемое свойство (computed property) позволяет только извлекать своё значение, но не задавать его, опускаем конструкцию get. Конструкция get требуется только в сопровождении с конструкцией set.
Следует писать так:
var diameter: Double {
return radius * 2
}
А не так:
var diameter: Double {
get {
return radius * 2
}
}
Короткие объявления функций оставляем на одной линии:
func reticulateSplines(spline: [Double]) -> Bool {
// тело функции
}
Если же объявление функции длинное, добавляем разрывы строк в допустимых местах, а также добавляем дополнительный отступ в последующих строках объявления функции:
func reticulateSplines(spline: [Double],
adjustmentFactor: Double,
translateConstant: Int,
comment: String) -> Bool {
// тело функции
}
В случаях, когда последним аргументом передается замыкание, размещаем его не внутри круглых скобок, а уже за ними (см. пример кода ниже). Параметрам этих функций даем максимально говорящие имена.
Следует писать так:
UIView.animateWithDuration(1.0) {
self.myView.alpha = 0
}
UIView.animateWithDuration(1.0,
animations: {
self.myView.alpha = 0
},
completion: { finished in
self.myView.removeFromSuperview()
}
)
А не так:
UIView.animateWithDuration(1.0, animations: {
self.myView.alpha = 0
})
UIView.animateWithDuration(1.0,
animations: {
self.myView.alpha = 0
}) { f in
self.myView.removeFromSuperview()
}
В описаниях замыканий, состоящих из одного выражения, и в которых контекст очевиден, следует упускать return:
attendeeList.sort { a, b in
a > b
}
Всегда, когда возможно, используем собственные типы языка Swift. Swift поддерживает т. н. bridging на Objective-C, таким образом можно пользоваться и полным арсеналом методов языка Objective-C.
Следует писать так:
let width = 120.0 // Double
let widthString = (width as NSNumber).stringValue // String
А не так:
let width: NSNumber = 120.0 // NSNumber
let widthString: NSString = width.stringValue // NSString
Константы объявляются с помощью ключевого слова let
, переменные – с помощью ключевого слова var
. Всегда используем let
вместо var
, если значение переменной не будет меняться.
Подсказка: рекомендуемая тактика — объявляем всё, используя ключевое слово let
, и меняем на var
только тогда, когда начинает возмущаться компилятор.
Объявляем типы переменных и типы возвращаемых значений функций как optionals (используя ?
в конце названия типа) везде, где возможно пустое значение (nil).
Распаковываем (unwrap) optionals с помощью !
, только если уверены, что к этому моменту переменная будет инициализирована непустым значением. Используем неявно распакованные optionals (!
вместо ?
при объявлении) только для тех переменных, для которых мы уверены, что они будут инициализированы до использования.
Используем optional binding, если нужно однократно распаковать optional, сразу выполнив несколько операций:
if let textContainer = self.textContainer {
// производим действия с textContainer
}
В этом случае, кстати говоря, в качестве имени константы рекомендуется дублировать оригинальное имя переменной всегда, когда это приемлимо и возможно, вместо того, чтобы использовать имена типа unwrappedTextContainer
или actualTextContainer
.
При объявлении optionals избегаем названий для них типа optionalString
или maybeView
, так как информация о том, что они optionals уже содержится в объявлении их типа.
Следует писать так:
var subview: UIView?
var volume: Double?
// в дальнейшем...
if let subview = subview, volume = volume {
// производим действия с распакованными subview и volume
}
А не так:
var optionalSubview: UIView?
var volume: Double?
if let unwrappedSubview = optionalSubview {
if let realVolume = volume {
// производим действия с unWrappedSubview и realVolume
}
}
Используем собственные инициализаторы структур языка Swift, а не конструкторы, унаследованные от CGGeometry.
Следует писать так:
let bounds = CGRect(x: 40, y: 20, width: 120, height: 80)
let centerPoint = CGPoint(x: 96, y: 42)
А не так:
let bounds = CGRectMake(40, 20, 120, 80)
let centerPoint = CGPointMake(96, 42)
Используем более компактные варианты оформления объявлений переменных и констант, оставив задачу определения типа компилятору. Исключением являются только те случаи, когда необходимо объявить переменную/константу специфического типа, например, CGFloat
или Int16
.
Следует писать так:
let message = "Click the button"
let currentBounds = computeViewBounds()
var names = [String]()
let maximumWidth: CGFloat = 106.5
А не так:
let message: String = "Click the button"
let currentBounds: CGRect = computeViewBounds()
var names: [String] = []
Замечание: Выбор говорящих названий еще более важен, чем раньше, если следовать вышенаписанному предписанию.
Используем компактные варианты оформления объявления массивов и строк.
Следует писать так:
var deviceModels: [String]
var employees: [Int: String]
var faxNumber: Int?
А не так:
var deviceModels: Array<String>
var employees: Dictionary<Int, String>
var faxNumber: Optional<Int>
В Swift не требуется ставить точку с запятой в конце каждого оператора. Этот знак необходим, только если Вы хотите объединить несколько операторов в одной строке.
Не надо так делать.
Следует писать так:
let swift = "not a scripting language"
А не так:
let swift = "not a scripting language";
Замечание: В этом вопрсе Swift сильно отличается от JavaScript, в котором опускание точек с запятой, как правило, небезопасно.
В спорных ситуациях используем американский английский, чтобы обеспечить соответствие всем API компании Apple.
Следует писать так:
let color = "red"
А не так:
let colour = "red"
- Стили кодирования
- [Java](Код стайл для языка Java)
- [C/C++](Стиль написания кода на С )
- [C#](Стиль написания кода на С# )
- [Swift](Руководство по оформлению кода на языке Swift )
- Написание комментариев к коммитам
- Android
- Android DevGuide
- [QR codes](Работа c QR на Android)
- [Полезные вещи](Полезные вещи для Android разработки)
- [Архитектура приложения](Архитектура приложения)
- [Используемые компоненты](Используемые компоненты)
- [Инструкция по сборке проекта](Инструкция по сборке проекта)
- iOS
- [Код на C++ под iOS](Использование кода и библиотек cpp при создании приложений на языке Swift)
- Стилевые таблицы NSS
- Структура проекта в Xcode
- Clean Architecture
- C и C++
- [Использование CMake для проектов на C++ и C ](Использование CMake для проектов на C и CPP)
- Форматы файлов
- [.bmp](Cтруктура хранения bmp файлов)
- [.jpg](Cтруктура хранения jpg файлов)
- [.png](Cтруктура хранения png файлов)
- Алгоритмы шифрования
- Кодирование информации псевдослучайными последовательностями чисел
- Визуальная криптография
- Схема разделения секретной визуальной информации
- Шифрование RGB изображения с помощью Фурье образа
- RSA-шифрование .bmp файлов
- Примеры использования
- [Библиотека матричной алгебры](Пример использования библиотеки матричной алгебры)
- Описание процесса кодирования файла
- Способ обезопасить использование приложения
- Java фасад библиотеки алгоритмов
- Алгоритм шифрования bmp на java заглушке
- Матричная арифметика
- [A+B](Сложение матриц)
- [A*p](Умножение матрицы на скаляр)
- [A*B](Умножение матриц)
- [Обратные матрицы](Нахождение обратной матрицы)
- Взятие по модулю
- [A
mod
p](Взятие матрицы по модулю простого числа) - [A
mod
P](Взятие матрицы по модулю - матрицы из простых чисел)
- Суперпозиция (модуль - простое число)
- [A+B
mod
p](Сложение матриц по модулю простого числа) - [A*c
mod
p](Умножение матрицы на скаляр по модулю простого числа) - [A*B
mod
p](Умножение матриц по модулю простого числа)
- Суперпозиция (модуль - матрицы из простых чисел)
- [A+B
mod
P](Сложение матриц по модулю - матрице простых чисел) - [A*c
mod
P](Умножение матрицы на скаляр по модулю - матрице простых чисел) - [A*B
mod
P](Умножение матриц по модулю - матрице простых чисел)
##Прочее
- [Утечки памяти](Memory Leaks)
- [Базовые цвета](Базовые цвета)
- [Clean Architecture](Clean Architecture)