self swift что такое
Документация
Методы
Методы
Дело в том, что структуры и перечисления могут определить методы в Swift, что является главным отличием от C или Objective-C. В Objective-C классы единственный тип, который может определять методы. В Swift вы можете выбирать, стоит ли вам определять класс, структуру или перечисление, и вы все равно, при любом раскладе, получаете возможность определения методов типа, который вы создадите.
Методы экземпляра
Методы экземпляра являются функциями, которые принадлежат экземплярам конкретного класса, структуры или перечисления. Они обеспечивают функциональность этих экземпляров, либо давая возможность доступа и изменения свойств экземпляра, либо обеспечивая функциональность экземпляра в соответствии с его целью. Методы экземпляра имеют абсолютно одинаковый синтаксис как и функции, что описаны в разделе Функции.
Вы пишете метод экземпляра внутри фигурных скобок типа, которому он принадлежит. Метод экземпляра имеет неявный доступ ко всем остальным методам экземпляра и свойствам этого типа. Метод экземпляра может быть вызван только для конкретного экземпляра типа, которому он принадлежит. Его нельзя вызвать в изоляции, без существующего экземпляра.
Класс Counter() определяет три метода экземпляра:
Вы можете вызвать методы экземпляра с тем же точечным синтаксисом:
Параметры функций могут иметь и имя аргумента (для использования внутри функций), и ярлык аргумента (для использования при вызове функций), что описано Ярлыки аргументов и имена параметров функций. То же самое верно для имен параметров методов, потому как методы те же самые функции, но ассоциированные с определенным типом.
Свойство self
Метод increment может быть вызван так:
Главное исключение из этого правила получается, когда имя параметра метода экземпляра совпадает с именем свойства экземпляра. В этой ситуации имя параметра имеет приоритет и появляется необходимость ссылаться на свойство в более подходящей форме. Вы используете свойство self для того, чтобы увидеть различие между именем параметра и именем свойства.
Здесь self разграничивает параметр метода x и свойство экземпляра, которое тоже x :
Изменение типов значений методами экземпляра
Структуры и перечисления являются типами значений. По умолчанию, свойства типов значений не могут быть изменены изнутри методов экземпляра.
Вы можете все это осуществить, если поставите ключевое слово mutating перед словом func для определения метода:
Обратите внимание, что вы не можете вызвать изменяющий ( mutating ) метод для константных типов структуры, потому как ее свойства не могут быть изменены, даже если свойства являются переменными, что описано в главе Свойства хранения постоянных экземпляров структуры.
Присваивание значения для self внутри изменяющего метода
Изменяющие методы для перечислений могут установить отдельный член перечисления как неявный параметр self :
Методы типа
Заметка
В Objective-C определять методы типов можно только для классов. В Swift вы можете создавать методы типа не только для классов, но и для структур и перечислений. Метод каждого типа ограничен самим типом, который его поддерживает.
Такие методы так же используют точечный синтаксис, как и методы экземпляра. Однако эти методы вы вызываете самим типом, а не экземпляром этого типа. Вот как вы можете вызвать метод самим классом SomeClass :
Внутри тела метода типа неявное свойство self ссылается на сам тип, а не на экземпляр этого типа. Это значит, что вы можете использовать self для того, чтобы устранить неоднозначность между свойствами типа и параметрами метода типа, точно так же как вы делали для свойств экземпляра и параметров метода экземпляра.
Если обобщить, то любое имя метода и свойства, которое вы используете в теле метода типа, будет ссылаться на другие методы и свойства на уровне типа. Метод типа может вызвать другой метод типа с иным именем метода, без использования какого-либо префикса имени типа. Аналогично, методы типа в структурах и перечислениях могут получить доступ к свойствам типа, используя имя этого свойства, без написания префикса имени типа.
Все уровни игры (кроме первого уровня) заблокированы, когда играют в первый раз. Каждый раз, заканчивая уровень, этот уровень открывается и у остальных игроков на устройстве. Структура LevelTracker использует свойства и методы типа для отслеживания уровней, которые были разблокированы. Так же она отслеживает текущий уровень каждого игрока.
В дополнение к его свойствам типа и методам типа, структура LevelTracker так же отслеживает и текущий прогресс игрока в игре. Она использует свойство экземпляра currentLevel для отслеживания уровня, на котором игрок играет.
Вы можете создать экземпляр класса Player для нового игрока и увидеть, что будет, когда игрок закончит первый уровень:
Если вы создадите второго игрока, и попробуете им начать прохождение уровня, который не был разблокирован ни одним игроком в игре, то вы увидите, что эта попытка будет неудачной:
Если вы нашли ошибку, пожалуйста, выделите фрагмент текста и нажмите Ctrl+Enter.
Если вы нашли ошибку, пожалуйста, выделите фрагмент текста и нажмите Ctrl+Enter.
Swift Features
Generic протоколы
Под этим термином я подразумеваю любые протоколы, в которых есть открытые typealias (associatedtype в Swift 2.2). В моем первом приложении на Swift было два таких протокола: (для примера я немного упростил их)
DataObservable отвечает за отслеживание изменения данных. При этом не важно, где эти данные хранятся (на сервере, локально или еще как). DataObserver получает оповещения о том, что данные изменились. В первую очередь нас будет интересовать протокол DataObservable, и вот его простейшая реализация.
Тут все просто: сохраняем ссылку на последний observer, и вызываем у него метод didDataChangedNotification, когда данные по какой-то причине изменяются. Но погодите… этот код не компилируется. Компилятор выдает ошибку «Protocol ‘DataObserver’ can only be used as a generic constraint because it has Self or associated type requirements». Все потому, что generic-протоколы могут использоваться только для накладывания ограничений на generic-параметры. Т.е. объявить переменную типа DataObserver не получится. Меня такое положение дел не устроило. Немного покопавшись в сети, я нашел решение, которое помогает разобраться со сложившейся проблемой, и имя ему Type Erasure.
Это паттерн, который представляет собой небольшой обертку над заданным протоколом. Для начала введем новый класс AnyDataObserver, который реализует протокол DataObserver.
Тело метода didDataChangedNotification пока оставим пустым. Идем дальше. Вводим в класс generic init (для чего он нужен расскажу чуть ниже):
В него передается параметр sourceObserver типа TObserver. Видно, что на TObserver накладываются ограничения: во-первых он должен реализовать протокол DataObserver, во-вторых его DataType должен в точности соответствовать DataType нашего класса. Собственно sourceObserver это и есть исходный observer-объект, который мы хотим обернуть. И наконец финальный код класса:
Собственно тут и происходит вся «магия». В класс добавляется закрытое поле observerHandler, в котором хранится реализация метода didDataChangedNotification объекта sourceObserver. В самом методе didDataChangedNotification нашего класса мы просто вызываем эту реализацию.
Теперь перепишем SimpleDataObservable:
Теперь код компилируется и прекрасно работает. Могу отметить, что некоторые классы из стандартной библиотеки Swift работают по схожему принципу (например AnySequence).
Тип Self
В определенный момент мне потребовалось ввести в проект протокол копирования:
Но что же должен возвращать метод copy? Any? CopyableType? Тогда при каждом вызове пришлось бы писать let copyObject = someObject.copy as! SomeClass, что не очень хорошо. В добавок к тому же этот код небезопасен. На помощь приходит ключевое слово Self.
Таким образом мы сообщаем компилятору, что реализация этого метода обязана вернуть объект того же типа, что и объект, для которого он был вызван. Тут можно провести аналогию с instancetype из Objective-C.
Рассмотрим реализацию этого протокола:
Для создание нового экземпляра используется ключевое слово dynamicType. Оно служит для получения ссылки на объект-тип (все это напоминает метод class из Objective-C). После получения объекта-типа, у него вызывается init (для гарантии того, что init без параметров действительно есть в классе, мы вводим его с ключевым словом required). После чего копируем в созданный экземпляр все нужные поля и возвращаем его из нашей функции.
Как только я закончил с копированием, возникла необходимость использовать Self еще в одном месте. Мне потребовалось написать протокол для View Controller, в котором бы был статический метод создания нового экземпляра этого самого View Controller.
Так как этот протокол никак напрямую не был связан с классом UIViewController, то я его сделал достаточно общим и назвал AutofactoryType:
Попробуем использовать его для создания View Conotroller:
Все бы хорошо, но этот код не скомпилируется: “Cannot convert return expression of type ViewController to return type ‘Self’” Дело в том, что компилятор не может преобразовать ViewController к Self. В данном случае ViewController и Self — это одно и то же, но в общем случае это не так (например, при использовании наследования).
Как же заставить этот код работать? Для этого есть не совсем честный (по отношению к строгой типизации), но вполне рабочий способ. Добавим функцию:
Ее назначение — это преобразование объекта одного типа к другому типу. Если преобразование не удается, то функция просто завершается с ошибкой.
Используем эту функцию в createInstance:
Благодаря автоматическому выводу типов, newInstance теперь преобразуется к Self (чего нельзя было сделать напрямую). Этот код компилируется и работает.
Специфичные расширения
Расширения типов в Swift не были бы такими полезными, если бы нельзя было писать специфичный код для разных типов. Возьмем, к примеру, протокол SequenceType из стандартной библиотеки и напишем для него такое расширение:
В расширении введено ограничение на элемент последовательности, он должен быть типа String. Таким образом для любой последовательности, состоящей из строк (и только для них), можно будет вызвать функцию concat.
Это позволяет значительную часть кода выносить в расширения, и вызывать его в нужном контексте, получая при этом все плюсы повторного использования.
Реализация методов протокола по умолчанию.
Реализация методов протокола по умолчанию.
Как следует из описания, любой тип реализующий этот протокол, должен обладать уникальным идентификатором uniqueId типа String. Но если немного подумать, то становится понятно, что в рамках одного модуля для любого типа уникальным идентификатором является его название. Так давайте напишем расширение для нашего нового протокола:
В данном случае ключевое слово Self используется для того, чтобы накладывать ограничения на объект-тип. Логика этого кода примерно следующая: «если этот протокол будет реализован классом UIViewController (или его наследником), то можно использовать следующую реализацию uniqueId». Это и есть реализация протокола по-умолчанию. На самом деле можно написать это расширение и без каких-либо ограничений:
И тогда все типы, реализующие UniqueIdentifierProvider, получат uniqueId “из коробки”.
Прелесть в том, что в классе может быть своя реализация этого метода. И в этом случае реализация по-умолчанию будет игнорироваться:
Явное указание Generic аргумента
В своем проекте я использовал MVVM, и за создание ViewModel отвечал метод:
Соответственно, так он использовался:
В данном случае в функцию createViewModel в качестве generic аргумента будет поставляться MyViewModel. Все благодаря тому, что Swift сам выводит типы из контекста. Но всегда ли это хорошо? На мой взгляд, это не так. В некоторых случаях может даже привести к ошибкам:
В первом case в метод createViewModel подставляется NormalViewModel.
Во втором мы забыли написать «as PreviewViewModel», из-за чего в метод createViewModel подставляется тип ViewModelBase (что в лучшем случае приведет к ошибке в runtime).
Значит, необходимо сделать указание типа явным. Для этого в createViewModel мы добавим новый параметр viewModelType типа TViewModel.Type. Type тут означает, что метод принимает в качестве параметра не экземпляр типа, а сам объект-тип.
После этого наш switch-case выглядит так:
Теперь В функцию createViewModel передается аргументы NormalViewModel.self и PreviewViewModel.self. Это объекты-типы NormalViewModel и PreviewViewModel. В Swift есть довольно странная особенность: если у функции один параметр, можно не писать self.
Но если аргументов два или больше, ключевое слово self необходимо.
Тот факт, что структуры и перечисления могут определять методы в Swift, является основным отличием от C и Objective-C. В Objective-C классы являются единственными типами, которые могут определять методы. В Swift вы можете выбрать, определять ли класс, структуру или перечисление, и при этом иметь возможность определять методы для создаваемого вами типа.
Методы экземпляра
Вы пишете метод экземпляра в открывающей и закрывающей скобках того типа, к которому он принадлежит. Метод экземпляра имеет неявный доступ ко всем другим методам экземпляра и свойствам этого типа. Метод экземпляра может быть вызван только для конкретного экземпляра того типа, к которому он принадлежит. Его нельзя вызвать изолированно без существующего экземпляра.
Вот пример, который определяет простой Counter класс, который может использоваться для подсчета количества раз, когда действие происходит:
Counter Класс определяет три метода экземпляра:
Вы вызываете методы экземпляра с тем же точечным синтаксисом, что и у свойств:
Собственная собственность
increment() Метод в приведенном выше примере мог бы быть написана так:
Основное исключение из этого правила возникает, когда имя параметра для метода экземпляра имеет то же имя, что и свойство этого экземпляра. В этой ситуации имя параметра имеет приоритет, и становится необходимым ссылаться на свойство более квалифицированным способом. Вы используете self свойство, чтобы различать имя параметра и имя свойства.
Здесь self устраняется неоднозначность между вызываемым параметром метода x и свойством экземпляра, которое также вызывается x :
Изменение типов значений из методов экземпляра
Тем не менее, если вам нужно изменить свойства вашей структуры или перечисления в конкретном методе, вы можете выбрать мутацию поведения для этого метода. Затем метод может видоизменять (то есть изменять) свои свойства изнутри метода, и любые изменения, которые он вносит, записываются обратно в исходную структуру после завершения метода. Метод также может назначить совершенно новый экземпляр своему неявному self свойству, и этот новый экземпляр заменит существующий, когда метод завершится.
Вы можете включить это поведение, поместив mutating ключевое слово перед func ключевым словом для этого метода:
Обратите внимание, что вы не можете вызвать метод мутации для константы типа структуры, потому что ее свойства не могут быть изменены, даже если они являются переменными свойствами, как описано в разделе Хранимые свойства экземпляров константной структуры :
Присвоение себе внутри метода мутации
Эта версия moveBy(x:y:) метода мутации создает новую структуру, чьи значения x и y значения установлены в целевом местоположении. Конечный результат вызова этой альтернативной версии метода будет точно таким же, как и при вызове более ранней версии.
Методы мутации для перечислений могут установить неявный self параметр, который будет отличаться от того же перечисления:
Методы типа
В Objective-C вы можете определять методы уровня типа только для классов Objective-C. В Swift вы можете определить методы уровня типа для всех классов, структур и перечислений. Каждый метод типа явно ограничен типом, который он поддерживает.
Методы типа вызываются с точечным синтаксисом, как методы экземпляра. Однако вы вызываете методы типа для типа, а не для экземпляра этого типа. Вот как вы вызываете метод типа для класса с именем SomeClass :
В теле метода типа неявное self свойство ссылается на сам тип, а не на экземпляр этого типа. Это означает, что вы можете использовать self для устранения неоднозначности между свойствами типа и параметрами метода типа, так же, как вы делаете для свойств экземпляра и параметров метода экземпляра.
В более общем смысле любые неквалифицированные имена методов и свойств, которые вы используете в теле метода типа, будут ссылаться на другие методы и свойства уровня типа. Метод типа может вызывать другой метод типа с именем другого метода без необходимости ставить перед ним префикс имени типа. Точно так же методы типа в структурах и перечислениях могут обращаться к свойствам типа, используя имя свойства типа без префикса имени типа.
В дополнение к его свойству type и методам type, он LevelTracker отслеживает прогресс отдельных игроков в игре. Он использует свойство экземпляра, вызываемое currentLevel для отслеживания уровня, который в данный момент играет игрок.
LevelTracker Структура используется с Player классом, как показано ниже, чтобы отслеживать и обновлять ход отдельного плеера:
Вы можете создать экземпляр Player класса для нового игрока и посмотреть, что произойдет, когда игрок завершит первый уровень:
Если вы создаете второго игрока, которого пытаетесь перейти на уровень, который еще не разблокирован ни одним игроком в игре, попытка установить текущий уровень игрока завершится неудачно:
Что такое » я » используется в Swift?
Я новичок в Swift, и мне интересно, что self используется для и почему.
Я видел это в классах и структурах, но я действительно не считаю их необходимыми или необходимыми даже упоминать их в моем коде. Для чего они используются и почему? В каких ситуациях необходимо его использовать?
Я читал много вопросов и ответов на этот вопрос, но ни один из них полностью отвечает на мои вопросы и они всегда склонны сравнивать его с this как в Java, с которого я совсем не знаю.
7 ответов
вы также будете использовать self много при создании расширений, например:
теперь давайте скажем, что вы хотите изменить сам результат var вы должны использовать мутирующий func, чтобы изменить себя
теперь давайте мутировать его
/ / теперь давайте посмотрим другой пример использования строк:
теперь давайте изменим myString1
Обновление: 24 Ноября 2015 Года!—24—>
Да это то же самое, что this на Java и self на С, но с Свифт, self требуется только при вызове свойства или метода из закрытия или для различения имен свойств внутри кода (например инициализаторы). Таким образом, вы можете безопасно использовать почти все компоненты класса, не используя self, если вы не звоните из закрытие.
на increment() метод в приведенном выше примере можно было бы написать вот так:
основное исключение из этого правила возникает, когда имя параметра для метод экземпляра имеет то же имя, что и свойство этого экземпляра. В эта ситуация, имя параметра имеет приоритет и становится необходимо обратиться к собственности более квалифицированным способом. Вы используете the self свойство для различения имени параметра и имя свойства.
здесь self различать между параметром метод, называемый x и свойство экземпляра, которое также называется x :»
Выдержка Из: Apple Inc. «Язык Программирования Swift (Предварительная Версия Swift 2).»
это как Рэй Вендерлих рекомендует использовать self в Swift для их руководства:
использование Self
для краткости избегайте использования self, поскольку Swift не требует доступа к свойствам объекта или вызова его методов.
используйте self при необходимости для различения имен свойств и аргументов в инициализаторах и при ссылке на свойства в выражениях закрытия (как требуется составитель):
и GitHub рекомендации по self для их применения:
только явно ссылаться на self при необходимости
включить ключевое слово explicit только тогда, когда это требуется языком-например, в закрытии или когда конфликт имен параметров:
обоснование: это делает семантику захвата себя более заметной в закрытиях и избегает многословия в другом месте.
в каких ситуациях нужно использовать
Это необходимые использовать его только тогда, когда имя локальной переменной затмевает имя свойства.
однако, как вопрос стиль (и читаемость), я всегда использую его:
Я использую его с именами свойств, потому что в противном случае мне интересно, что это за переменная (поскольку она не объявлена локально и не является входящей параметр.)
Я использую его как приемник вызовов функций (методов), чтобы отличить такие методы от функций верхнего уровня или локальных функций.
когда мы определяем класс, как:
мы создаем Класс Объекта. Да, класс-это тоже объект.
тогда независимо от того, сколько экземпляров создается с помощью класса, все экземпляры будут иметь ссылки на его Класс Объекта.
вы можете представить, что все методы экземпляра, определенные классом, находятся в объекте класса, и будет только один экземпляр.
это означает, что все экземпляры, созданные с помощью класса, используют один и тот же метод.
теперь представьте, что вы myMethod в объекте Class и поскольку вы разделяетесь для всех экземпляров, у вас должен быть способ определить, над каким экземпляром вы работаете.
поправьте меня, если я ошибаюсь, спасибо.
«на практике вам не нужно писать себя в своем коде очень часто. Если вы явно не пишете self, Swift предполагает, что вы ссылаетесь свойству или методу текущего экземпляра при каждом использовании известное свойство или имя метода в методе.»
Выдержка Из: Apple Inc. «Язык Программирования Swift.»в iBooks. https://itun.es/tw/jEUH0.l
прежде всего: хорошие ответы, примеры и объяснения уже размещены здесь, хотя я должен кое-что указать:
зарезервированное слово: self в swift похож на this но это не то же самое, что в Java или Javascript.
Как правильно процитировал @Dave Gomez:
каждый экземпляр типа имеет неявное свойство self, которое точно эквивалентно самому экземпляру.
и здесь начинается одно из главных отличий, потому что:
вот несколько примеров:
если вы хотите прочитать больше, пожалуйста, смотрите:почему «я».я компиляции и запуска в swift
вопрос OP о том, что это такое в swift, поэтому я не буду утомлять читателей объяснениями, что это такое на Java или Javascript (но если некоторым читателям это нужно, просто напишите комментарий).
в следующей статье объясняется self подробнее:
когда self доступен в методе типа ( static func или class func ), это относится к фактическому типу (а не к экземпляру).
Swift позволяет опустить self когда вы хотите получить доступ к свойствам экземпляров.
когда параметр метода имеет то же имя, что и свойство экземпляра, вы должны явно использовать self.myVariable = myVariable чтобы сделать различие. Обратите внимание, что параметры метода имеют приоритет над свойствами экземпляра.
self-это свойство экземпляра, которое ссылается на себя. Он используется для доступа к экземпляру класса, структуры и перечисления в методах. Если параметр метода имеет то же имя, что и свойство экземпляра, необходимо явно использовать self.переменная = переменная, чтобы сделать различие. Обратите внимание, что параметры метода имеют приоритет над свойствами экземпляра.
What is «self» used for in Swift?
I am new to Swift and I’m wondering what self is used for and why.
I have seen it in classes and structures but I really don’t find them essential nor necessary to even mention them in my code. What are they used for and why? In what situations it’s necessary to use it?
I have been reading lots of questions and answers for this question but none of them fully answers my questions and they always tend to compare it with this as in Java, with which I’m not familiar whatsoever.
9 Answers 9
Yes it is the same as this in Java and self in Objective-C, but with Swift, self is only required when you call a property or method from a closure or to differentiate property names inside your code, such as initializers. So you can use almost all of your class components safely without using self unless you are making the call from a closure.
The increment() method in the example above could have been written like this:
The main exception to this rule occurs when a parameter name for an instance method has the same name as a property of that instance. In this situation, the parameter name takes precedence, and it becomes necessary to refer to the property in a more qualified way. You use the self property to distinguish between the parameter name and the property name.
Here, self disambiguates between a method parameter called x and an instance property that is also called x :”
Excerpt From: Apple Inc. “The Swift Programming Language (Swift 2 Prerelease).”
This is how Ray Wenderlich recommends the use of self in Swift for their tutorials:
Use of Self
For conciseness, avoid using self since Swift does not require it to access an object’s properties or invoke its methods.
Use self when required to differentiate between property names and arguments in initializers, and when referencing properties in closure expressions as required by the compiler:
And this is GitHub’s recommendations on self for their applications:
Only explicitly refer to self when required
Only include the explicit keyword when required by the language — for example, in a closure, or when parameter names conflict:
Rationale: This makes the capturing semantics of self stand out more in closures, and avoids verbosity elsewhere.