Возможно ли это в Swift? Если нет, то есть ли это обходное решение?
Если вы хотите использовать необязательные методы, вы должны пометить свой протокол атрибутом @objc
:
@objc protocol MyProtocol {
@objc optional func doSomething()
}
class MyClass : MyProtocol {
// no error
}
В противном случае протоколы Swift ведут себя как интерфейсы на других языках OO, где должны быть реализованы все методы, определенные в интерфейсах.
В Swift 2.0 можно добавлять стандартные реализации протокола. Это создает новый способ использования дополнительных методов в протоколах.
protocol MyProtocol {
func doSomethingNonOptionalMethod()
func doSomethingOptionalMethod()
}
extension MyProtocol {
func doSomethingOptionalMethod(){
// leaving this empty
}
}
Это не очень хороший способ создания дополнительных методов протокола, но дает вам возможность использовать структуры в обратных вызовах протокола.
Я написал небольшое резюме здесь: http://www.avanderlee.com/swift-2-0/optional-protocol-methods/
Другие ответы здесь, связанные с маркировкой протокола как "@objc", не работают при использовании типов, специфичных для swift.
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"
Чтобы объявить факультативные протоколы, которые хорошо работают с быстрым, объявите функции как переменные вместо func.
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
В Swift 3.0
@objc protocol CounterDataSource {
@objc optional func increment(forCount count: Int) -> Int
@objc optional var fixedIncrement: Int { get }
}
Это сэкономит ваше время.
@objc
нужен всем участникам сейчас?
optional
перед каждым методом.Вот конкретный пример с шаблоном делегирования.
Настройка протокола:
@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?()
Так как есть некоторые ответы о том, как использовать необязательный модификатор и @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
Слегка от темы от оригинального вопроса, но он строит идею Антуана, и я подумал, что это может помочь кому-то.
Вы также можете сделать вычисляемые свойства необязательными для структур с расширением протокола.
Вы можете сделать свойство на протоколе опционным
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?
}
Ive также написала, как сделать дополнительные свойства в протоколах Swift в моем блоге, которые Ill продолжают обновлять, если все изменится через Swift 2 релизов.
Я думаю, что перед тем, как спросить , как вы можете реализовать необязательный метод протокола, вы должны спросить почему его следует реализовать.
Если мы думаем о быстрых протоколах как интерфейсе в классическом объектно-ориентированном программировании, необязательные методы не имеют большого смысла, и, возможно, лучшим решением будет создание реализации по умолчанию или отдельный протокол в набор протоколов (возможно, с некоторые отношения наследования между ними), чтобы представить возможную комбинацию методов в протоколе.
Для дальнейшего чтения см. https://useyourloaf.com/blog/swift-optional-protocol-methods/, что дает отличный обзор по этому вопросу.
Чтобы проиллюстрировать механику Антуана, ответьте:
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"
если вы хотите сделать это в чистом быстром, лучший способ - реализовать реализацию по умолчанию, если вы вернете тип Swift, например, struct с типами 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()
}
}
тогда вы можете реализовать протокол, не определяя каждый func
Здесь очень простой пример для быстрых классов ТОЛЬКО, а не для структур или перечислений. Обратите внимание, что метод протокола, являющийся факультативным, имеет два уровня опциональной цепочки при игре. Также классу, принимающему протокол, требуется атрибут @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!)
его без знака вопроса: delegate?.indexDidChange(index!)
Когда вы устанавливаете необязательное требование для метода в протоколе Тип, который будет соответствовать ему, может НЕ реализовывать этот метод, так что ?
используется для проверки реализации, и если ее нет, программа не будет аварийно завершена. @Unheilig
Поместите @optional
перед методами или свойствами.
@optional
даже не правильное ключевое слово. Это optional
, и вы должны объявить класс и протокол с атрибутом @objc
.
respondsToSelector
?