Connect with us

Программирование

7 ключевых слов Swift, которые вы не используете (а следовало бы)

В этой статье мы рассмотрим 7 ключевых слов Swift, которые вас поразят.

Опубликовано

/

     
     

Swift мощнее, чем вы думаете. Большинство разработчиков используют лишь около 60% его потенциала, и есть много функций, которые вы не использовали или о которых даже не слышали.

В этой статье мы рассмотрим 7 ключевых слов Swift, которые вас поразят.

1. some

Вы всё чаще видите ключевое слово some в коде.

struct ContentView: View {
        
    var body: some View {
        
        Label("Cart", systemImage: "cart")
            .font(.largeTitle)
        
    }
}

Ключевое слово some относится к определённому типу данных, который вы не хотите раскрывать никому.

Рассмотрим пример:

func AppButton() -> some View {
    Button("Click Here") {
       
    }
}

В приведённом выше коде AppButton возвращает «некое представление». Это означает, что не обязательно возвращать только кнопку; можно вернуть любое представление, например VStack или текст.

Если мы хотим вернуть конкретное представление, например кнопку, то это следует записать так:

func AppButton() -> Button<Text> {
    Button("Click Here") {
       
    }
}

Если вы попытаетесь вернуть любой View, отличный от Button, вы получите ошибку компилятора.

7 ключевых слов Swift, которые вы не используете (а следовало бы)

Чаще всего some используется с протоколами или непрозрачными типами возвращаемых данных. Давайте рассмотрим другой пример с протоколами.

protocol Shape {
    func area() -> Double
}

struct Circle: Shape {
    var radius: Double
    func area() -> Double { .pi * radius * radius }
}

struct Recta: Shape {
    var radius: Double
    func area() -> Double { 2*(.pi * radius * radius) }
}


func makeShape() -> some Shape {
    Circle(radius: 5)
}

Мы создали протокол Shape, соответствующий классам Circle и Rectangle, а впоследствии и другим классам.

Мы возвращаем Shape с помощью функции makeShape(), и теперь Shape может быть либо Circle, либо Rectangle.

При каждом вызове makeShape() функция не знает, какой это тип фигуры. Это также полезно, когда нужно скрыть некоторую информацию и показать только необходимое.

2. unowned

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

Когда вы создаёте объект, Swift сохраняет его в памяти до тех пор, пока на него что-то ссылается.

class User {
    var name: String
    init(name: String) { self.name = name }
}

var user = User(name: "Jayant")

В данном случае объект пользователя строго владеет классом User, и класс User остаётся в памяти до тех пор, пока существует объект пользователя.

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

class AppUser {
    var name: String
    var add: Address?
    init(name: String) { self.name = name }
}

class Address {
    var appUser: AppUser?
    var address:String?
}

let user = AppUser(name: "Jayant")
let appUser = Address()

Здесь классы AppUser и Address владеют друг другом, что может привести к утечкам памяти.

Если объект AppUser уничтожен, Address сохраняет его в памяти, а если объект Address уничтожен, AppUser сохраняет его в памяти, поскольку оба объекта указывают друг на друга, и этот цикл продолжается бесконечно.

Чтобы разорвать этот цикл, используйте ключевое слово unowned.

class AppUser {
    var name: String
    var add: Address?
    init(name: String) { self.name = name }
}

class Address {
    unowned var appUser: AppUser?
    var address:String?
}

AppUser владеет Address, а Address ссылается на AppUser, но не поддерживает его живым. После уничтожения объекта AppUser Swift автоматически удаляет оба объекта.

3. @frozen

Это ключевое слово обычно используется с enum и struct для обеспечения их стабильности.

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

Тогда вы можете пометить его ключевым словом @frozen, и Swift будет быстрее принимать решения и получать доступ.

Рассмотрим пример:

@frozen public enum ApiStatus {
    case Success
    case Error
    case Loading
}

Здесь у нас есть перечисление ApiStatus, и мы уверены, что его пространство имён (Success, Error, Loading) не изменится в будущем; поэтому мы пометили его ключевым словом @frozen.

Ключевое слово @frozen в основном используется разработчиками библиотек и Apple для блокировки типа для повышения производительности.

Например, Apple использует ключевое слово @frozen в стандартной библиотеке.

@frozen public enum Bool {
    case true
    case false
}

Мы знаем, что тип Bool имеет фиксированные значения, такие как true и false, и никогда не добавляет никаких новых типов, поэтому он отмечен ключевым словом @frozen.

4. associatedtype

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

Поясним на примере:

protocol Users {
    associatedtype Item
    
    func getItem() -> Item
    
    func getItems() -> [Item]
}

Здесь мы создаём протокол, в котором переменная item используется с ключевым словом associatedtype. Переменная item имеет общий тип, такой как Int, String, Bool и т. д.; любой класс, соответствующий протоколу Users, определит её тип данных.

class AdminUser : Users {
    
    typealias Item = String
    
    func getItem() -> Item {
        <#code#>
    }
    
    func getItems() -> [Item] {
        <#code#>
    }
    
}

Как видите, AdminUser соответствует протоколу Users; он определяет тип данных String, и теперь Item — это тип данных String, используемый с остальными функциями.

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

5. @autoclosure

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

Как следует из названия, оно автоматически оборачивает выражение в замыкание, поэтому вам не нужно писать замыкание ( {} ).

Давайте разберёмся на примере:

func printIfTrue(_ isTrue: () -> Bool) {
    if isTrue() {
        print("The condition is true!!!")
    }
}

Это функция, которая принимает замыкание в качестве параметра и возвращает логическое значение.

Теперь, когда мы где-либо вызываем эту функцию, нам нужно записать её так:

printIfTrue{2 > 1}

Нам нужно писать фигурные скобки, так как это замыкание.

Можно ли что-то сделать, чтобы не писать фигурные скобки каждый раз? Например:

printIfTrue(2 > 1)

Да, давайте добавим ключевое слово @autoclosure к замыканию.

func printIfTrue(_ isTrue: @autoclosure () -> Bool) {
    if isTrue() {
        print("The condition is true!!!")
    }
}

Мы добавили ключевое слово @autoclosure, которое позволяет нам писать так:

printIfTrue(2 > 1)

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

6. @discardableResult

У вас есть функция, которая что-то возвращает, но вы не использовали её значение — при компиляции будет выдано предупреждение.

⚠️ Result of call to ‘function’ is unused

func sum(x: Int, y: Int) -> Int {
    return x + y
}

Выше пример функция суммы. Когда мы где-то используем эту функцию и не используем ее значение, компилятор выдаст предупреждение.

7 ключевых слов Swift, которые вы не используете (а следовало бы)

Чтобы решить эту проблему, используйте ключевое слово @discardableResult.

Добавьте @discardableResult к функции суммы.

@discardableResult
func sum(x: Int, y: Int) -> Int {
    return x + y
}

Теперь всё выглядит нормально.

7. @_specialize

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

Использование дженериков с функциями означает, что вы можете определить любой тип данных, например, Int, String, Bool и т.д., во время выполнения. Но эта гибкость иногда делает работу немного медленнее.

Предположим, вы создаёте дженерик с функцией и знаете, что в большинстве случаев вам придётся использовать с ней целочисленное значение. Тогда с помощью @_specialize вы можете указать тип Int в качестве типа по умолчанию. Это делает версию для целых чисел более быстрой.

Разберёмся на примере:

@_specialize(where T == Int)
func printSomething<T>(_ item: T) {
    print(item)
}

Здесь дженерик T — это тип Int по умолчанию для более быстрого доступа, но вы можете передать любое универсальное значение.

printSomething(5)        // uses the specialized (faster) version
printSomething("Hello")  // uses the generic version

Эта функция будет выполняться быстрее для типа Int.

Источник

Если вы нашли опечатку - выделите ее и нажмите Ctrl + Enter! Для связи с нами вы можете использовать info@apptractor.ru.
Telegram

Популярное

Сообщить об опечатке

Текст, который будет отправлен нашим редакторам: