Swift 5.3: Что нового?

    Привет Хабр! Язык программирования Swift обладает большой популярностью ввиду его использования в написании приложений под iOS, поэтому его развитие представляет интерес для всех занятых в этой области.

    Давайте посмотрим что нового приготовил разработчикам Swift версии 5.3.

    Multiple trailing closures


    Новая версия (SE-0279) предлагает новый синтаксис для конечных замыканий, который позволяет вызывать несколько замыканий в качестве параметров функции более читаемым способом. Это сводит к минимуму использование слишком большого количества скобок в сигнатуре функции.

    import Foundation
    
    func load(url: String, success: (Data) -> Void, failure: (Error) -> Void) {
        
    }
    
    // old  version
    
    load(url: "someURL", success: { data in }, failure: { error in })
    
    // new multiple trailing closures
    
    load(url: "someURL") { (data) in
        // do smth
    } failure: { (error) in
        // do smth
    }

    На примере 2 вариантов вызова видно, что визуально второй смотрится несколько приятнее.

    Multi-Pattern Catch Clauses


    В настоящее время каждый пункт catch в операторе do-catch может содержать только один шаблон. Чтобы обойти эту проблему, разработчики будут использовать возможности вариантов коммутаторов для включения сопоставления шаблонов в тело операторов catch, тем самым увеличивая вложенный и дублированный код (SE-0276).

    Catch-пункты теперь позволяют пользователю указывать разделенный запятыми список шаблонов с возможностью связывания переменных с телом catch — как в switch-е.

    enum NetworkError: Error {
        case failure, timeout
    }
    
    // old  version
    func networkCall(){
      do{
        try someNetworkCall()
      } catch NetworkError.timeout{
        print("timeout")
      } catch NetworkError.failure{
        print("failure")
      }
    }
    
    // new multi-Pattern catch clauses
    func networkCall(){
      do{
        try someNetworkCall()
      } catch NetworkError.failure, NetworkError.timeout {
        print("handle for both")
      }
    }

    Synthesized Comparable Conformance for Enums


    До сих пор сравнивать 2 элемента перечисления было не то что бы «приятным» делом. Надо было конформить Comparable и написать статическую функцию < для определения того, является ли исходное значение меньше другого.

    Теперь Swift (SE-0266) позволяет не «париться» над реализацией всех этих вещей, и не нужно явно реализовывать протокол, пока у вашего перечисления есть одинаковые типы. Если соответствующие значения не заданы, перечисления будут сравниваться по семантическому порядку объявления.

    enum Brightness: Comparable {
        case low(Int)
        case medium
        case high
    }
    
    ([.high, .low(1), .medium, .low(0)] as [Brightness]).sorted()
    // [Brightness.low(0), Brightness.low(1), Brightness.medium, Brightness.high]

    количество self-ов можно будет сократить


    Отныне можно опускать self в тех местах, где это больше не нужно (SE-0269). Ранее использование self в замыканиях было необходимо, когда мы захватывали значения из внешней области видимости.

    struct OldView: View {
    
        var body: some View {
            Button(action: {
                self.sayHello()
            }) {
                Text("Press")
            }
        }
        
        func sayHello() {}
    }
    
    struct NewView: View {
    
        var body: some View {
            Button {
                sayHello()
            } label: {
                Text("Press")
            }
        }
        
        func sayHello(){}
    }

    Where в generic-ах


    Новая версия языка (SE-0267) ввела возможность присоединять where к функциям внутри универсальных типов и расширений.

    struct Stack<Element> {
        private var array = [Element]()
    
        mutating func push(_ obj: Element) {
            array.append(obj)
        }
    
        mutating func pop(_ obj: Element) -> Element? {
            array.popLast()
        }
    }
    
    extension Stack {
        func sorted() -> [Element] where Element: Comparable {
            array.sorted()
        }
    }

    В стек можно добавить новый метод sorted (), но только для тех случаев, когда элементы внутри стека конформят Comparable.

    Новый тип Float16


    Введена Float16 плавающая точка половинной точности (SE-0277). С появлением машинного обучения на мобильных устройствах в последние годы это только указывает на амбиции Apple в продвижении данной темы. Float 16 обычно используется на мобильных графических процессорах для вычислений и в качестве сжатого формата для весов в приложениях, использующих ML.

    let f16: Float16 = 7.29

    Swift 5.3 ввел множество улучшений для Swift Package Manager (SPM). Рассмотрим же их.

    1. SE-0271 (Package Manager Resources) позволяет SPM содержать такие ресурсы, как изображения, аудио, JSON и многое другое.
    2. SE-0272 (Package Manager Binary Dependencies) позволяет SPM использовать бинарные пакеты наряду с существующей поддержкой исходных пакетов. Это означает, что общие SDK с закрытым исходным кодом, такие как Firebase, теперь могут быть интегрированы с помощью SPM.
    3. SE-0273 (Package Manager Conditional Target Dependencies) позволяет настроить целевые объекты так, чтобы они имели зависимости только для определенных платформ и конфигураций. Например, можно обозначить специальные дополнительные фреймворки при компиляции для Linux.
    4. SE-0278 позволяет добавлять локализованные ресурсы.

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

    Similar posts

    Ads
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More

    Comments 15

      +9
      А вот то что разрешили не использовать self в замыканиях мне не очень нравится, так как большинство утечек памяти как раз было связано с тем что люди забывают про то что self захватывается замыканием. Найти проблему было достаточно легко, просто через поиск «.self», сейчас же это будет чуть-чуть сложнее, так как «sayHello()» может быть и другим замыканием, которое было объявлено выше. Но посмотрим как оно пойдёт, может я не прав и это будет действительно лучше.
        0

        К счастью, сделано по уму: исключение сделано для типов значений, которые вовсе не передаются по ссылке, и если есть явное указание на тип self в замыкании, например ‘execute { [self] in’. И да, я тоже запускаю поиск по ‘self.’ для поиска утечек :)

          0
          как это помогает? достаточно давно можно писать без скобок
          guard let self = self else { return }
            0
            При self из числа value type можно не писать guard let self вообще, а в некоторых случаях, когда объект и так висит в памяти от начала до конца (сразу приходят в голову только синглтоны), можно просто указать [self] in вначале тела замыкания, и тоже сэкономить 5 символов в каждой строке. Как-то так :)
              0
              если висит в памяти от начала и до конца как при UIView.animate, то зачем указывать
              [self] in вначале тела замыкания
              ?
                +1
                Наверно, чтобы не заставляло дальше по тексту писать self.methodName или self.varName, — ну любят люди экономить по 5 букв, не знаю, что ещё сказать. Главное для меня то, что не убрали вообще self в замыканиях, так как это стало бы источником дополнительных ошибок.
                Висят в памяти от начала и до конца работы всего приложения. Замыкание animations: @escaping () -> Void наоборот не должно иметь в себе [self] in, если вызов происходит из самого View, так как это будет подвешивать его в памяти (View держит ссылку на @escaping замыкание, а замыкание — на View. В таком случае как раз нужен [weak self] in и всё дальше как обычно.
                  0
                  насколько понимаю, будет подвешивать в памяти в любом случае, так как анимация происходит на главном потоке и вызов completion гарантируется?
                    0
                    Немного не понял вопрос, что значит гарантируется?
                    В нормальной ситуации (без ошибочной ссылки из стороннего объекта на замыкание и без reatin cycle, когда замыкание и View удерживают друг друга) @escaping такая ситуация встречаться не должна.
                    Выполнение @escaping возможно, пока жив в памяти соответствующий экземпляр замыкания. Если не сохранять ссылку на замыкание специально, то на него держит сильную ссылку порождающий экземпляр класса (в данном случае View), а также может держать держать ссылку экземпляр CFRunLoopObserver (если не ошибаюсь) главного потока, в котором код выполняется асинхронно или другого потока, хотя анимация на другом потоке выполняться не должна вообще.
                    Если экземпляр View уничтожается и ссылка на замыкание не хранится где-то ещё, то runloop:
                    1) дойдет до обработки события счётчика ссылок и обнаружит, что количество ссылок на замыкание = 0, после чего объявит использовавшуюся под него память свободной. Продолжения расчётов для анимации не произойдет;
                    2) runloop на главном потоке увидит наличие удерживающей ссылки от другого потока на замыкание. В этом случае я затрудняюсь ответить, что происходит. Но думаю, что скорее всего сторонний поток завершит выполнение (уже ненужной анимации, потому её и нужно исполнять на главном!), перейдет обратно по стеку, отпустит последнюю ссылку на замыкание. После чего замыкание также будет уничтожено (а возможно и весь поток, если после этого у него пустует стек и нечего больше выполнять).
          0

          Тут скорее про такое поведение в структурах, ибо там это не опасно.

          0
          Поддержку windows в swift 5.3 пробывали? Какие грабли?
          Или пока только 4.1.3 можно использовать.
            +1
            Новая версия (SE-0279) предлагает новый синтаксис для конечных замыканий, который позволяет вызывать несколько замыканий в качестве параметров функции более читаемым способом. Это сводит к минимуму использование слишком большого количества скобок в сигнатуре функции.


            Смотрю на код, и в новом представлении насчитываю на 4 скобки больше, чем в старой версии
              0
              Да, я тоже этот момент не понял. То, что оно нагляднее выглядит, так это за счет indentation по моему.
                0
                Количество скобок не меняется, так как круглые скобки можно и в первом примере поставить. А вот запятых меньше становится.
                  0
                  Но пропало слово success. ИМХО, но тогда уже лучше исппользовать вот такую верстку
                  load(
                      url: "someURL", 
                      success: { data in }, 
                      failure: { error in }
                  )
                  

                    +1
                    Вот если бы ещё запятые при этом можно было не писать. А то напоминает о сишных точках с запятой в конце строки. Только тут ещё хуже, потому что после последней строчки запятая не ставится.

                    Было бы хорошо:
                    load(url: "someURL")
                    success: { data in
                    
                    }
                    failure: {error in 
                    
                    }
                    


                    Или:
                    load(
                        url: "someURL"
                        success: { data in
                    
                        }
                        failure: {error in 
                    
                        }
                    )
                    

              Only users with full accounts can post comments. Log in, please.