Swift это новый язык программирования от компаний Apple, который она презентовала в этом году на WWDC. Вместе с языком программирования, Apple выпустила отличный справочник по языку Swift, который я рекомендую прочитать или ознакомиться с ним. Тем не менее, читать книгу это очень долго! Так что если у Вас нет много времени и Вы просто хотите узнать о новом языке Swift, то эта статья для Вас.
В данной статье я бы хотел поделиться некоторыми размышлениями по поводу перехода от Objective-C к Swift. Я постараюсь дать Вам несколько советов и указать на недостатки при разном подходе к обеим языкам. Поэтому без лишних отступлений, перейдем к самой статье.
Первое, наиболее существенное изменение, которое стоит упомянуть, это отказ от структуры interface.h/implementation.m.
Должен признать, что я сторонник этой модели. Получение и обмен информацией о классе просто с помощью файла интерфейса является безопасным и быстрым.
В Swift интерфейса и реализации не разделены на два файла. Мы просто реализовываем наш класс (и в момент написания даже не представляется возможным добавить модификаторы видимости).
Если действительно сложно справляться с данным изменением, то можно использовать следующее: здравый смысл.
Мы можем легко увеличить читаемость наших классов хорошим документированием. Например, можно перемещать элементы, которые хотим сделать «публичными», в верхней части нашего файла используя расширения для разграничения данных, доступных для всех и личную информацию.
Еще один очень распространенный приём – ставить для приватных методов и переменных подчеркивание «_»
Вот небольшой пример их смешевания:
Хотя мы не можем изменить видимость элементов наших классов, можно попытаться сделать доступ к некоторым «более трудным» из них.
Нестандартным решением является использование вложенного класса, которое частично скрывает личные данные (по крайней мере, в автозаполнение)
Пример:
Мы помещаем приватную реализацию в приватный постоянный случай и используем «обычную» реализацию в класс в качестве общественного интерфейса. Приватные элементы, на самом деле, не скрыты, но для доступа к ним мы должны пройти через «приватные» константы.
Возникает вопрос: стоит ли это конечной цели, частичное скрытие личных элементов?
Мое предложение — ждать модификаторов видимости (Apple работает над этим), а пока использовать хорошее документирование с или без расширений.
В Objective-C я редко использовал константные ключевые слова, даже когда знал, что некоторые данные никогда не изменятся. В Swift, разработчики Apple предлагают использовать константу (let) вместо переменной (var). Так что просто следите за ней и попытайтесь выяснить роль ваших переменных. В конечном счете, Вы будете использовать больше констант, чем ожидаете.
Посмотрите на 2 строчки кодов и найдите разницу:
В течение первых двух недель работы с Swift, я заставлял себя убирать точку с запятой с каждого ряда кода. Сейчас уже легче (и я уже забыл, каково это в Objective-C).
Вывод типа дает возможность присвоить тип переменной, выводя ее непосредственно из её определения. Это еще одно преимущество, которое немного трудно освоить, когда оно исходит с использованием подробного языка Objective-C.
Мы должны попытаться использовать методы последовательного присваивания имен, в противном случае было бы трудно для другого разработчика (и для вас), определить тип, выведенный неудачным выбором присваивания имен:
Более подходящее имя облегчает работу:
Следующее существенное изменение – использование круглых скобок, которые больше не нужно ставить:
Помните, то, что Вы пишите в скобках оценивается как выражение и не всегда разрешено делать запись таким способом. При связке переменных, например, мы не можем использовать скобки:
Не требуется выбирать интерфейс или удалять точку с запятой и скобки, но можно рассмотреть эти варианты, как один из способов написания кода в Swift. В конечном итоге мы повышаем читабельность и экономим время на наборе текста и символов.
Работая с функциями, которые возвращают «value» (значение) или «nothing» (ничего), не задумывались ли Вы, какой лучший способ для определения «nothing»? Я использовал NSNotFound, -1, 0, пользовательские возвращаемые значения.
Благодаря Optionals (Дополнительное) имеем «nothing-value», которое полностью определяется, нам просто нужно добавить знак вопроса после типа данных.
Мы можем написать:
В этом примере отношение «Человек владеет автомобилем» определяется как Optional (Дополнительное). Это значит, что свойство «автомобиль» может быть ноль, а человек не мог иметь автомобиль.
Тогда мы обращаемся к этому значению, используя дополнительную привязку (если позволить (let) машину =) или с помощью развернутой фразы (автомобиль?). Если мы не определяем свойство как дополнительное, мы обязаны установить значение для этого свойства, иначе функция инициализации вынесет ошибку.
Последняя возможность определить не дополнительное значение свойства — в пределах функции инициализации.
Таким образом, мы должны определить, как свойства класса будут взаимодействовать с остальным классом, и как они будут вести себя во время существования экземпляров класса.
Эти усовершенствования полностью изменяют способ, которым мы представляем наши классы.
Если вам трудно работать с опциями, потому что Вы не можете понять, почему компилятор попросит вас, дать развернутое значение перед его использованием …
… я предлагаю подумать об опции дополнительно как о структуре (это структура, поэтому не должна быть слишком трудной), которая не содержит величины напрямую, но добавляет слой вокруг неё (окутывает, обрамляет-wrap). Если внутренняя величина определяется, вы удаляете слой (разворачиваете-unwrap), и получаете требуемое значение, в противном случае вы получаете ноль.
Принудительное разворачивание через знак «!» — это просто способ, чтобы удалить слой, не заботясь о внутренней величине. Вы рискуете, пытаясь получить доступ к значению за слоем. Если это значение равно нулю, приложение просто дает сбой.
После нескольких лет программирования на Objective-C и Cocoa мы зависимы от шаблона делегирования. Однако, мы по-прежнему используем эту схему. Вот супер простой пример использования делегата:
Мы заменяем проверку существования делегата и используем respondToSelector с дополнительной цепочкой.
Обратите внимание, что мы должны приставить протокол с помощью ключевого слова @obj, потому что мы использовали @optional. Кстати, компилятор предупреждает нас сообщением в случае, если мы забыли это сделать.
Для реализации этого делегата мы реализовываем протокол в другом класс, и назначаем его, также как и в Objective-C:
Другим общепринятым методом, который мы пользуемся в Swift, является интерактивный элемент (target-action), и в этом случае применяем его также как и в Objective-C.
Небольшая разница заключается в том, как мы определяем адрес сегмента (selector). Мы просто пишем метод прототипа, используя строку, которая автоматически будет видоизменятся в:
Любите его или ненавидьте его, Синглтон по прежнему является одной из самых принятых моделей программирования.
Нравится вам это или нет, паттерн Singleton – один из самых применимых образцов. Мы можем реализовать его, используя GDC и dispatch_once или положиться на поточнобезопасную природу ключевого слова let.
Давайте посмотрим на данный код:
1. SharedReader – это статическая составляющая (мы можем заменить ее функцией).
2. Статические (не составляющие) свойства еще не разрешены в реализации класса. Так, благодаря вложенным типам, мы добавляем вложенную структуру в класс. Структура поддерживает статические свойства, так что мы просто добавляем здесь статическое свойство.
3. Свойство _instance является константой. Оно не может быть заменено другим значением, и является поточнобезопасным.
Мы можем обратиться к единственному экземпляру DataReader с помощью:
DataReader.sharedReader
В Swift, структура и вычисления имеют много характеристик, которые Вы едва ли примените в других языках.
Они поддерживают:
Как видите, структура использует функцию инициализации, которая в данном случае автоматически создана Swift (мы можем добавить другие параметры ввода для клиентов).
Синтаксис enum немного отличается от того, который мы использовали. Он определяется ключевым словом case:
Еnum не ограничивается своими свойствами:
Мы также можем построить enum с более сложными характеристиками:
В предыдущем коде мы добавили вложенный тип (vitamin) и дополнительное свойство (mainVitamin), который присваивает начальные значения элементов для данной структуры в зависимости от значения enum.
С помощью Objective-C, мы привыкли к неизменным и изменяемым версиям любого класса. Некоторые примеры: NSArray и NSDictionary.
С Swift нам не нужны различные типы данных, мы просто по-новому используем постоянное или переменное значение.
Переменная массив является изменяемой, в то время как с константой массива мы не можем изменить свои сохраненные значения. Так что просто имейте в виду, правило «let = неизменное, var = переменная» (Исправленная ошибка: перед Beta 3 можно изменить неизменный массив).
Мне нравится синтаксис блоков, это так ясно и легко запомнить!
Кстати, после нескольких лет разработок Cocoa, мы привыкли к данному синтаксису, и иногда я предпочитаю заменить легкие задачи делегирования блоками. Они наполнены смыслом, быстрые и хорошо применимы.
В Swift аналогичными блоками являются элементы замыкания. Они обладают многими свойствами, и Apple проделала большую работу, пытаясь упростить путь их написания. Пример на официальной документации Swift лишает меня дара речи. Он начинается таким определением:
и перепроектируется в:
Таким образом, есть различные пути реализации замыкания благодаря выводу типа, сокращениям ($ 0, $ 1) и прямым функциям (>).
В этой статье я не описываю синтаксис замкнутого выражения, но хочется сказать несколько слов о значениях сбора данных в пределах замкнутого выражения.
В Objective-C мы определяем переменную как __block, когда мы намерены изменить его значение через Block. Использование замыканий, в данном случае, становится ненужным.
Мы можем получить доступ и изменять любое значение окружающей области. На самом деле замкнутые выражения достаточно разумны, чтобы захватить внешние элементы. Элемент вводится в качестве копии или ссылки. Если закрытие изменяет значение элемента, оно создает ссылку, если нет — создает копию.
Если закрытие относится к вхождению, которое содержит или использует его, мы можем натолкнуться на цикл обращения.
Давайте посмотрим пример:
Замкнутое выражения agePotion используется, сохраняя ссылку на текущий экземпляр. В то же время этот экземпляр содержит ссылку на закрытие – и здесь возникает цикл обращения.
Чтобы избежать этой проблемы мы используем список Capture. Этот список связывает слабую ссылку с экземпляром, который мы хотим использовать в Закрытии. Синтаксис очень прост — добавьте слабую ссылку перед определением Закрытие и экземпляр получит слабую ссылку вместо сильной.
Мы уже знаем, как слабая ссылка работает в Objective-C. Точно также она работает в Swift, никаких изменений нет.
Я действительно оценил введение этого ключевого слова, потому что это хорошая подсказка для определения соотношения между классами.
Опишем простое соотношение между человеком и его банковским счетом:
1. Человек может иметь счет в банке (не обязательно)
2. Счет в банке должен принадлежать человеку (обязательно)
Эти отношения собираются создать цикл. Первое решение будет добавлением слабой ссылки на свойство «Банк Account.owner». Однако с помощью слабой ссылки, мы определяем еще одно полезное ограничение: свойство должно всегда иметь значение, оно не может быть равным нулю (таким образом, мы удовлетворяем пункт 2 из предыдущего списка).
На самом деле, больше нечего сказать о слабой ссылке. Она работает так же, как слабая ссылка без увеличения регистра, на который она указывает и обеспечивает значение, отличное от нуля.
Должен признать: иногда я по-прежнему работаю над ошибками составителя. Чем больше я использую Swift, тем яснее становится, что я не зря трачу время экспериментируя и изучая. Есть много интересных изменений и вещей по сравнению с Objective-C, которые не существовали раньше, и которые мотивируют меня практиковаться больше.
Это долгожданная новинка в развитии IOS/OSX и я уверен, что Вы полюбите его!
p.s. Перевод не претендует на самый правильный и самый лучший перевод на хабре, если есть какие-то замечание, пишите в личку, буду править. Спасибо за понимание.
В данной статье я бы хотел поделиться некоторыми размышлениями по поводу перехода от Objective-C к Swift. Я постараюсь дать Вам несколько советов и указать на недостатки при разном подходе к обеим языкам. Поэтому без лишних отступлений, перейдем к самой статье.
Одиночный файл против файла реализации интерфейса
Первое, наиболее существенное изменение, которое стоит упомянуть, это отказ от структуры interface.h/implementation.m.
Должен признать, что я сторонник этой модели. Получение и обмен информацией о классе просто с помощью файла интерфейса является безопасным и быстрым.
В Swift интерфейса и реализации не разделены на два файла. Мы просто реализовываем наш класс (и в момент написания даже не представляется возможным добавить модификаторы видимости).
Если действительно сложно справляться с данным изменением, то можно использовать следующее: здравый смысл.
Мы можем легко увеличить читаемость наших классов хорошим документированием. Например, можно перемещать элементы, которые хотим сделать «публичными», в верхней части нашего файла используя расширения для разграничения данных, доступных для всех и личную информацию.
Еще один очень распространенный приём – ставить для приватных методов и переменных подчеркивание «_»
Вот небольшой пример их смешевания:
// Public
extension DataReader {
var data { }
func readData(){
var data = _webserviceInteraction()
}
}
// Private implementation
class DataReader: NSObject {
let _wsURL = NSURL(string: "http://theurl.com")
func _webserviceInteraction()->String{
// ...
}
}
Хотя мы не можем изменить видимость элементов наших классов, можно попытаться сделать доступ к некоторым «более трудным» из них.
Нестандартным решением является использование вложенного класса, которое частично скрывает личные данные (по крайней мере, в автозаполнение)
Пример:
import UIKit
class DataReader: NSObject {
// Public ***********************
var data:String?{
get{return private.internalData}
}
init(){
private = DataReaderPrivate()
}
func publicFunction(){
private.privateFunc()
}
// Private **********************
var private:DataReaderPrivate
class DataReaderPrivate {
var internalData:String?
init(){
internalData = "Private data!"
}
func privateFunc (){}
}
}
Мы помещаем приватную реализацию в приватный постоянный случай и используем «обычную» реализацию в класс в качестве общественного интерфейса. Приватные элементы, на самом деле, не скрыты, но для доступа к ним мы должны пройти через «приватные» константы.
let reader = DataReader()
reader.private.privateFunc()
Возникает вопрос: стоит ли это конечной цели, частичное скрытие личных элементов?
Мое предложение — ждать модификаторов видимости (Apple работает над этим), а пока использовать хорошее документирование с или без расширений.
Константы и переменные
В Objective-C я редко использовал константные ключевые слова, даже когда знал, что некоторые данные никогда не изменятся. В Swift, разработчики Apple предлагают использовать константу (let) вместо переменной (var). Так что просто следите за ней и попытайтесь выяснить роль ваших переменных. В конечном счете, Вы будете использовать больше констант, чем ожидаете.
Пишите только то, что необходимо написать
Посмотрите на 2 строчки кодов и найдите разницу:
let wsURL:NSURL = NSURL(string:"http://wsurl.com");
vs
let wsURL = NSURL(string:"http://wsurl.com")
В течение первых двух недель работы с Swift, я заставлял себя убирать точку с запятой с каждого ряда кода. Сейчас уже легче (и я уже забыл, каково это в Objective-C).
Вывод типа дает возможность присвоить тип переменной, выводя ее непосредственно из её определения. Это еще одно преимущество, которое немного трудно освоить, когда оно исходит с использованием подробного языка Objective-C.
Мы должны попытаться использовать методы последовательного присваивания имен, в противном случае было бы трудно для другого разработчика (и для вас), определить тип, выведенный неудачным выбором присваивания имен:
let a = something()
Более подходящее имя облегчает работу:
let a = anInt()
Следующее существенное изменение – использование круглых скобок, которые больше не нужно ставить:
if (a > b){}
vs
if a > b {}
Помните, то, что Вы пишите в скобках оценивается как выражение и не всегда разрешено делать запись таким способом. При связке переменных, например, мы не можем использовать скобки:
if (let x = data){} // Error!
if let x = data {} // OK!
Не требуется выбирать интерфейс или удалять точку с запятой и скобки, но можно рассмотреть эти варианты, как один из способов написания кода в Swift. В конечном итоге мы повышаем читабельность и экономим время на наборе текста и символов.
Опциональные
Работая с функциями, которые возвращают «value» (значение) или «nothing» (ничего), не задумывались ли Вы, какой лучший способ для определения «nothing»? Я использовал NSNotFound, -1, 0, пользовательские возвращаемые значения.
Благодаря Optionals (Дополнительное) имеем «nothing-value», которое полностью определяется, нам просто нужно добавить знак вопроса после типа данных.
Мы можем написать:
class Person{
let name:String
let car:Car? // Optional value
init(name:String){
self.name = name
}
}
// ACCESSING THE OPTIONAL VALUE ***********
var Mark = Person(name:"mark")
// use optional binding
if let car = Mark.car {
car.accelerate()
}
// unwrap the value
Mark.car?.accelerate()
В этом примере отношение «Человек владеет автомобилем» определяется как Optional (Дополнительное). Это значит, что свойство «автомобиль» может быть ноль, а человек не мог иметь автомобиль.
Тогда мы обращаемся к этому значению, используя дополнительную привязку (если позволить (let) машину =) или с помощью развернутой фразы (автомобиль?). Если мы не определяем свойство как дополнительное, мы обязаны установить значение для этого свойства, иначе функция инициализации вынесет ошибку.
Последняя возможность определить не дополнительное значение свойства — в пределах функции инициализации.
Таким образом, мы должны определить, как свойства класса будут взаимодействовать с остальным классом, и как они будут вести себя во время существования экземпляров класса.
Эти усовершенствования полностью изменяют способ, которым мы представляем наши классы.
Дополнительная распаковка
Если вам трудно работать с опциями, потому что Вы не можете понять, почему компилятор попросит вас, дать развернутое значение перед его использованием …
Mark.car?
… я предлагаю подумать об опции дополнительно как о структуре (это структура, поэтому не должна быть слишком трудной), которая не содержит величины напрямую, но добавляет слой вокруг неё (окутывает, обрамляет-wrap). Если внутренняя величина определяется, вы удаляете слой (разворачиваете-unwrap), и получаете требуемое значение, в противном случае вы получаете ноль.
Принудительное разворачивание через знак «!» — это просто способ, чтобы удалить слой, не заботясь о внутренней величине. Вы рискуете, пытаясь получить доступ к значению за слоем. Если это значение равно нулю, приложение просто дает сбой.
Шаблон делегирования
После нескольких лет программирования на Objective-C и Cocoa мы зависимы от шаблона делегирования. Однако, мы по-прежнему используем эту схему. Вот супер простой пример использования делегата:
@objc protocol DataReaderDelegate{
@optional func DataWillRead()
func DataDidRead()
}
class DataReader: NSObject {
var delegate:DataReaderDelegate?
var data:NSData?
func buildData(){
delegate?.DataWillRead?() // Optional method check
data = _createData()
delegate?.DataDidRead() // Required method check
}
}
Мы заменяем проверку существования делегата и используем respondToSelector с дополнительной цепочкой.
delegate?.DataWillRead?()
Обратите внимание, что мы должны приставить протокол с помощью ключевого слова @obj, потому что мы использовали @optional. Кстати, компилятор предупреждает нас сообщением в случае, если мы забыли это сделать.
Для реализации этого делегата мы реализовываем протокол в другом класс, и назначаем его, также как и в Objective-C:
class ViewController: UIViewController, DataReaderDelegate {
override func viewDidLoad() {
super.viewDidLoad()
let reader = DataReader()
reader.delegate = self
}
func DataWillRead() {...}
func DataDidRead() {...}
}
Шаблон программировани — Target-action
Другим общепринятым методом, который мы пользуемся в Swift, является интерактивный элемент (target-action), и в этом случае применяем его также как и в Objective-C.
class ViewController: UIViewController {
@IBOutlet var button:UIButton
override func viewDidLoad() {
super.viewDidLoad()
button.addTarget(self, action: "buttonPressed:", forControlEvents: UIControlEvents.TouchUpInside)
}
func buttonPressed(sender:UIButton){...}
}
Небольшая разница заключается в том, как мы определяем адрес сегмента (selector). Мы просто пишем метод прототипа, используя строку, которая автоматически будет видоизменятся в:
Selector("buttonPressed:")
Шаблон программировани Singleton
Любите его или ненавидьте его, Синглтон по прежнему является одной из самых принятых моделей программирования.
Нравится вам это или нет, паттерн Singleton – один из самых применимых образцов. Мы можем реализовать его, используя GDC и dispatch_once или положиться на поточнобезопасную природу ключевого слова let.
class DataReader: NSObject {
class var sharedReader:DataReader {
struct Static{
static let _instance = DataReader()
}
return Static._instance
}
...
}
Давайте посмотрим на данный код:
1. SharedReader – это статическая составляющая (мы можем заменить ее функцией).
2. Статические (не составляющие) свойства еще не разрешены в реализации класса. Так, благодаря вложенным типам, мы добавляем вложенную структуру в класс. Структура поддерживает статические свойства, так что мы просто добавляем здесь статическое свойство.
3. Свойство _instance является константой. Оно не может быть заменено другим значением, и является поточнобезопасным.
Мы можем обратиться к единственному экземпляру DataReader с помощью:
DataReader.sharedReader
Структуры и вычисления
В Swift, структура и вычисления имеют много характеристик, которые Вы едва ли примените в других языках.
Они поддерживают:
struct User{
// Struct properties
let name:String
let ID:Int
// Method!!!
func sayHello(){
println("I'm " + self.name + " my ID is: \(self.ID)")
}
}
let pamela = User(name: "Pamela", ID: 123456)
pamela.sayHello()
Как видите, структура использует функцию инициализации, которая в данном случае автоматически создана Swift (мы можем добавить другие параметры ввода для клиентов).
Синтаксис enum немного отличается от того, который мы использовали. Он определяется ключевым словом case:
enum Fruit {
case orange
case apple
}
Еnum не ограничивается своими свойствами:
enum Fruit:String {
case .orange = "Orange"
case .apple = "Apple"
}
Мы также можем построить enum с более сложными характеристиками:
enum Fruit{
// Available Fruits
case orange
case apple
// Nested type
struct Vitamin{
var name:String
}
// Compound property
var mainVitamin:Vitamin {
switch self{
case .orange:
return Vitamin(name: "C")
case .apple:
return Vitamin(name: "B")
}
}
}
let Apple = Fruit.apple
var Vitamin = Apple.mainVitamin
В предыдущем коде мы добавили вложенный тип (vitamin) и дополнительное свойство (mainVitamin), который присваивает начальные значения элементов для данной структуры в зависимости от значения enum.
Изменяемые и неизменяемые
С помощью Objective-C, мы привыкли к неизменным и изменяемым версиям любого класса. Некоторые примеры: NSArray и NSDictionary.
С Swift нам не нужны различные типы данных, мы просто по-новому используем постоянное или переменное значение.
Переменная массив является изменяемой, в то время как с константой массива мы не можем изменить свои сохраненные значения. Так что просто имейте в виду, правило «let = неизменное, var = переменная» (Исправленная ошибка: перед Beta 3 можно изменить неизменный массив).
Блоки vs Замыкание
Мне нравится синтаксис блоков, это так ясно и легко запомнить!
</IronicMode>
Кстати, после нескольких лет разработок Cocoa, мы привыкли к данному синтаксису, и иногда я предпочитаю заменить легкие задачи делегирования блоками. Они наполнены смыслом, быстрые и хорошо применимы.
В Swift аналогичными блоками являются элементы замыкания. Они обладают многими свойствами, и Apple проделала большую работу, пытаясь упростить путь их написания. Пример на официальной документации Swift лишает меня дара речи. Он начинается таким определением:
reversed = sort(names, { (s1: String, s2: String) -> Bool in
return s1 > s2
})
и перепроектируется в:
reversed = sort(names, >)
Таким образом, есть различные пути реализации замыкания благодаря выводу типа, сокращениям ($ 0, $ 1) и прямым функциям (>).
В этой статье я не описываю синтаксис замкнутого выражения, но хочется сказать несколько слов о значениях сбора данных в пределах замкнутого выражения.
В Objective-C мы определяем переменную как __block, когда мы намерены изменить его значение через Block. Использование замыканий, в данном случае, становится ненужным.
Мы можем получить доступ и изменять любое значение окружающей области. На самом деле замкнутые выражения достаточно разумны, чтобы захватить внешние элементы. Элемент вводится в качестве копии или ссылки. Если закрытие изменяет значение элемента, оно создает ссылку, если нет — создает копию.
Если закрытие относится к вхождению, которое содержит или использует его, мы можем натолкнуться на цикл обращения.
Давайте посмотрим пример:
class Person{
var age:Int = 0
@lazy var agePotion: (Int) -> Void = {
(agex:Int)->Void in
self.age += agex
}
func modifyAge(agex:Int, modifier:(Int)->Void){
modifier(agex)
}
}
var Mark:Person? = Person()
Mark!.modifyAge(50, Mark!.agePotion)
Mark = nil // Memory Leak
Замкнутое выражения agePotion используется, сохраняя ссылку на текущий экземпляр. В то же время этот экземпляр содержит ссылку на закрытие – и здесь возникает цикл обращения.
Чтобы избежать этой проблемы мы используем список Capture. Этот список связывает слабую ссылку с экземпляром, который мы хотим использовать в Закрытии. Синтаксис очень прост — добавьте слабую ссылку перед определением Закрытие и экземпляр получит слабую ссылку вместо сильной.
@lazy var agePotion: (Int) -> Void = {
[unowned self](agex:Int)->Void in
self.age += agex
}
Unowned и Слабые ссылки
Мы уже знаем, как слабая ссылка работает в Objective-C. Точно также она работает в Swift, никаких изменений нет.
Я действительно оценил введение этого ключевого слова, потому что это хорошая подсказка для определения соотношения между классами.
Опишем простое соотношение между человеком и его банковским счетом:
1. Человек может иметь счет в банке (не обязательно)
2. Счет в банке должен принадлежать человеку (обязательно)
We can describe this relation with code:
class Person{
let name:String
let account:BankAccount!
init(name:String){
self.name = name
self.account = BankAccount(owner: self)
}
}
class BankAccount{
let owner:Person
init(owner:Person){
self.owner = owner
}
}
Эти отношения собираются создать цикл. Первое решение будет добавлением слабой ссылки на свойство «Банк Account.owner». Однако с помощью слабой ссылки, мы определяем еще одно полезное ограничение: свойство должно всегда иметь значение, оно не может быть равным нулю (таким образом, мы удовлетворяем пункт 2 из предыдущего списка).
На самом деле, больше нечего сказать о слабой ссылке. Она работает так же, как слабая ссылка без увеличения регистра, на который она указывает и обеспечивает значение, отличное от нуля.
Заключение
Должен признать: иногда я по-прежнему работаю над ошибками составителя. Чем больше я использую Swift, тем яснее становится, что я не зря трачу время экспериментируя и изучая. Есть много интересных изменений и вещей по сравнению с Objective-C, которые не существовали раньше, и которые мотивируют меня практиковаться больше.
Это долгожданная новинка в развитии IOS/OSX и я уверен, что Вы полюбите его!
p.s. Перевод не претендует на самый правильный и самый лучший перевод на хабре, если есть какие-то замечание, пишите в личку, буду править. Спасибо за понимание.