Відповіді:
protocol MyProtocol {
func doSomething()
}
extension MyProtocol {
func doSomething() {
/* return a default value or just leave empty */
}
}
struct MyStruct: MyProtocol {
/* no compile error */
}
Переваги
Жоден час виконання Objective-C не бере участь (ну, принаймні, явно, принаймні) Це означає, що ви можете відповідати структурам, перерахункам та некласам NSObject
. Також це означає, що ви можете скористатися потужною системою дженериків.
Ви завжди можете бути впевнені, що всі вимоги виконуються, стикаючись із типами, які відповідають такому протоколу. Це завжди або конкретна реалізація, або за замовчуванням. Ось як поводяться "інтерфейси" чи "контракти" іншими мовами.
Недоліки
Для невимогливості Void
потрібно мати розумне значення за замовчуванням , що не завжди можливо. Однак, коли ви зіткнулися з цією проблемою, це означає, що або така вимога дійсно не повинна мати реальної реалізації за замовчуванням, або ви помилилися під час проектування API.
Ви не можете розрізняти реалізацію за замовчуванням і жодну реалізацію , принаймні, не вирішуючи цю проблему зі спеціальними значеннями повернення. Розглянемо наступний приклад:
protocol SomeParserDelegate {
func validate(value: Any) -> Bool
}
Якщо ви надаєте реалізацію за замовчуванням, яка просто повертається true
- це добре на перший погляд. Тепер розглянемо наступний псевдо-код:
final class SomeParser {
func parse(data: Data) -> [Any] {
if /* delegate.validate(value:) is not implemented */ {
/* parse very fast without validating */
} else {
/* parse and validate every value */
}
}
}
Немає способу здійснити таку оптимізацію - ви не можете знати, чи реалізує ваш делегат метод чи ні.
Хоча існує декілька різних способів подолати цю проблему (використовуючи необов'язкові закриття, різні об'єкти делегування для різних операцій, щоб назвати декілька), цей приклад чітко представляє проблему.
@objc optional
.@objc protocol MyProtocol {
@objc optional func doSomething()
}
class MyClass: NSObject, MyProtocol {
/* no compile error */
}
Переваги
Недоліки
Це суттєво обмежує можливості вашого протоколу, вимагаючи, щоб усі відповідні типи були сумісні з Objective-C. Це означає, що тільки класи, які успадковують, NSObject
можуть відповідати такому протоколу. Ніяких структур, жодних перерахунків, жодних асоційованих типів.
Ви завжди повинні перевірити, чи реалізований необов'язковий метод , або необов'язково викликаючи або перевіряючи, чи відповідає відповідний тип. Це може спричинити багато шаблонів, якщо ви часто використовуєте необов'язкові методи.
respondsToSelector
?
optional func doSomething(param: Int?)
У Swift 2 і далі можна додати реалізацію протоколу за замовчуванням. Це створює новий спосіб необов'язкових методів у протоколах.
protocol MyProtocol {
func doSomethingNonOptionalMethod()
func doSomethingOptionalMethod()
}
extension MyProtocol {
func doSomethingOptionalMethod(){
// leaving this empty
}
}
Це не дуже приємний спосіб створення необов'язкових методів протоколу, але дає можливість використовувати структури в зворотному виклику протоколу.
Тут я написав невеликий підсумок: https://www.avanderlee.com/swift-2-0/optional-protocol-methods/
Оскільки є кілька відповідей про те, як використовувати необов’язковий модифікатор та атрибут @objc для визначення необов'язкового протоколу вимог, я наведу зразок про те, як використовувати розширення протоколу для визначення необов'язкового протоколу.
Нижче код - Swift 3. *.
/// Protocol has empty default implementation of the following methods making them optional to implement:
/// `cancel()`
protocol Cancelable {
/// default implementation is empty.
func cancel()
}
extension Cancelable {
func cancel() {}
}
class Plane: Cancelable {
//Since cancel() have default implementation, that is optional to class Plane
}
let plane = Plane()
plane.cancel()
// Print out *United Airlines can't cancelable*
Зверніть увагу, що методи розширення протоколу не можуть викликатися кодом Objective-C, і ще гірше, що команда Swift не виправить це. https://bugs.swift.org/browse/SR-492
Інші відповіді тут, пов’язані з позначенням протоколу як "@objc", не працюють при використанні типів, що відповідають швидкості.
struct Info {
var height: Int
var weight: Int
}
@objc protocol Health {
func isInfoHealthy(info: Info) -> Bool
}
//Error "Method cannot be marked @objc because the type of the parameter cannot be represented in Objective-C"
Для того, щоб оголосити необов'язкові протоколи, які добре працюють зі швидким, оголошуйте функції змінними замість функціональних.
protocol Health {
var isInfoHealthy: (Info) -> (Bool)? { get set }
}
А потім реалізуйте протокол так
class Human: Health {
var isInfoHealthy: (Info) -> (Bool)? = { info in
if info.weight < 200 && info.height > 72 {
return true
}
return false
}
//Or leave out the implementation and declare it as:
//var isInfoHealthy: (Info) -> (Bool)?
}
Потім ви можете використовувати "?" перевірити, чи функція реалізована чи ні
func returnEntity() -> Health {
return Human()
}
var anEntity: Health = returnEntity()
var isHealthy = anEntity.isInfoHealthy(Info(height: 75, weight: 150))?
//"isHealthy" is true
Ось конкретний приклад із схемою делегування.
Налаштуйте свій протокол:
@objc protocol MyProtocol:class
{
func requiredMethod()
optional func optionalMethod()
}
class MyClass: NSObject
{
weak var delegate:MyProtocol?
func callDelegate()
{
delegate?.requiredMethod()
delegate?.optionalMethod?()
}
}
Встановіть делегата до класу та реалізуйте Протокол. Зверніть увагу, що необов'язковий метод не потрібно реалізовувати.
class AnotherClass: NSObject, MyProtocol
{
init()
{
super.init()
let myInstance = MyClass()
myInstance.delegate = self
}
func requiredMethod()
{
}
}
Важливим є те, що необов'язковий метод є необов’язковим і йому потрібно "?" при дзвінку. Згадайте другий знак питання.
delegate?.optionalMethod?()
У Swift 3.0
@objc protocol CounterDataSource {
@objc optional func increment(forCount count: Int) -> Int
@objc optional var fixedIncrement: Int { get }
}
Це заощадить ваш час.
@objc
це потрібно всім членам зараз?
required
прапорцем, але з помилками: required
може використовуватися лише в оголошеннях 'init'.
optional
Перед кожним методом потрібно додати ключове слово.@objc
, а не лише протокол.
Щоб проілюструвати механіку відповіді Антуана:
protocol SomeProtocol {
func aMethod()
}
extension SomeProtocol {
func aMethod() {
print("extensionImplementation")
}
}
class protocolImplementingObject: SomeProtocol {
}
class protocolImplementingMethodOverridingObject: SomeProtocol {
func aMethod() {
print("classImplementation")
}
}
let noOverride = protocolImplementingObject()
let override = protocolImplementingMethodOverridingObject()
noOverride.aMethod() //prints "extensionImplementation"
override.aMethod() //prints "classImplementation"
Я думаю, що перш ніж запитати, як можна реалізувати необов’язковий метод протоколу, ви повинні запитати, чому ви повинні його реалізувати.
Якщо ми розглядаємо швидкі протоколи як інтерфейс у класичному об'єктно-орієнтованому програмуванні, необов'язкові методи не мають особливого сенсу, і, можливо, кращим рішенням було б створити реалізацію за замовчуванням або розділити протокол на набір протоколів (можливо, з деякими відносинами успадкування між ними) представляти можливе поєднання методів у протоколі.
Для подальшого читання див. Https://useyourloaf.com/blog/swift-optional-protocol-methods/ , який дає чудовий огляд цього питання.
Трохи від теми від початкового питання, але це вибудовує ідею Антуана, і я думав, що це може комусь допомогти.
Ви також можете зробити обчислювані властивості необов’язковими для структур з розширеннями протоколу.
Ви можете зробити властивість протоколу необов'язковою
protocol SomeProtocol {
var required: String { get }
var optional: String? { get }
}
Реалізуйте обчислену властивість фіктивного модуля в розширенні протоколу
extension SomeProtocol {
var optional: String? { return nil }
}
Тепер ви можете використовувати структури, які не мають чи не реалізовані необов'язкові властивості
struct ConformsWithoutOptional {
let required: String
}
struct ConformsWithOptional {
let required: String
let optional: String?
}
Я також написав, як робити необов'язкові властивості в протоколах Swift на своєму блозі , які я буду постійно оновлювати, якщо все зміниться через версії Swift 2.
Як створити необов'язкові та потрібні методи делегації.
@objc protocol InterViewDelegate:class {
@objc optional func optfunc() // This is optional
func requiredfunc()// This is required
}
Ось дуже простий приклад для швидких класів ТІЛЬКИ, а не для структур або перерахувань. Зауважте, що метод протоколу, необов'язковий, має два рівні необов'язкового ланцюга під час відтворення. Також класу, що приймає протокол, потрібен атрибут @objc у своїй декларації.
@objc protocol CollectionOfDataDelegate{
optional func indexDidChange(index: Int)
}
@objc class RootView: CollectionOfDataDelegate{
var data = CollectionOfData()
init(){
data.delegate = self
data.indexIsNow()
}
func indexDidChange(index: Int) {
println("The index is currently: \(index)")
}
}
class CollectionOfData{
var index : Int?
weak var delegate : CollectionOfDataDelegate?
func indexIsNow(){
index = 23
delegate?.indexDidChange?(index!)
}
}
delegate?.indexDidChange?(index!)
:?
protocol CollectionOfDataDelegate{ func indexDidChange(index: Int) }
тоді ви будете називати його без знака питання: delegate?.indexDidChange(index!)
Коли ви встановлюєте необов'язкові вимоги до методу в протоколі, тип, який відповідає йому, НЕ може реалізувати цей метод , тому ?
використовується для перевірки на реалізацію, а якщо немає, програма не вийде з ладу. @Unheilig
weak var delegate : CollectionOfDataDelegate?
(Забезпечуєте слабку орієнтацію?)
delegate?
використання? Ця інформація дійсно повинна належати там іншим у майбутньому. Я хочу підкреслити це, але ця інформація дійсно повинна відповідати.
якщо ви хочете зробити це в найкоротші терміни, найкращим способом є надання детальної інформації про реалізацію за замовчуванням, якщо ви повернете тип Swift, наприклад, структура з типами Swift
приклад:
struct magicDatas {
var damagePoints : Int?
var manaPoints : Int?
}
protocol magicCastDelegate {
func castFire() -> magicDatas
func castIce() -> magicDatas
}
extension magicCastDelegate {
func castFire() -> magicDatas {
return magicDatas()
}
func castIce() -> magicDatas {
return magicDatas()
}
}
тоді ви можете реалізовувати протокол без визначення кожного функціоналу
Є два способи створити необов'язковий метод у швидкому протоколі.
1 - Перший варіант - позначити ваш протокол за допомогою атрибута @objc. Хоча це означає, що його можна прийняти лише класами, це означає, що ви позначаєте окремі методи як необов'язкові, як це:
@objc protocol MyProtocol {
@objc optional func optionalMethod()
}
2 - Швидший спосіб: цей варіант кращий. Напишіть реалізацію за замовчуванням додаткових методів, які нічого не роблять, як це.
protocol MyProtocol {
func optionalMethod()
func notOptionalMethod()
}
extension MyProtocol {
func optionalMethod() {
//this is a empty implementation to allow this method to be optional
}
}
Swift має функцію під назвою розширення, яка дозволяє нам забезпечити реалізацію за замовчуванням для тих методів, які ми хочемо бути необов'язковими.
Один варіант - зберігати їх як необов’язкові змінні функції:
struct MyAwesomeStruct {
var myWonderfulFunction : Optional<(Int) -> Int> = nil
}
let squareCalculator =
MyAwesomeStruct(myWonderfulFunction: { input in return input * input })
let thisShouldBeFour = squareCalculator.myWonderfulFunction!(2)
Визначте функцію в протоколі та створіть розширення для цього протоколу, а потім створіть порожню реалізацію для функції, яку ви хочете використовувати як необов'язковий.
Щоб Optional
Protocol
швидко визначитись, слід використати @objc
ключове слово перед Protocol
оголошенням та attribute
/ method
декларацією всередині цього протоколу. Нижче наведено зразок необов’язкової властивості протоколу.
@objc protocol Protocol {
@objc optional var name:String?
}
class MyClass: Protocol {
// No error
}
Поставте @optional
перед методами чи властивостями.
@optional
навіть не є правильним ключовим словом. Це так optional
, і ви повинні оголосити клас та протокол з @objc
атрибутом.