Эта статья — результат изучения стиля Swift из The Pragmatic Bookshelf и жизненного опыта. Это руководство может использовать iOS-инженер любого уровня.

У вас не было понятия о стилевом коде

когда вы впервые начали писать программное обеспечение. Вероятно, удачная компиляция была фантастической. Однако с годами разработка фреймворка стилей кода необходима для полезности и означает наличие опыта. Некоторые из этих советов основаны на повышении производительности, а другие — на чистом визуальном стиле.

Стилизация фигурных скобок в Swift

прост. Если вы хотите ухаживать за своими коллегами, поделитесь этими занудными битами…

Существует 2 стиля форматирования фигурных скобок. Первый, One True Brace Style, насколько я знаю, напыщенный, известен как 1TBS.

1 ТБ Стиль

If let x = x {
// code
} else {
// code
}

Второй — стиль Allman, также известный как стиль BSD.

Оллман

If let x = x 
{
// code
} 
else 
{
// code
}

Без ведома многих программистов Swift, мы в подавляющем большинстве следуем стилю 1TBS. Однако стиль Allman может пригодиться в ситуациях, когда вам нужна лучшая читабельность. Вы можете использовать гибридный подход обоих в одной области.

Избегайте нетерпеливых оценок с помощью ключевого слова Lazy

при использовании функций высокого порядка. Lazy, конечно, задержит вычисление до тех пор, пока не понадобится функция более высокого порядка. Это избавит вас от ненужного создания массивов.

let newCars = allCars.lazy.filter({$0.isNew})

Сложные операторы Guard в Swift

должны быть помещены под индивидуальную охрану, а не числиться группами.

func validateScore() {

//Prefer
guard let score = score else {return}
guard score.isEmpty else {return}
guard let validator = validator else {return}


//Avoid 
guard let score = score,
      score.isEmpty,
      let validator, validator
else {return}
}

Этот стиль позволяет вам легко комментировать отдельные операторы защиты и настраивать вертикальный интервал для комментариев.

Объединение и Тернарные операторы

могут оказаться уместными в подобных сценариях. Swift Style рекомендует отдавать предпочтение объединению из-за его краткости и ясности.

//Prefer
backgroundColor ?? .grey

//Avoid
backgroundColor == nil ? .grey : backgroundColor!

При использовании тернарного оператора стек «?» и «:» вертикально вот так…

backgroundColor == nil 
? .grey 
: backgroundColor!

По моему опыту, ваш наставник, коллеги и будущий я будут аплодировать такому стилю форматирования, потому что коммиты, изменяющие значения, повлияют только на одну строку. Если я изменю .grey на .white, это будет хорошо видно в PR.

Коллекции Стайлинга

является прямым, дайте каждому элементу отдельную линию и оставьте замыкающую скобку. Это, опять же, помогает в написании чистых PR.

// Prefer
let carColors: [String: UIColor] =
[
  "Corvette": .yellow,
  "Tesla Model Y": .black,
  "Toyota Tundra": .blue
]

//Avoid
let carColors: [String:UIColor] = ["Corvette": .yellow,
  "Tesla Model Y": .black,
  "Toyota Tundra": .blue]

//Short collections like this are okay
let nascarNumbers: [Int] = [1, 23, 44, 62]

При добавлении коллекций

предпочитаю append(contentsOf:) и append() вместо «+». «+=» вызывает append(contentsOf:).

//Prefer 
cars.append(contentsOf: mustangs)

//Prefer
cars += mustangs

//Avoid
cars + mustangs

Более быстрая и чистая итерация опций

можно легко выполнить с помощью сопоставления с образцом case let. Оба этих шаблона делают одно и то же, за исключением того, что case let намного чище.

//Prefer
for case let pet? in pets {
}

//Avoid
for pet in pets {
  if let pet = pet {
  }
}

Будьте более описательными с forEach

или используйте цикл for in, чтобы быть более наглядным.

//Prefer
for car in cars {print(car)}

//Prefer
cars.forEach {car in access(car)}

//Avoid
cars.forEach {access{$0}}

Целочисленная читабельность

можно упростить с помощью этой тактики подчеркивания.

//Prefer
let usBankruptValue: Int = 7_000_000

//Avoid
let usBankruptValue: Int = 7000000
//What number is this ^ you mean I have to count the zeros now?

Swift игнорирует подчеркивание во время компиляции. Придерживайтесь естественного шаблона, обозначающего продвижение на 3 места.

Объявления типов

Должен быть последовательным, и мы должны избегать полагаться на вывод типа. Будьте как можно более описательными со значениями, потому что 20 может быть целым числом или двойным числом, но 20,0 не может быть целым числом.

//Prefer
let leadingConstant: CGFloat = 20.0

//Avoid
let leadingConstant: CGFloat = 20

//Avoid
let leadingConstant = 20.0 as CGFloat

Придерживайтесь согласованных объявлений типов и, если позволяет руководство по стилю вашей компании, отдавайте предпочтение объявлениям типов перед знаком «=».

//Prefer 
let cars: [String] = []

//Prefer Repeating When Possible
let cars: [String] = .init(repeating: "Chevy", 6)

//Avoid
let cars = [String]()

Предпочитаю литье или литералы

чтобы избежать дополнительных вызовов функций. В следующем примере avoid мы без необходимости используем инициализатор UInt.

//Prefer
let carNumber: UInt8 = 8

//Avoid
let carNumber = UInt(8)

С наборами опций

быть как можно более описательным с аргументами. Отличным примером из Swift Style является…

//Prefer
accessQueue.sync(flags: [.barrier])

//Avoid
accessQueue.sync(flags: .barrier)

Пусть скобки передают идею о том, что можно добавить больше вариантов.

При работе с опционами

вы можете использовать синтаксический сахар Swift, чтобы обеспечить более четкое сопоставление с образцом.

//Prefer
switch (optionalOne, optionalTwo) {
  case let (first?, second?):...
}

//Avoid
switch (optionalOne, optionalTwo) {
  case let (.some(first), .some(second):...
}

Более чистые объявления кортежей

может сократить блоки кода по вертикали и позволить вам объявлять связанные элементы в одном и том же месте.

//Maybe use this
var (carId, mpg) = (1395, 32)

//Maybe use this
var carId = 1395
var mpg = 32

//Avoid
var carId = 1395; var mpg = 32

Замена с помощью кортежей может быть выполнена быстрее, чем классический способ установки временного значения…

//Prefer
(x, y) = (y, x)

//Prefer - write a function to swap
swap(&first, &second)

//Avoid
let tmp = second
second = first
first = tmp

Использовать затенение с одинаковым именем

при разворачивании опций…

//Prefer
guard let car = car else {return}

//Avoid
guard let mustang = car else {return}

Это может помочь вам избежать конфликтов имен за пределами области видимости и свести к минимуму необходимость использования self.

Вы также можете развернуть с помощью ключевого слова var…

//Prefer, mutable car
if var car = car {}

//Avoid
if let car = car {

  //Making car mutable
  var variableCar = car
}

Используйте ключевое слово «есть»

чтобы проверить, могут ли ключевые слова со стертым типом быть разрешены как другой тип. Это может быть полезно, если вам не нужно выполнять приведение типов.

if object is car {
  print("")
}

Пытаться?

следует зарезервировать для случаев, когда вам все равно, почему операция не удалась. Вместо этого используйте шаблон do-catch.

//Prefer
do { try requestCars() }
catch { assertionFailure("Request Cars Failed") }

//Avoid
let cars = try? requestCars()

Когда нужны только индексы

вы можете перебирать их напрямую без перечисления.

//Prefer
for carIdx in cars.indices {
}

//Avoid
for (index, _) in cars.enumerated {
}

Обновите свои операторы Switch

с предложениями where. Кроме того, выровняйте ключевые слова case по вертикали с ключевым словом switch.

switch car.isBlack() {
//If car is available do something
case true where car.isAvailable(): ...
//If true and unavailable do something else
case true: ...
default:...
}

Предпочитайте двойные числа, а не поплавки

поскольку двойники более точны. Двойное число содержит 15 десятичных цифр, а число с плавающей запятой имеет точность 9.

Предпочитайте Int UInt (или другим вариантам)

Int поддерживает лучшую совместимость. В 32-битной системе Int равен 32 битам. В 64-битной системе целое число равно 64 битам. Это не относится к Int32 или Int64 с фиксированным размером.

Следует использовать неявное «я»

по возможности для краткости. Избегайте явного вызова себя, когда это не нужно.

struct Car {
  var color: UIColor? = .black
  
  mutating func changeColor() {
    
    //Prefer
    color = .white
  
    //Avoid
    self.color = .white
  }
}

Предпочитайте слабый захват, а не неизвестный

поскольку weak безопаснее, unowned предназначен для объектов с гарантированным сроком службы.