Генерация последовательностей

Протокол 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

Среда 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
Playground live animation