Apakah mungkin di Swift? Jika tidak, adakah solusi untuk melakukannya?
Apakah mungkin di Swift? Jika tidak, adakah solusi untuk melakukannya?
Jawaban:
protocol MyProtocol {
func doSomething()
}
extension MyProtocol {
func doSomething() {
/* return a default value or just leave empty */
}
}
struct MyStruct: MyProtocol {
/* no compile error */
}
Keuntungan
Tidak ada runtime Objective-C yang terlibat (well, setidaknya tidak secara eksplisit). Ini berarti Anda dapat menyesuaikan struct, enum dan non- NSObject
kelas untuk itu. Juga, ini berarti Anda dapat memanfaatkan sistem obat generik yang kuat.
Anda selalu dapat memastikan bahwa semua persyaratan dipenuhi ketika menemukan tipe yang sesuai dengan protokol tersebut. Itu selalu merupakan implementasi konkret atau standar. Ini adalah bagaimana "antarmuka" atau "kontrak" berperilaku dalam bahasa lain.
Kekurangan
Untuk non- Void
persyaratan, Anda harus memiliki nilai default yang masuk akal , yang tidak selalu memungkinkan. Namun, ketika Anda menghadapi masalah ini, itu berarti bahwa persyaratan seperti itu harus benar-benar tidak memiliki implementasi standar, atau bahwa Anda membuat kesalahan selama desain API.
Anda tidak dapat membedakan antara implementasi default dan tidak ada implementasi sama sekali , setidaknya tanpa mengatasi masalah itu dengan nilai pengembalian khusus. Perhatikan contoh berikut:
protocol SomeParserDelegate {
func validate(value: Any) -> Bool
}
Jika Anda memberikan implementasi default yang baru saja kembali true
- baik-baik saja pada pandangan pertama. Sekarang, pertimbangkan kode pseudo berikut:
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 */
}
}
}
Tidak ada cara untuk mengimplementasikan optimasi seperti itu - Anda tidak bisa tahu apakah delegasi Anda menerapkan metode atau tidak.
Meskipun ada sejumlah cara berbeda untuk mengatasi masalah ini (menggunakan penutupan opsional, objek delegasi yang berbeda untuk beberapa operasi yang berbeda untuk menyebutkan beberapa), contoh itu menyajikan masalah dengan jelas.
@objc optional
.@objc protocol MyProtocol {
@objc optional func doSomething()
}
class MyClass: NSObject, MyProtocol {
/* no compile error */
}
Keuntungan
Kekurangan
Ini sangat membatasi kemampuan protokol Anda dengan mengharuskan semua jenis yang sesuai agar kompatibel dengan Objective-C. Ini berarti, hanya kelas-kelas yang diwarisi dari yang NSObject
dapat memenuhi protokol tersebut. Tidak ada struct, tidak ada enum, tidak ada tipe yang terkait.
Anda harus selalu memeriksa apakah metode opsional diterapkan dengan memanggil atau memeriksa secara opsional apakah tipe yang sesuai mengimplementasikannya. Ini mungkin memperkenalkan banyak pelat baja jika Anda sering memanggil metode opsional.
respondsToSelector
?
optional func doSomething(param: Int?)
Di Swift 2 dan selanjutnya, mungkin untuk menambahkan implementasi protokol standar. Ini menciptakan cara baru metode opsional dalam protokol.
protocol MyProtocol {
func doSomethingNonOptionalMethod()
func doSomethingOptionalMethod()
}
extension MyProtocol {
func doSomethingOptionalMethod(){
// leaving this empty
}
}
Ini bukan cara yang sangat bagus dalam membuat metode protokol opsional, tetapi memberi Anda kemungkinan untuk menggunakan struct di dalam panggilan balik protokol.
Saya menulis ringkasan kecil di sini: https://www.avanderlee.com/swift-2-0/optional-protocol-methods/
Karena ada beberapa jawaban tentang cara menggunakan pengubah opsional dan atribut @objc untuk mendefinisikan protokol persyaratan opsional, saya akan memberikan sampel tentang cara menggunakan ekstensi protokol untuk menentukan protokol opsional.
Kode di bawah ini adalah 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*
Harap perhatikan metode ekstensi protokol tidak dapat dipanggil oleh kode Objective-C, dan lebih buruk lagi adalah tim Swift tidak akan memperbaikinya. https://bugs.swift.org/browse/SR-492
Jawaban lain di sini yang melibatkan menandai protokol sebagai "@objc" tidak berfungsi saat menggunakan tipe swift-specific.
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"
Untuk mendeklarasikan protokol opsional yang bekerja dengan baik dengan cepat, deklarasikan fungsi sebagai variabel, bukan fungsi.
protocol Health {
var isInfoHealthy: (Info) -> (Bool)? { get set }
}
Dan kemudian implementasikan protokolnya sebagai berikut
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)?
}
Anda kemudian dapat menggunakan "?" untuk memeriksa apakah fungsi telah diterapkan atau tidak
func returnEntity() -> Health {
return Human()
}
var anEntity: Health = returnEntity()
var isHealthy = anEntity.isInfoHealthy(Info(height: 75, weight: 150))?
//"isHealthy" is true
Ini adalah contoh nyata dengan pola pendelegasian.
Siapkan Protokol Anda:
@objc protocol MyProtocol:class
{
func requiredMethod()
optional func optionalMethod()
}
class MyClass: NSObject
{
weak var delegate:MyProtocol?
func callDelegate()
{
delegate?.requiredMethod()
delegate?.optionalMethod?()
}
}
Atur delegasi ke kelas dan mengimplementasikan Protokol. Pastikan metode opsional tidak perlu diterapkan.
class AnotherClass: NSObject, MyProtocol
{
init()
{
super.init()
let myInstance = MyClass()
myInstance.delegate = self
}
func requiredMethod()
{
}
}
Satu hal penting adalah bahwa metode opsional adalah opsional dan memerlukan "?" saat menelepon. Sebutkan tanda tanya kedua.
delegate?.optionalMethod?()
Di Swift 3.0
@objc protocol CounterDataSource {
@objc optional func increment(forCount count: Int) -> Int
@objc optional var fixedIncrement: Int { get }
}
Ini akan menghemat waktu Anda.
@objc
diperlukan pada semua anggota sekarang?
required
flag, tetapi dengan kesalahan: required
hanya dapat digunakan pada deklarasi 'init'.
optional
kata kunci sebelum setiap metode.@objc
, bukan hanya protokol.
Untuk mengilustrasikan mekanisme jawaban Antoine:
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"
Saya pikir sebelum bertanya bagaimana Anda dapat mengimplementasikan metode protokol opsional, Anda harus bertanya mengapa Anda harus menerapkannya.
Jika kita menganggap protokol cepat sebagai Antarmuka dalam pemrograman berorientasi objek klasik, metode opsional tidak masuk akal, dan mungkin solusi yang lebih baik adalah dengan membuat implementasi standar, atau memisahkan protokol menjadi satu set protokol (mungkin dengan beberapa hubungan warisan di antara mereka) untuk mewakili kemungkinan kombinasi metode dalam protokol.
Untuk bacaan lebih lanjut, lihat https://useyourloaf.com/blog/swift-optional-protocol-methods/ , yang memberikan gambaran yang sangat baik tentang masalah ini.
Agak keluar dari topik dari pertanyaan awal, tetapi itu membangun ide Antoine dan saya pikir itu mungkin membantu seseorang.
Anda juga dapat membuat properti yang dihitung opsional untuk struct dengan ekstensi protokol.
Anda dapat membuat properti pada protokol opsional
protocol SomeProtocol {
var required: String { get }
var optional: String? { get }
}
Menerapkan properti yang dihitung dummy dalam ekstensi protokol
extension SomeProtocol {
var optional: String? { return nil }
}
Dan sekarang Anda dapat menggunakan struct yang memiliki atau tidak memiliki properti opsional diimplementasikan
struct ConformsWithoutOptional {
let required: String
}
struct ConformsWithOptional {
let required: String
let optional: String?
}
Saya juga menulis cara melakukan properti opsional dalam protokol Swift di blog saya , yang saya akan terus perbarui jika terjadi perubahan melalui rilis Swift 2.
Cara membuat metode delegasi opsional dan wajib.
@objc protocol InterViewDelegate:class {
@objc optional func optfunc() // This is optional
func requiredfunc()// This is required
}
Berikut adalah contoh yang sangat sederhana untuk Kelas swift SAJA, dan bukan untuk struktur atau enumerasi. Perhatikan bahwa metode protokol bersifat opsional, memiliki dua level rantai opsional yang dimainkan. Juga kelas yang mengadopsi protokol membutuhkan atribut @objc dalam deklarasi.
@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) }
maka Anda akan memanggilnya tanpa tanda tanya: delegate?.indexDidChange(index!)
Ketika Anda menetapkan persyaratan opsional untuk metode dalam protokol, Tipe yang akan sesuai dengannya mungkin TIDAK menerapkan metode itu , jadi ?
digunakan untuk memeriksa implementasi dan Jika tidak ada program tidak akan crash. @Unheilig
weak var delegate : CollectionOfDataDelegate?
(pastikan referensi lemah?)
delegate?
penggunaan ke jawaban Anda? Informasi itu harus benar-benar menjadi milik orang lain di masa depan. Saya ingin mengungguli ini, tetapi informasi itu harus benar-benar ada dalam jawabannya.
jika Anda ingin melakukannya dengan swift murni, cara terbaik adalah dengan memberikan partikel implementasi standar jika Anda mengembalikan tipe Swift seperti misalnya struct dengan tipe Swift
contoh:
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()
}
}
maka Anda dapat mengimplementasikan protokol tanpa mendefinisikan setiap fungsi
Ada dua cara Anda dapat membuat metode opsional dalam protokol cepat.
1 - Opsi pertama adalah menandai protokol Anda menggunakan atribut @objc. Meskipun ini berarti hanya dapat diadopsi oleh kelas, itu berarti Anda menandai metode individual sebagai opsional seperti ini:
@objc protocol MyProtocol {
@objc optional func optionalMethod()
}
2 - Cara yang lebih cepat: Opsi ini lebih baik. Tulis implementasi default dari metode opsional yang tidak melakukan apa-apa, seperti ini.
protocol MyProtocol {
func optionalMethod()
func notOptionalMethod()
}
extension MyProtocol {
func optionalMethod() {
//this is a empty implementation to allow this method to be optional
}
}
Swift memiliki ekstensi fitur yang disebut yang memungkinkan kami untuk memberikan implementasi default untuk metode yang kami inginkan opsional.
Salah satu opsi adalah menyimpannya sebagai variabel fungsi opsional:
struct MyAwesomeStruct {
var myWonderfulFunction : Optional<(Int) -> Int> = nil
}
let squareCalculator =
MyAwesomeStruct(myWonderfulFunction: { input in return input * input })
let thisShouldBeFour = squareCalculator.myWonderfulFunction!(2)
Tetapkan fungsi dalam protokol dan buat ekstensi untuk protokol itu, lalu buat implementasi kosong untuk fungsi yang ingin Anda gunakan sebagai opsional.
Untuk mendefinisikan Optional
Protocol
dengan cepat Anda harus menggunakan @objc
kata kunci sebelum Protocol
deklarasi dan attribute
/ method
deklarasi di dalam protokol itu. Di bawah ini adalah contoh Properti Opsional dari protokol.
@objc protocol Protocol {
@objc optional var name:String?
}
class MyClass: Protocol {
// No error
}
Letakkan @optional
di depan metode atau properti.
@optional
bahkan bukan kata kunci yang benar. Itu optional
, dan Anda harus mendeklarasikan kelas dan protokol dengan @objc
atributnya.