Статьи

Swift с точки зрения разработчика Objective-C

Первоначально написанный на Дилана Tian

После последней WWDC большинство разработчиков iOS не говорят о новых интересных функциях iOS 8 или API. Вместо этого они говорят о совершенно новом языке: Swift. Да, вы правильно поняли — совершенно новый язык программирования. Как это интересно!

Apple тайно работает над Swift уже несколько лет. Это современный язык программирования, который использует сильные стороны других популярных языков (например, Python) и избегает плохих вещей в Objective-C (например, плохое ручное управление памятью и ужасный блочный синтаксис). Как заявлял Apple, это Objective-C без C. Кроме того, Swift также может получить доступ к инфраструктуре Apple Cocoa Touch и использовать тот же компилятор LLVM, что и Objective-C, так что они могут легко смешиваться в одном проекте.

Теперь вы можете быть похожи на меня, задаваясь вопросом, почему Apple представит новый язык для программирования на iOS и Mac OS. Давайте пройдемся по самым захватывающим частям Swift, чтобы узнать, сможем ли мы найти причину.

Типы

Вывод типа, вероятно, является причиной № 1, почему я предпочитаю использовать Swift вместо Objective-C. На самом деле, я думаю, что это самая удобная функция Swift. В Swift большую часть времени нам не нужно писать аннотации типов. Компилятор Swift будет определять соответствующие типы из значения переменных. Из-за вывода типа размер нашего кода был уменьшен. 

Swift также является языком, безопасным для типов. Он выполняет проверку типов при компиляции нашего кода, чтобы убедиться, что нет несовпадающих типов. Это одно из огромных различий между Objective-C и Swift. Objective-C предоставляет динамическое время выполнения, что означает, что он решает, какую реализацию метода вызывать прямо перед этим. Если метод не был реализован, вы даже можете перенаправить вызов на другой объект.

В Swift, поскольку компилятор проверяет все типы, при вызове метода вместо динамического вызова компилятор будет напрямую вызывать правильную реализацию в нужных местах. По сравнению с Objective-C Swift не только позволяет нам быстрее находить ошибки, но и повышает скорость выполнения.

Затворы

Блоки чрезвычайно полезны в Objective-C. Мы используем блоки для передачи автономных функций в нашем коде — например, обратных вызовов событий. Однако синтаксис блоков в Objective-C просто ужасен. Даже опытный разработчик все еще должен использовать шаблоны при написании блоков.

В Swift мы избегаем этой боли и используем замыкания для передачи функций. Замыкания аналогичны блокам, но с более четким, элегантным и упрощенным стилем кодирования. Вот пример объявления метода, который принимает блок, и последующего вызова этого метода:

1.  Цель-C:

//Define a method that accept two integers and a block as
// parameters
- (void)doSomethingWithFirstValue:(int)firstvalue
                      secondValue:(int)secondvalue
                            block:(int (^)(int, int))block {
   int result = block(firstvalue, secondvalue);
   NSLog(@"%d", result);
}
...
//A block add two integers together and return the result
[self doSomethingWithFirstValue:3
                    secondValue:7
                          block:^(int firstValue, int secondValue) {
      return firstValue + secondValue;
}];

2.  Свифт:

//Define a function that accept two integers and a closure as
// parameters
func doSomethingWithClosure(firstValue:Int,
        secondValue:Int, closure:(Int,Int) -> Int) {
    let result = closure(firstValue, secondValue)
    println(result)
}
...
//A closure add two integers together and return the result
doSomethingWithClosure(3, 7, {(firstValue:Int, secondValue:Int)->;Int  in
    return firstValue + secondValue
})

Благодаря выводу типа мы можем упростить его еще больше:

doSomethingWithClosure(3, 7, {(firstValue, secondValue)  in
    return firstValue + secondValue
})

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

doSomethingWithClosure(3, 7) {(firstValue, secondValue)  in
    return firstValue + secondValue
}

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

doSomethingWithClosure(3, 7) {(firstValue, secondValue)  in
    firstValue + secondValue
}

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

doSomethingWithClosure(3, 7) {
    $0 + $1
}

Ницца!

По сравнению с блоками замыкания легко писать и читать, особенно когда нам нужно передать действительно длинную функцию. Помимо синтаксиса, замыкания также более гибкие. Например, замыкание позволяет нам напрямую возвращать несколько типов. Чтобы добиться того же результата с блоками, мы должны поместить возвращаемые значения в коллекцию, а затем вернуть эту коллекцию.

Затворы более широко используются в Swift, чем вы думаете. На самом деле есть три различных типа закрытия. Функции — это просто особый тип именованного замыкания.

Подобно блокам в Objective-C, замыкания могут сохранять значения из своего контекста, удерживая сильные ссылки или просто копируя значения. К счастью, в большинстве случаев нам не нужно заботиться об управлении памятью замыканий; Swift делает это для нас автоматически. 

Optionals

Если вы пришли из Objective-C, вы должны быть знакомы с ноль. В принципе, вы можете установить указатель на ничто в любое время. Вместо нуля Apple ввела понятие «опциональных» в Swift, которое обрабатывает отсутствие значения. Как работают дополнительные устройства? Необязательный это что-то вроде коробки. Когда мы определяем значение как необязательное, мы фактически помещаем значение в поле. Материал внутри коробки может быть либо самим значением, либо нулем.

Чтобы определить необязательный тип, мы просто добавляем ?метку ‘ в конце исходного типа:

//Here we define an optional type
let aString: String? = "hello world"

Соответственно, когда мы пытаемся использовать вещи внутри коробки, мы должны сначала достать их из коробки. Здесь мы добавляем знак ‘ !‘ в конце, чтобы принудительно развернуть значение.

//To force to unwrap
let unwrappedString = "The stuff in the box is " + aString!

На самом деле, в этом простом примере есть ошибка. ! следует использовать только тогда, когда мы знаем, что у нас есть значение, иначе это приведет к ошибке во время компиляции. Поэтому мы почти всегда должны делать проверку, прежде чем развернуть коробку.

//Here we do optional binding.
let aString: String? = "hello world"
if let unwrappedString = aString {
    println("The stuff in the box is " + unwrappedString)
} else {
    println("Nothing in the box")
}

Здесь мы сделали необязательную привязку, чтобы получить необязательный тип. Делая это, нам не нужно добавлять! в конце больше. Swift проверит, равен ли он нулю, и присвоит значение соответственно.

Есть некоторые огромные различия между Objective-C и Swift при использовании nil. В Objective-C мы можем указать любой объект на ноль в любое время. Однако в Swift только опциональные значения могут быть nil, что означает, что неопциональные типы никогда не могут быть nil. Это заставляет нас тщательно обдумывать, когда мы действительно хотим использовать ноль. Например, если функция ожидает возврата строки, она должна вернуть строку, и эта строка не может быть nil.

В Objective-C только объекты могут указывать на ноль. Но в Swift мы можем установить любое значение по желанию. Потому что под капотом опционные функции — это просто простое перечисление, которое содержит none и универсальный тип. Все это является еще одним доказательством того, что Swift является языком, безопасным для типов.

Дженерики

Последнее, что я хотел бы отметить в Swift — это дженерики. Дженерики — это новое мощное оружие, которого нет в Objective-C. При использовании дженериков мы могли бы сначала использовать тип заполнителя, а затем определить этот конкретный тип. Поскольку swift является строго типизированным языком и очень строг по отношению к типам, дженерики обеспечивают некоторую необходимую гибкость Например, вот функция, которая принимает общие параметры:

//compare a and b, if a > b, return true, else return false
func compare<T:Comparable> (a:T, b:T) ->; Bool {
    return a > b;
}

Передав универсальные параметры, теперь мы можем сравнивать любые типы параметров, если этот параметр реализует быстрые сопоставимые протоколы. На самом деле, понимаете ли вы это или нет, когда мы пишем Swift, мы везде используем дженерики. Потому что дженерики были глубоко встроены в стандартную библиотеку Swift. Например, в Swift массивы и словари являются общими коллекциями. И, как я упоминал ранее, optionals — это enum, который содержит в себе универсальный тип. Apple настоятельно рекомендует нам использовать дженерики для написания более гибких, многократно используемых функций. Apple также очень хорошо рассмотрела некоторые продвинутые общие темы на сессии 404 WWDC 2014.

В заключение 

Как новый язык программирования, Swift имеет действительно чистый и понятный стиль. Он сочетает в себе преимущества Objective-C с возможностями современных языков сценариев. С точки зрения скорости, это также быстрее, чем Objective-C. Для разработчиков Apple Xcode 6 также поддерживает Swift «живое кодирование», которое сразу показывает результаты во время набора текста, позволяя программистам легче отлаживать и исследовать.

Самое главное, чистый синтаксис Swift и мощные инструменты отладки привлекут больше людей для изучения программирования на iOS. Благодаря повышению скорости работы приложений клиенты также могут использовать более качественные приложения. Я думаю, что, представив Swift, Apple намерена ускорить процесс разработки приложений и привлечь как больше клиентов, так и разработчиков.

С другой стороны, поскольку Objective-C долгое время доминировал в программировании под iOS, у него огромное количество сообществ поддержки и сторонних библиотек. Это не будет легко заменено полностью Swift. Так что в течение долгого времени, я думаю, они оба будут существовать в области разработки iOS. Но лично я уже предпочитаю писать код со Swift.