Swift_rus Flashcards

Code examples and Q&A

1
Q

`struct Tutorial {
var difficulty: Int = 1
}

var tutorial1 = Tutorial()
var tutorial2 = tutorial1
tutorial2.difficulty = 2`

Чему равны значения tutorial1.difficulty и tutorial2.difficulty? Была бы какая-то разница, если бы Tutorial был классом? Почему?

A

tutorial1.difficulty равен 1, а tutorial2.difficulty равен 2.

В Swift структуры — типы-значения (value type). Они копируются, а не ссылаются. Следующая строка копирует tutorial1 и присваивает её tutorial2:

var tutorial2 = tutorial1

Изменения в tutorial2 не отражаются на tutorial1.

Если бы Tutorial был бы классом, tutorial1.difficulty и tutorial2.difficulty равнялись бы 2. Классы в Swift — ссылочные типы (reference type). Когда вы меняете свойство tutorial1, вы увидите такое же изменение у tutorial2 — и наоборот.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q

Вы объявили view1 при помощи var, а view2 — при помощи let. В чём разница и скомпилируется ли последняя строка?

import UIKit

var view1 = UIView()
view1.alpha = 0.5
let view2 = UIView()
view2.alpha = 0.5 // Эта строка скомпилируется?
A

Да, последняя строка скомпилируется. view1 — это переменная, и вы можете назначить её значение новым экземпляром UIView. Используя let, вы можете присвоить значение лишь однажды, так что следующий код не скомпилируется:

view2 = view1 // Ошибка: view2 is immutable

Однако, UIView — это класс со ссылочной семантикой, так что вы можете изменять свойства view2 — что означает, что код скомпилируется.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
Q

Этот код сортирует массив по алфавиту. Максимально упростите замыкание.

var animals = ["fish", "cat", "chicken", "dog"]
animals.sort { (one: String, two: String) -> Bool in
    return one < two
}
print(animals)
A

Swift автоматически определяет тип параметров замыкания и возвращаемый тип, так что вы можете убрать их:

animals.sort { (one, two) in return one < two }

Вы можете заменить имена параметров использованием нотации $i:

animals.sort { return $0 < $1 }

Замыкания, состоящие из одного оператора, могут не содержать ключевое слово return. Значение последнего выполненного оператора становится возвращаемым результатом замыкания:

animals.sort { $0 < $1 }

Наконец, так как Swift знает, что элементы массива соответствуют протоколу Equatable, вы можете просто написать:

animals.sort(by:

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q

Этот код создаёт два класса: Address и Person. Также создаются два экземпляра класса Person (Ray и Brian).

class Address {
  var fullAddress: String
  var city: String
  init(fullAddress: String, city: String) {
    self.fullAddress = fullAddress
    self.city = city
  }
}
class Person {
  var name: String
  var address: Address
  init(name: String, address: Address) {
    self.name = name
    self.address = address
  }
}
var headquarters = Address(fullAddress: "123 Tutorial Street", city: "Appletown")
var ray = Person(name: "Ray", address: headquarters)
var brian = Person(name: "Brian", address: headquarters)

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

brian.address.fullAddress = “148 Tutorial Street”

Это компилируется и выполняется без ошибок. Но, если вы проверите теперь адрес Ray, то вы увидите, что он тоже «переехал».

Что здесь произошло и как мы можем исправить это?

A

Address — это класс и обладает ссылочной семантикой. Таким образом, headquarters — это один и тот же экземпляр класса, который разделяют ray и brian. Изменение headquarters изменит адрес обоих.
Чтобы исправить это, можно создать новый экземпляр класса Address и присвоить его Brian, или объявить Address как struct вместо class.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
5
Q

Что такое optional и какие проблемы они решают?

A

optional позволяет переменной любого типа представить ситуацию “отсутствие значения”. В Objective-C «отсутствие значения» было доступно только в ссылочных типах с использованием специального значения nil. У типов-значений (value types), вроде int или float, такой возможности не было.
Swift расширил концепцию «отсутствия значения» на типы-значения. Переменная optional может содержать либо значение, либо nil, сигнализирующее об отсутствии значения.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
6
Q

Коротко перечислите основные отличия между structure и class.

A

Классы поддерживают наследование, а структуры — нет.

Классы — ссылочный тип, структуры — тип-значение.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
7
Q

Что такое generics и для чего они нужны?

A

В Swift вы можете использовать generics в классах, структурах и перечислениях.

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

Например, в этом коде вторая функция — это «клон» первой, за исключением того, что у неё параметры string, а не integer.

func areIntEqual(_ x: Int, _ y: Int) -> Bool {
  return x == y
}
func areStringsEqual(_ x: String, _ y: String) -> Bool {
  return x == y
}

areStringsEqual(“ray”, “ray”) // true
areIntEqual(1, 1) // true

Применяя generics, вы совмещаете две функции в одной и одновременно обеспечиваете безопасность типов:

func areTheyEqual(_ x: T, _ y: T) -> Bool {
  return x == y
}

areTheyEqual(“ray”, “ray”)
areTheyEqual(1, 1)

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

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
8
Q

В некоторых случаях не получится избежать неявного разворачивания (implicitly unwrapped) optionals. Когда и почему?

A

Наиболее частые причины для использования implicitly unwrapped optionals:

когда вы не можете инициализировать свойство, которое не nil в момент создания. Типичный пример — outlet у Interface Builder, который всегда инициализируется после его владельца. В этом особенном случае, если в Interface Builder всё правильно сконфигурировано — вам гарантировано, что outlet не-nil перед его использованием.
чтобы разрешить проблему цикла сильных ссылок, когда два экземпляра классов ссылаются друг на друга и требуется не-nil ссылка на другой экземпляр. В этом случае вы помечаете ссылку на одной стороне как unowned, а на другой стороне используете неявное разворачивание optional.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
9
Q

Какими способами можно развернуть optional? Оцените их в смысле безопасности.

var x : String? = “Test”

A

Принудительное развёртывание (forced unwrapping) — небезопасно.

let a: String = x!

Неявное развертывание при объявлении переменной — небезопасно.

var a = x!

Optional binding — безопасно.

if let a = x {
  print("x was successfully unwrapped and is = \(a)")
}

Optional chaining — безопасно.

let a = x?.count

Nil coalescing operator — безопасно.

let a = x ?? “”

Оператор Guard — безопасно.

guard let a = x else {
  return
}

Optional pattern — безопасно.

if case let a? = x {
print(a)
}

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
10
Q

Замыкания — это ссылочный тип или тип-значение?

A

Замыкания — это ссылочный тип. Если вы присваиваете переменной замыкание, а затем копируете в другую переменную, вы копируете ссылку на то же самое замыкание и его список захвата.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
11
Q

Опишите циклические ссылки в Swift? Как их можно исправить?

A

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

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

How well did you know this?
1
Not at all
2
3
4
5
Perfectly