Протокол Strideable, реализуемый основными числовыми типами, позволяет легко и быстро создавать ограниченные числовые последовательности по принципу арифметической прогрессии.
Метод stride принимает на вход граничное значение последовательности и шаг. А вариант его вызова с to или through определяет вхождение самой границы (если на ней останавливается расчет) в конечный результат (to — не войдет, through — войдет).
import Foundation
for i in 1.stride(to: 25, by: 3) {
// 1, 4, 7, 10, 13, 16, 19, 22
// 25 excluded
}
for j in 1.stride(through: 25, by: 3) {
// 1, 4, 7, 10, 13, 16, 19, 22, 25
// 25 included
}
for k in 6.stride(through: 1, by: -2) {
// 6, 4, 2
}
Если в логике требуется взять значение по умолчанию вместо пустого, можно воспользоваться тернарным выражением. Но наиболее изящным будет применение специального оператора «??».
import Foundation
let dividend: Double = 222
let divisor: Double? = nil
dividend / (divisor == nil ? 1 : divisor!)
dividend / (divisor ?? 1)
В языке Swift типы делятся на две группы: типы значений и ссылочные.
К типам значений относятся перечисления и структуры (например, стандартные строки, числа, словари и массивы относятся к ним). Переменные с таким типом содержат непосредственно само значение, а переприсвоение между ними происходит через полное копирование этого значения.
import Foundation
var firstValue: Double = 11
var secondValue: Double = firstValue
secondValue += 1
print(firstValue)
// 11
print(secondValue)
// 12
Ссылочными типами являются классы и замыкания (они же блоки). Такие переменные хранят только ссылку на объект, но не его сам, а копирование производится путем создания еще одной ссылки.
import UIKit
var firstView: UIView = UIView()
var secondView: UIView = firstView
print(firstView.tag)
//0
secondView.tag = 10
print(secondView.tag)
// 10
print(firstView.tag)
// 10
К преимуществам значений относятся простота использования и безопасность работы с ними при конкурентном программировании, так как другой поток не сможет изменить ваши данные.
Ссылочные же типы наоборот, могут создать трудности в многопоточных приложениях, но позволяют экономить память, держа в ней лишь небольшое число общих экземпляров. Однако, чтобы при этом не столкнуться с утечкой памяти, нужно понимать механизм ее управления и очистки. В Swift за это отвечает Automatic Reference Counting (ARC), подсчитывающий количество ссылок на каждый объект. И только при снижении этого показателя до нуля объект деинициализируется и удаляется из памяти.
В большинстве случаев ARC прекрасно справляется со своей работой самостоятельно. За исключением зацикливаний, когда один объект имеет ссылку на другой, а тот на него. В этой ситуации разработчику необходимо сделать одну из ссылок «слабой» (не учитываемой ARC), превратив связь в одностороннюю. Для этого служат ключевые слова weak (с необязательными переменными) и unowned (с обязательными).
import Foundation
class ControllerPart {
var controller: Controller?
init(controller: Controller) {
self.controller = controller
}
}
class Controller {
var part: ControllerPart?
deinit {
print("Controller deleted")
}
}
var controller: Controller? = Controller()
var controllerPart: ControllerPart? = ControllerPart(controller: controller!)
controller!.part = controllerPart!
controller = nil
/*
Controller not deleted, because controllerPart still has a reference to it.
But if we make this reference weak:
weak var controller: Controller?
or
unowned var controller: Controller
Controller deleted
*/
У замыканий это делается в списке захвата.
import Foundation
class Mechanism {
var strength = 0
lazy var action: () -> Void = {
[unowned self] in
self.strength++
}
deinit {
print("Mechanism deleted")
}
}
var mechanism: Mechanism? = Mechanism()
// Make lazy property active
mechanism?.action()
mechanism = nil
// Mechanism deleted
Дополнительные материалы:
Отличие ленивых свойств от обычных в моменте установки их начальных значений. У ленивых это происходит во время первого обращения к ним, а не при инициализации экземпляра. Эта особенность позволяет сдвинуть исходное задание тяжело вычисляемых свойств на потом, до их фактической надобности.
import Foundation
class Message {
private(set) var lastText: String?
lazy var text: String = {
// Very long calculations...
let value = "I'm lazy"
self.lastText = value
return value
}()
}
let message = Message()
print(message.lastText)
// nil
print(message.text)
// I'm lazy
print(message.lastText)
// I'm lazy
Среда Playground, впервые появившаяся в Xcode 6, незаменима для быстрого прототипирования, разработки и тестирования алгоритмов. Однако, по умолчанию в ней не отображается анимация графических объектов. Чтобы это исправить, необходимо импортировать модуль XCPlayground и задать у текущей страницы свойство liveView. После этого Assistant Editor (включается в меню View → Assistant Editor → Show Assistant Editor) станет показывать динамические изменения.
import UIKit
import XCPlayground
let view = UIView(frame: CGRect(x: 0, y: 0, width: 500, height: 500))
view.backgroundColor = UIColor(white: 0.9, alpha: 1)
let animator = UIDynamicAnimator(referenceView: view)
let gravity = UIGravityBehavior()
let collision = UICollisionBehavior()
collision.translatesReferenceBoundsIntoBoundary = true
for i in 1...50 {
let item = UIView(frame: CGRect(x: Int(arc4random_uniform(480)),
y: Int(arc4random_uniform(100)),
width: 20,
height: 20))
item.backgroundColor = UIColor(red: CGFloat(drand48()),
green: CGFloat(drand48()),
blue: CGFloat(drand48()),
alpha: 1)
gravity.addItem(item)
collision.addItem(item)
view.addSubview(item)
}
animator.addBehavior(gravity)
animator.addBehavior(collision)
XCPlaygroundPage.currentPage.liveView = view